Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: c46d1d4be9
Fetching contributors…

Cannot retrieve contributors at this time

file 172 lines (143 sloc) 3.347 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
//
// Future.m
// ActorKit
//
// Created by Steve Dekorte on 20110830.
// Copyright 2011 Steve Dekorte. BSD licensed.
//

#import "ActorProxy.h"
#import "FutureProxy.h"
#import "NSThread+Actor.h"

@implementation FutureProxy

@synthesize futureActor;
@synthesize futureInvocation;
@synthesize futureValue;
@synthesize nextFuture;
@synthesize futureWaitingThreads;
@synthesize futureException;
@synthesize futureLock;

- (id)init
{
    //self = [super init]; // NSProxy doesn't implement init
    
if (self)
{
done = NO;
[self setFutureLock:[[[Mutex alloc] init] autorelease]];
[self setFutureWaitingThreads:[NSMutableSet set]];
    }
    
    return self;
}

- (void)dealloc
{
[self setFutureActor:nil];
[self setFutureInvocation:nil];
[self setFutureValue:nil];
[self setNextFuture:nil];
[self setFutureWaitingThreads:nil];
[self setFutureException:nil];
[self setFutureLock:nil];
[super dealloc];
}

- (void)futureAppend:(FutureProxy *)aFuture
{
if(nextFuture)
{
[nextFuture futureAppend:aFuture];
}
else
{
[self setNextFuture:aFuture];
}
}

- (void)futureShowSend
{
NSLog(@"FutureProxy send [%@ %@]\n",
[[futureActor actorTarget] className],
NSStringFromSelector([futureInvocation selector]));
}

- (void)futureSend
{
@try
{
//[self futureShowSend];
[futureInvocation invokeWithTarget:[futureActor actorTarget]];

id r;
[futureInvocation getReturnValue:(void *)&r];
[self setFutureResult:r];
}
@catch (NSException *e)
{
[self setFutureException:e];
[self setFutureResult:nil];
}

for(NSThread *waitingThread in futureWaitingThreads)
{
[waitingThread setWaitingOnFuture:nil];
}

[futureWaitingThreads removeAllObjects];
[futureLock resumeThread];
}

- (void)setFutureResult:(id)anObject
{
if(done)
{
return;
}

done = YES;

[self setFutureValue:anObject];
}

- (BOOL)isWaitingOnCurrentThread
{
// the recursion should avoid loop since the deadlock detection prevents loops

for(NSThread *waitingThread in futureWaitingThreads)
{
if([[waitingThread waitingOnFuture] isWaitingOnCurrentThread])
{
return YES;
}
}

return NO;
}

- (void)futurePassExceptionIfNeeded
{
if(futureException)
{
// guessing we have to wrap the exception so the stack info of original will be available
NSMutableDictionary *info = [NSMutableDictionary dictionary];
[info setObject:futureException forKey:@"exception"];
[info setObject:self forKey:@"future"];

NSException *e = [[NSException alloc] initWithName:@"Future"
reason:@"exception during send"
userInfo:info];
[e raise];
}
}

- (void)futureRaiseExceptionIfDeadlock
{
if([self isWaitingOnCurrentThread])
{
[NSException raise:@"Future" format:@"waiting for result on this coroutine would cause a deadlock"];
}
}

- futureResult
{
if(done)
{
[self futurePassExceptionIfNeeded];
return futureValue;
}

[futureWaitingThreads addObject:[NSThread currentThread]];
[self futureRaiseExceptionIfDeadlock];
[futureLock pauseThread];
[self futureRaiseExceptionIfDeadlock];

return futureValue;
}


- (void)forwardInvocation:(NSInvocation *)anInvocation
{
[anInvocation invokeWithTarget:[self futureResult]];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
return [[self futureResult] methodSignatureForSelector:aSelector];
}

@end
Something went wrong with that request. Please try again.