Removing two commented out lines.
[hom.git] / Source / DPMultiThreading.h
blob18cf19c850d345fdd7a4d2eb47fbae428f121996
1 //
2 // DPMultiThreading.h
3 // HigherOrderMessaging
4 //
5 // Created by Ofri Wolfus on 25/05/07.
6 // Copyright 2007 Ofri Wolfus. All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without modification,
9 // are permitted provided that the following conditions are met:
10 //
11 // 1. Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // 2. Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 // 3. Neither the name of Ofri Wolfus nor the names of his contributors
17 // may be used to endorse or promote products derived from this software
18 // without specific prior written permission.
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #import <Foundation/Foundation.h>
32 #import <CoreFoundation/CoreFoundation.h>
33 #import <AvailabilityMacros.h>
34 #include <pthread.h>
35 #include <libkern/OSAtomic.h> // For OSSpinLock
37 #if defined(__HOM_FRAMEWORK__)
38 #import <HigherOrderMessaging/DPObjCRuntime.h>
39 #elif defined(__UITESTINGKIT__)
40 #import <UITestingKit/DPObjCRuntime.h>
41 #import <UITestingKit/DPRunLoopSource.h>
42 #import <UITestingKit/DPUtilities.h> // For DPSetUpAutoreleasePool()
43 #else
44 #import "DPObjCRuntime.h" // For DP_EXTERN
45 #endif
47 #if defined(__HOM_FRAMEWORK__)
48 #import <HigherOrderMessaging/DPMessage.h>
49 #else
50 #import "DPMessage.h"
51 #endif
54 #ifndef __UITESTINGKIT__
55 /*!
56 * @abstract A base class for runloop sources.
57 * @discussion Subclass this class in order to create our own runloop source.
59 @interface DPRunLoopSource : NSObject {
60 @private
61 int32_t _refCount;
62 CFRunLoopSourceRef _src;
65 /*!
66 * @abstract Initializes a new runloop source with a given priority.
68 * @param priority A priority index indicating the order in which run loop sources
69 * are processed. When multiple run loop sources are firing in a single pass through
70 * the run loop, the sources are processed in increasing order of this parameter.
71 * If the run loop is set to process only one source per loop, only the highest
72 * priority source, the one with the lowest order value, is processed.
73 * Pass 0 unless there is a reason to do otherwise.
75 - (id)initWithPriority:(unsigned)priority;
77 /*!
78 * @abstract Called by the runloop in order for the source to do its work.
79 * @discussion Override this method in your subclass to perform the actual work.
80 * The default implementation of this method does nothing.
82 - (void)fire;
84 /*!
85 * @abstract Signals the receiver, marking it as ready to fire.
86 * @discussion This method marks the receiver as ready to fire.
87 * The receiver's -fire will then be invoked by one of the runloops the receiver
88 * is added to, whichever happens to be available first.
89 * After firing, the receiver must be signaled again in order to fire again.
91 - (void)signal;
94 /*!
95 * @abstract Invalidates the receiver, stopping it from ever firing again.
96 * @discussion Once invalidated, the receiver will never fire again. This method
97 * automatically removes the receiver from all run loop modes in which it was registered.
99 - (void)invalidate;
102 * @abstract Returns whether the receiver is valid and able to fire.
104 - (BOOL)isValid;
107 * @abstract Returns the ordering parameter for the receiver, which the run loop uses to
108 * determine the order in which sources are processed when multiple sources are firing.
110 - (unsigned)priority;
114 * @abstract A scheduling callback for the receiver.
115 * @discussion This method is invoked when the receiver is added to a run loop mode.
116 * The default implementation of this method does nothing.
118 - (void)scheduleWithRunLoop:(CFRunLoopRef)rl forMode:(NSString *)mode;
121 * @abstract A cancel callback for the receiver.
122 * @discussion This method is invoked when the receiver is removed from a run loop mode.
123 * The default implementation of this method does nothing.
125 - (void)cancelMode:(NSString *)mode forRunLoop:(CFRunLoopRef)rl;
129 * @abstract Returns the underlying CFRunLoopSourceRef powering the receiver.
131 - (CFRunLoopSourceRef)getCFRunLoopSource;
133 @end
136 * @abstract Support for DPRunLoopSource.
138 @interface NSRunLoop (DPRunLoopSource)
141 * @abstract Registers <code>src</code> with the receiver for <code>mode</code>.
143 - (void)addSource:(DPRunLoopSource *)src forMode:(NSString *)mode;
146 * @abstract Unregisters <code>src</code> with the receiver for <code>mode</code>.
148 - (void)removeSource:(DPRunLoopSource *)src forMode:(NSString *)mode;
151 * @abstract Returns whether the receiver contains a given source.
153 - (BOOL)containsSource:(DPRunLoopSource *)src inMode:(NSString *)mode;
155 @end
156 #endif //__UITESTINGKIT__
159 @interface DPQueue : NSObject {
160 int32_t _refCount;
161 NSMutableArray *queue;
162 OSSpinLock queueLock;
165 - (void)enqueu:(id)obj;
166 - (id)dequeue;
167 - (unsigned)count;
169 @end
173 * @abstract A queue of invocations that can be shared across
174 * runloops to distribute work.
176 * @discussion An invocation queue is a runloop source, and therefor
177 * can be shared across runloops/threads. Each runloop takes the topmost
178 * invocation and invokes it, until the queue is empty.
180 * DPInvocation queue implements thread safe reference-counting so there's
181 * no need to lock when retaining/releasing it.
183 @interface DPInvocationQueue : DPRunLoopSource {
184 DPQueue *queue;
185 int32_t _theApocalypseArrived;
189 * @abstract Returns the default queue in the current thread.
190 * @discussion If there's no queue in the current thread one
191 * is created.
193 + (id)defaultQueue;
196 * @abstract Appends an invocation to the queue for later execution.
198 * @discussion If the invocation returns an object (either instance or class)
199 * a future is returned. A future is a proxy to the result of the invocation
200 * that does not yet exist.
202 * Upon the first message to the future it'll block the caller thread until
203 * the result of the invocation is available. When the result is available,
204 * the future will act as a simple proxy and just forward any message to its
205 * target. No thread safety is implemented and the target of the proxy (the
206 * result of the invocation) is assumed to be owned by the caller thread.
208 * For non-object return values nil is returned. If you have no use for the
209 * proxy just ignore it, but if you do, you must retain it to keep it around.
211 * If you wish to get the real object behind the future, send it a
212 * <code>self</code> message and use the result.
214 * Warning: Futures are not thread safe. They assume to be owned by excactly
215 * one thread and to never be messaged from another thread. That being said,
216 * after the first message to the future returns (meaning the future's target
217 * is now available), the future can safely be shared across threads, assuming
218 * its target is thread safe of course. Futures implement thread-safe reference
219 * counting to allow sharing after a target is available.
221 - (id)appendInvocation:(NSInvocation *)invocation;
224 * @abstract Removes an invocation from the queue.
226 * @discussion This method removes the topmost invocation that matches
227 * <code>invocation</code> and returns. If the invocation appears more
228 * than once in the queue, you should invoke this method as many times
229 * as the invocation appears.
231 //- (void)removeInvocation:(NSInvocation *)invocation;
234 * @abstract Invokes all invocations of the receiver empties it.
236 * @discussion This method returns only after all invocations have
237 * been invoked and the receiver is empty.
238 * The queue is locked until all invocations are invoked, preventing
239 * additions of invocations from other threads.
241 - (void)pushAllInvocations;
243 @end
246 * @abstract Returns whether a given object is a future or not.
247 * @discussion Once a future gets its value, it is no longer
248 * considered a future and this function returns <code>NO</code>.
250 DP_EXTERN BOOL DPObjectIsFuture(id obj);
254 * @abstract A condition variable that's shared across threads.
255 * @discussion A condition variable is a variable that's shared
256 * across threads and it's value is only available when a certain
257 * condition is met.
259 * This is a wrapper around pthread's condition variable.
261 @interface DPConditionVariable : NSObject {
262 @private
263 int32_t _refCount;
264 pthread_mutex_t _lock;
265 pthread_cond_t _condition;
266 volatile void *_value;
267 volatile int _conditionValue;
271 * @abstract Waits for the default condition (1) and returns the value.
273 - (void *)wait;
276 * @abstract Waits until a certain condition is met, and returns the value.
278 * @param cond The condition to wait for. -1 is a reserved condition. Never use it yourself.
279 * @result The value that was signaled/broadcasted.
281 - (void *)waitForCondition:(int)cond;
284 * @abstract Signals the default condition (1) with a given value.
285 * @discussion If there are more than one thread waiting for this value
286 * only one is unblocked.
288 - (void)signalValue:(void *)val;
291 * @abstract Signals a custom condition with a given value.
292 * @discussion If there are more than one thread waiting for this value
293 * only one is unblocked.
295 * @param cond The condition to signal. -1 is a reserved condition. Never use it yourself.
296 * @param val The value to send with the signal.
298 - (void)signalCondition:(int)cond withValue:(void *)val;
301 * @abstract Broadcasts the default condition (1) with a given value.
302 * @discussion A broadcast unblocks all threads waiting for the condition.
304 - (void)broadcastValue:(void *)cond;
307 * @abstract Broadcasts a custom condition with a given value.
308 * @discussion A broadcast unblocks all threads waiting for the condition.
310 * @param cond The condition to signal. -1 is a reserved condition. Never use it yourself.
311 * @param val The value to send with the signal.
313 - (void)broadcastCondition:(int)cond withValue:(void *)val;
316 * @abstract Resets the receiver to its initial condition and value.
317 * @discussion If you'd like to reuse a condition variable, send it a
318 * <code>clear</code> message before waiting for a new condition.
320 - (void)clear;
322 @end
324 @class DPCoroutineStack, DPCoroutineScheduler, DPCoroutine;
327 * @abstract A class representing a pool of threads that share work.
329 * @discussion A thread pool may have any number of threads and any
330 * number of messages to send. The threads in the pool send the messages
331 * whenever they can, and split the workload among themselves.
333 @interface DPThreadPool : NSObject {
334 @private
335 int32_t _refCount;
336 DPInvocationQueue *queue;
337 DPCoroutineStack *coroStack;
338 NSMutableArray *threads;
342 * @abstract Returns the number of processors currently available for executing threads.
343 * @discussion This number can change when power management modes are changed.
344 * @result The number of active CPUs or -1 on error.
346 + (int)activeCPUs;
349 * @abstract Creates and returns an autoreleased pool with a given
350 * number of threads.
352 + (id)poolWithNumberOfThreads:(unsigned)threadsCount;
355 * @abstract Spawns a new thread and adds it to the pool.
357 - (void)spawnThread;
360 * @abstract Terminates a thread from the pool.
362 * @discussion If there are sleeping threads one of them is terminated.
363 * Otherwise, the first thread to become idle is terminated. Note that
364 * any prioir messages added to the pool will be sent before the thread
365 * is terminated.
367 - (void)terminateThread;
370 * @abstract Returns the total amount of threads in the pool.
372 - (unsigned)numberOfThreads;
375 * @abstract Returns the number of active threads in the pool.
376 * @discussion An active thread is a thread that processes a messages.
378 - (unsigned)activeThreads;
381 * @abstract Adds a message to the pool's work queue.
382 * @discussion The message is invoked whenever one of the threads in
383 * the pool finds the time to do it.
385 - (id)sendMessage:(DPMessage *)msg to:(id)target;
387 - (void)sendCoroutineMessage:(DPMessage *)message to:(id)target;
389 @end
393 * @abstract Adds an API for easy usage of worker threads.
395 @interface NSThread (DPWorkerThread)
398 * @abstract Detaches and returns a new worker thread.
400 * @discussion A worker thread is a thread that has a default
401 * invocation queue set up together with an active runloop.
403 * This method does all the dirty work for you (including setting up an
404 * autorelease pool), but you can set up a worker thread yourself buy calling
405 * <code>[[NSRunLoop defaultRunLoop] addSource:[DPInvocationQueue defaultQueue]
406 forMode:NSDefaultRunLoopMode];</code>
407 * and running the runloop ins the default mode.
409 + (id)detachNewWorkerThread;
411 #if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_10_5 > MAC_OS_X_VERSION_MAX_ALLOWED
413 * @abstract Returns the main thread.
415 + (NSThread *)mainThread;
416 #endif
419 * @abstract Returns the default invocaiton queue of the receiver, or <code>nil</code>
420 * if none exists.
422 - (DPInvocationQueue *)defaultInvocationQueue;
425 * @abstract Sets the default invocation queue of the receiver.
427 - (void)setDefaultInvocationQueue:(DPInvocationQueue *)queue;
430 * @abstract Terminates a worker thread that was created using
431 * +[NSThread detachNewWorkerThread].
433 * @discussion If the thread wasn't created with +[NSThread detachNewWorkerThread],
434 * this method does nothing.
436 - (void)terminate;
439 * @abstract Sends a given message to an object inside the context of the
440 * receiving thread.
442 * @discussion The object must respond to the passed message or an exception
443 * will be thrown.
445 * @result A future if the message returns an object, <code>nil</code> otherwise.
446 * See the documentation for -[DPInvocationQueue appendInvocation:] for more
447 * information about futures.
449 - (id)sendMessage:(DPMessage *)msg to:(id)obj;
451 @end
453 @interface DPThreadID : NSObject {
454 pthread_t threadId;
456 + (id)currentIdentifier;
457 - (pthread_t)getThreadID;
458 @end
460 @interface NSObject (DPAsyncMessaging)
463 * @abstract Makes the receiver receive <code>msg</code> after the given delay.
465 - (void)receiveMessage:(DPMessage *)msg afterDelay:(NSTimeInterval)sec;
468 * @abstract Spwns a new thread in which the passed message will be received.
470 * @discussion If the message doesn't return an object the behavior is undefined,
471 * and will most likely cause a crash.
473 * @result A future to the message's result. Please refer to the
474 * -[DPInvocationQueue appendInvocation:] documentation for more information
475 * about futures.
477 - (id)future:(DPMessage *)msg;
479 @end
481 @interface NSInvocation (DPMessageSupport)
483 + (id)invocationWithMessage:(DPMessage *)msg receiver:(id)target;
485 @end
487 #ifndef __UITESTINGKIT__
489 * @abstract Sets up an autorelease pool that's automatically released
490 * and recreated at each entry of the current runloop.
491 * @discussion The autorelease pool is added to the current runloop in
492 * <code>runLoopMode</code>. If <code>runLoopMode</code> is <code>nil</code>,
493 * the pool is added to the current mode.
494 * Each call to this function creates and sets up a new autorelease pool.
496 DP_EXTERN void DPSetUpAutoreleasePool(NSString *runLoopMode);
497 #endif