DPQueue is now a two-lock concurrent queue.
[hom.git] / Source / DPCoroutine.h
blob5cde1722b884ed3d4a7e6373932665824854fa84
1 //
2 // DPCoroutine.h
3 // HigherOrderMessaging
4 //
5 // Created by Ofri Wolfus on 01/08/07.
6 // Copyright 2007 Ofri Wolfus. All rights reserved.
7 //
9 #import <Foundation/Foundation.h>
10 #import "DPMessage.h"
11 #import "DPMultiThreading.h"
12 #import "Coro.h"
15 @interface DPCoroutine : NSObject {
16 int32_t _refCount;
17 Coro *_coro;
18 BOOL isActive;
19 DPMessage *message;
20 id target;
21 DPCoroutine *parent;
24 /*!
25 * @abstract Returns the currently active coroutine in the current thread
26 * or nil if no coroutine is active.
28 + (id)currentCoroutine;
31 /*!
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;
45 /*!
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.
53 - (void)yield;
55 @end
58 @interface DPCoroutineStack : DPRunLoopSource {
59 OSSpinLock mainCorosLock;
60 NSMutableDictionary *mainCoros;
61 DPQueue *stack;
62 DPQueue *unusedCoroutines;
63 int32_t activeRoutines;
66 /*!
67 * @abstract Returns the current active stack in the current thread.
69 + (id)currentStack;
71 /*!
72 * @abstract Sets the current stack.
74 + (void)setCurrentStack:(id)stack;
76 /*!
77 * @abstract Returns the default coroutine stack of the main thread.
79 + (id)mainStack;
82 /*!
83 * @abstract Adds a coroutine to the receiver's queue, which will be
84 * executed later.
86 - (void)addCoro:(DPCoroutine *)coro;
88 /*!
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.
94 - (BOOL)nextCoro;
96 /*!
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.
101 - (BOOL)hasWork;
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.
109 - (void)empty;
111 @end
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:
123 <code>
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];
132 [stack release];
133 [pool release];
135 </code>
137 - (void)coroutine:(DPMessage *)msg;
139 @end
141 #ifndef DPCoroutineYield
144 * @abstract Stops execution of the current coroutine and passes control to another coroutine.
146 #define DPCoroutineYield() [[DPCoroutine currentCoroutine] yield]
147 #endif