3 // HigherOrderMessaging
5 // Created by Ofri Wolfus on 01/08/07.
6 // Copyright 2007 Ofri Wolfus. All rights reserved.
9 #import <Foundation/Foundation.h>
11 #import "DPMultiThreading.h"
15 @interface DPCoroutine
: NSObject
{
25 * @abstract Returns the currently active coroutine in the current thread
26 * or nil if no coroutine is active.
28 + (id
)currentCoroutine
;
32 * @abstract Creates and returns a new coroutine.
34 * @discussion The returned instance must be added to a <code>DPCoroutineStack</code>
35 * in order to start execution.
37 * @param msg The message which its method will be executed as the coroutine's body.
38 * @param target The object which will receiver the message.
40 * @result An initialized DPCoroutine instance or <code>nil</code> if either <code>msg</code>
41 * or </code>target</code> is <code>nil</code>.
43 - (id
)initWithMessage
:(DPMessage
*)msg target
:(id
)target
;
46 * @abstract Stops the execution of the receiver and passes control to the coroutine's stack.
48 * @discussion This method causes the receiver to save its current execution state and return
49 * control to its stack. The receiver's coroutine stack then schedules the receiver to continue
50 * execution later, and executes other coroutines until then.
51 * Don't use this method unless you have to. Use the <code>DPCoroutineYield()</code> macro instead.
58 @interface DPCoroutineStack
: DPRunLoopSource
{
59 OSSpinLock mainCorosLock
;
60 NSMutableDictionary
*mainCoros
;
62 DPQueue
*unusedCoroutines
;
63 int32_t activeRoutines
;
67 * @abstract Returns the current active stack in the current thread.
72 * @abstract Sets the current stack.
74 + (void)setCurrentStack
:(id
)stack
;
77 * @abstract Returns the default coroutine stack of the main thread.
83 * @abstract Adds a coroutine to the receiver's queue, which will be
86 - (void)addCoro
:(DPCoroutine
*)coro
;
89 * @abstract Executes the next coroutine in the queue.
90 * @discussion You rarely, if ever, need to invoke this method directly.
92 * @result <code>YES</code> if the receiver processed a coroutine, <code>NO</code> otherwise.
97 * @abstract Returns whether the receiver has coroutines to process or not.
98 * @discussion Due to thread safety issues, this method may not always be accurate
99 * and might return <code>YES</code> even if the receiver has no work.
104 * @abstract Makes the receiver process all its coroutines until they complete.
106 * @discussion This method starts a tight loop that exists only after all coroutines returned.
107 * Don't invoke this method unless you're absolutely sure you need it.
114 @interface
NSObject (DPCoroutine
)
117 * @abstract Creates a new coroutine with a given message and adds it to the current coroutine stack.
119 * @discussion This method does nothing if there's no active coroutine stack in the current thread.
120 * A stack is automatically created for you in the main thread and added to the default runloop mode.
121 * For threads you create yourself you must set up a stack by hand like this:
124 - (void)startThreadMethod {
125 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
126 DPCoroutineStack *stack = [[DPCoroutineStack alloc] init];
128 [DPCoroutineStack setCurrentStack:stack];
129 [[NSRunLoop currentRunLoop] addSource:stack forMode:NSDefaultRunLoopMode];
130 [[NSRunLoop currentRunLoop] run];
137 - (void)coroutine
:(DPMessage
*)msg
;
141 #ifndef DPCoroutineYield
144 * @abstract Stops execution of the current coroutine and passes control to another coroutine.
146 #define DPCoroutineYield() [[DPCoroutine currentCoroutine] yield]