/Volumes/Plantain/MyDocuments/Projects/MacTrek/MacTrek/Luky/Concurrency/LLThreadWorker.m

00001 #import "LLThreadWorker.h"
00002 
00003 
00004 @interface LLThreadWorker (PrivateAPI)
00005 
00016 - (LLThreadWorker *)  initWithTarget:(id)target 
00017                     selector:(SEL)selector 
00018                     argument:(id)argument
00019                     didEndSelector:(SEL)didEndSelector;
00020 
00021     
00027 - (void) startThread:(NSArray *)callingPortArray;
00028 
00029 
00035 -(void)runPrimaryTask:(id)notUsed;
00036 
00037     
00038 
00039 @end // PrivateAPI
00040 
00041 
00042 
00043 
00044 @implementation LLThreadWorker
00045 
00046 
00051 + (LLThreadWorker *) workOn:(id)target 
00052                    withSelector:(SEL)selector 
00053                    withObject:(id)argument
00054                    didEndSelector:(SEL)didEndSelector;  // Optional
00055 {
00056     LLThreadWorker *tw;
00057     NSPort *port1;
00058     NSPort *port2;
00059     NSConnection *conn;
00060     NSArray *callingPortArray;
00061     
00062     // Make sure the target has that selector
00063     if( ![target respondsToSelector:selector] )
00064     {   
00065         NSLog( @"\nLLThreadWorker reports: Target %@ does not respond to selector %@.", target, selector );
00066         return nil;
00067     }   // end if: error
00068     
00069     // Create an instance of LLThreadWorker
00070     tw = [[[LLThreadWorker alloc] 
00071             initWithTarget:target 
00072             selector:selector 
00073             argument:argument
00074             didEndSelector:didEndSelector] autorelease];
00075 
00076     if( !tw )
00077         return nil;
00078     
00079     // Set up connection to "target"
00080     port1 = [NSPort port];
00081     port2 = [NSPort port];
00082     conn = [NSConnection connectionWithReceivePort:port1 sendPort:port2];
00083     [conn setRootObject:target];
00084     callingPortArray = [NSArray arrayWithObjects:port2, port1, conn, nil];
00085     
00086     // Launch thread in an internal selector that will handle the strange NSThread requirements.
00087     [NSThread detachNewThreadSelector:@selector(startThread:) toTarget:tw withObject:callingPortArray];
00088 
00089     return tw;
00090 }   // end workOn
00091 
00092 
00093 
00094 
00098 - (LLThreadWorker *) initWithTarget:(id)target 
00099                    selector:(SEL)selector 
00100                    argument:(id)argument
00101                    didEndSelector:(SEL)didEndSelector
00102 {    
00103     if( ![super init] )
00104         return nil;
00105 
00106     // Set instance variables
00107     _target             = target;
00108     _selector           = selector;
00109     _argument           = argument;
00110     _didEndSelector     = didEndSelector;
00111     _cancelled          = [[NSConditionLock alloc] initWithCondition:NO];
00112 
00113     // Retain instance variables
00114     [_target            retain];
00115     [_argument          retain];
00116 
00117     return self;
00118 }   // end initWithTarget
00119 
00120 
00124 - (void)dealloc
00125 {
00126     // Release instance variables
00127     [_target            release];
00128     [_argument          release];
00129     [_cancelled         release];
00130 
00131     // Releasing these makes the program crash...
00132     //[_callingConnection release];
00133     //[_conn2 release];
00134     //[_port1 release];
00135     //[_port2 release];
00136     
00137     // Clear instance variables - Probably unnecessary.
00138     _target            = nil;
00139     _argument          = nil;
00140     _callingConnection = nil;
00141     _conn2             = nil;
00142     _port1             = nil;
00143     _port2             = nil;
00144     _cancelled         = nil;
00145 
00146     [super dealloc];
00147 }   // end dealloc
00148 
00149 
00150 
00151 
00155 -(void)markAsCancelled
00156 {
00157     // Get lock if we're currently NOT cancelled
00158     if( [_cancelled tryLockWhenCondition:NO] )
00159         [_cancelled unlockWithCondition:YES];
00160 }       // end markAsCancelled
00161 
00162 
00163 
00164 
00165 
00169 -(BOOL)cancelled
00170 {
00171     return [_cancelled condition];
00172 }       // end cancelled
00173 
00174 
00175 
00176 
00177 
00183 - (void)startThread:(NSArray *)callingPortArray
00184 {
00185     NSAutoreleasePool *pool;
00186     
00187     // Thread startup maintenance
00188     pool = [[NSAutoreleasePool alloc] init];
00189     
00190     // Set up connections on new thread
00191     _port1 = [callingPortArray objectAtIndex:0];
00192     _port2 = [callingPortArray objectAtIndex:1];
00193     _conn2 = [callingPortArray objectAtIndex:2];
00194     _callingConnection = [NSConnection connectionWithReceivePort:_port1 sendPort:_port2];
00195 
00196     // Prime the run loop
00197     
00198     [[NSRunLoop currentRunLoop] 
00199         addTimer:[NSTimer scheduledTimerWithTimeInterval:0 
00200             target:self 
00201             selector:@selector(runPrimaryTask:) 
00202             userInfo:nil 
00203             repeats:NO] 
00204         forMode:NSDefaultRunLoopMode];
00205     //[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
00206     //                         beforeDate:[NSDate distantFuture]];
00207     
00208     //[self runPrimaryTask:nil];
00209     
00210     // Run one iteration of the run loop
00211     _endRunLoop = NO;
00212     BOOL isRunning;
00213     do {
00214         isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
00215                                              beforeDate:[NSDate distantFuture]];
00216         NSLog(@"isRunning: %d, _endRunLoop: %d", isRunning, _endRunLoop );
00217     } while ( isRunning && !_endRunLoop);   
00218 
00219     
00220     [pool release];
00221 }   // end startThread
00222 
00223 
00228 -(void)runPrimaryTask:(id)notUsed
00229 {
00230     id userInfo;
00231         
00232     // Call user's selector with this LLThreadWorker as
00233     // an argument, if a second argument is taken.
00234     if( [[_target methodSignatureForSelector:_selector] numberOfArguments] == 4 ) // 2 hidden + 2 exposed
00235         userInfo = [_target performSelector:_selector withObject:_argument
00236                                  withObject:self];
00237     else
00238         userInfo = [_target performSelector:_selector withObject:_argument];
00239     
00240     // Call finalizing method in calling thread
00241     if( _didEndSelector )
00242         [(id)[_callingConnection rootProxy] performSelector:_didEndSelector withObject:userInfo];
00243 
00244     // Clean up thread maintenance]
00245     [_callingConnection invalidate];
00246     [_conn2 invalidate];
00247     [_port1 invalidate];
00248     [_port2 invalidate];
00249     
00250     _endRunLoop = YES;
00251 }   // end runPrimaryTask
00252 
00253 
00258 + (NSString *)description
00259 {   return @"LLThreadWorker v0.7. Public Domain. Original author: Robert Harder, rob@iharder.net. Keep up-to-date at http://iHarder.net";
00260 }   // end description
00261 
00262 
00263 
00264 @end
00265 

Generated on Fri Jul 28 19:15:22 2006 for MacTrek by  doxygen 1.4.7