mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 16:50:58 +00:00
More thread changes for MacOS-X compatibility
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@26340 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
7c710cfbcb
commit
b6638d05aa
4 changed files with 140 additions and 51 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
2008-03-17 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Headers/Foundation/NSThread.h:
|
||||||
|
* Source/NSThread.m: Add ([+isMainThread]) and ([-isFinished]).
|
||||||
|
Also check that we are not trying to perform a selector on an invalid
|
||||||
|
thread finished.
|
||||||
|
|
||||||
2008-03-17 Richard Frith-Macdonald <rfm@gnu.org>
|
2008-03-17 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/NSRunLoop.m:
|
* Source/NSRunLoop.m:
|
||||||
|
|
|
@ -38,6 +38,17 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class encapsulates OpenStep threading. See [NSLock] and its
|
||||||
|
* subclasses for handling synchronisation between threads.<br />
|
||||||
|
* Each process begins with a main thread and additional threads can
|
||||||
|
* be created using NSThread. The GNUstep implementation of OpenStep
|
||||||
|
* has been carefully designed so that the internals of the base
|
||||||
|
* library do not use threading (except for methods which explicitly
|
||||||
|
* deal with threads of course) so that you can write applications
|
||||||
|
* without threading. Non-threaded applications are more efficient
|
||||||
|
* (no locking is required) and are easier to debug during development.
|
||||||
|
*/
|
||||||
@interface NSThread : NSObject
|
@interface NSThread : NSObject
|
||||||
{
|
{
|
||||||
@private
|
@private
|
||||||
|
@ -48,6 +59,7 @@ extern "C" {
|
||||||
unsigned _stackSize;
|
unsigned _stackSize;
|
||||||
BOOL _cancelled;
|
BOOL _cancelled;
|
||||||
BOOL _active;
|
BOOL _active;
|
||||||
|
BOOL _finished;
|
||||||
NSHandler *_exception_handler; // Not retained.
|
NSHandler *_exception_handler; // Not retained.
|
||||||
NSMutableDictionary *_thread_dictionary;
|
NSMutableDictionary *_thread_dictionary;
|
||||||
struct autorelease_thread_vars _autorelease_vars;
|
struct autorelease_thread_vars _autorelease_vars;
|
||||||
|
@ -56,11 +68,46 @@ extern "C" {
|
||||||
void *_reserved; // For future expansion
|
void *_reserved; // For future expansion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the NSThread object corresponding to the current thread.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* NB. In GNUstep the library internals use the GSCurrentThread()
|
||||||
|
* function as a more efficient mechanism for doing this job - so
|
||||||
|
* you cannot use a category to override this method and expect
|
||||||
|
* the library internals to use your implementation.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
+ (NSThread*) currentThread;
|
+ (NSThread*) currentThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Create a new thread - use this method rather than alloc-init. The new
|
||||||
|
* thread will begin executing the message given by aSelector, aTarget, and
|
||||||
|
* anArgument. This should have no return value, and must set up an
|
||||||
|
* autorelease pool if retain/release memory management is used. It should
|
||||||
|
* free this pool before it finishes execution.</p>
|
||||||
|
*/
|
||||||
+ (void) detachNewThreadSelector: (SEL)aSelector
|
+ (void) detachNewThreadSelector: (SEL)aSelector
|
||||||
toTarget: (id)aTarget
|
toTarget: (id)aTarget
|
||||||
withObject: (id)anArgument;
|
withObject: (id)anArgument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminates the current thread.<br />
|
||||||
|
* Normally you don't need to call this method explicitly,
|
||||||
|
* since exiting the method with which the thread was detached
|
||||||
|
* causes this method to be called automatically.
|
||||||
|
*/
|
||||||
+ (void) exit;
|
+ (void) exit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a flag to say whether the application is multi-threaded or not.<br />
|
||||||
|
* An application is considered to be multi-threaded if any thread other
|
||||||
|
* than the main thread has been started, irrespective of whether that
|
||||||
|
* thread has since terminated.<br />
|
||||||
|
* NB. This method returns YES if called within a handler processing
|
||||||
|
* <code>NSWillBecomeMultiThreadedNotification</code>
|
||||||
|
*/
|
||||||
+ (BOOL) isMultiThreaded;
|
+ (BOOL) isMultiThreaded;
|
||||||
+ (void) sleepUntilDate: (NSDate*)date;
|
+ (void) sleepUntilDate: (NSDate*)date;
|
||||||
|
|
||||||
|
@ -79,6 +126,11 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
+ (NSArray*) callStackReturnAddresses;
|
+ (NSArray*) callStackReturnAddresses;
|
||||||
|
|
||||||
|
/** Returns a boolean indicating whether this thread is the main thread of
|
||||||
|
* the process.
|
||||||
|
*/
|
||||||
|
+ (BOOL) isMainThread;
|
||||||
|
|
||||||
/** Returns the main thread of the process.
|
/** Returns the main thread of the process.
|
||||||
*/
|
*/
|
||||||
+ (NSThread*) mainThread;
|
+ (NSThread*) mainThread;
|
||||||
|
@ -114,6 +166,11 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
- (BOOL) isExecuting;
|
- (BOOL) isExecuting;
|
||||||
|
|
||||||
|
/** Returns a boolean indicating whether the receiving
|
||||||
|
* thread has completed executing.
|
||||||
|
*/
|
||||||
|
- (BOOL) isFinished;
|
||||||
|
|
||||||
/** Returns a boolean indicating whether this thread is the main thread of
|
/** Returns a boolean indicating whether this thread is the main thread of
|
||||||
* the process.
|
* the process.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -279,6 +279,9 @@ typedef enum {
|
||||||
* from the runloop when the event/descriptor is triggered.
|
* from the runloop when the event/descriptor is triggered.
|
||||||
*/
|
*/
|
||||||
- (void) fire;
|
- (void) fire;
|
||||||
|
/* Cancel all pending performers.
|
||||||
|
*/
|
||||||
|
- (void) invalidate;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/* Return (and optionally create) GSRunLoopThreadInfo for the specified
|
/* Return (and optionally create) GSRunLoopThreadInfo for the specified
|
||||||
|
|
|
@ -103,6 +103,7 @@ static NSNotificationCenter *nc = nil;
|
||||||
SEL selector;
|
SEL selector;
|
||||||
NSConditionLock *lock; // Not retained.
|
NSConditionLock *lock; // Not retained.
|
||||||
NSArray *modes;
|
NSArray *modes;
|
||||||
|
BOOL invalidated;
|
||||||
}
|
}
|
||||||
+ (GSPerformHolder*) newForReceiver: (id)r
|
+ (GSPerformHolder*) newForReceiver: (id)r
|
||||||
argument: (id)a
|
argument: (id)a
|
||||||
|
@ -110,6 +111,8 @@ static NSNotificationCenter *nc = nil;
|
||||||
modes: (NSArray*)m
|
modes: (NSArray*)m
|
||||||
lock: (NSConditionLock*)l;
|
lock: (NSConditionLock*)l;
|
||||||
- (void) fire;
|
- (void) fire;
|
||||||
|
- (void) invalidate;
|
||||||
|
- (BOOL) isInvalidated;
|
||||||
- (NSArray*) modes;
|
- (NSArray*) modes;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -406,17 +409,6 @@ gnustep_base_thread_callback(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class encapsulates OpenStep threading. See [NSLock] and its
|
|
||||||
* subclasses for handling synchronisation between threads.<br />
|
|
||||||
* Each process begins with a main thread and additional threads can
|
|
||||||
* be created using NSThread. The GNUstep implementation of OpenStep
|
|
||||||
* has been carefully designed so that the internals of the base
|
|
||||||
* library do not use threading (except for methods which explicitly
|
|
||||||
* deal with threads of course) so that you can write applications
|
|
||||||
* without threading. Non-threaded applications are more efficient
|
|
||||||
* (no locking is required) and are easier to debug during development.
|
|
||||||
*/
|
|
||||||
@implementation NSThread
|
@implementation NSThread
|
||||||
|
|
||||||
+ (NSArray*) callStackReturnAddresses
|
+ (NSArray*) callStackReturnAddresses
|
||||||
|
@ -426,17 +418,6 @@ gnustep_base_thread_callback(void)
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Returns the NSThread object corresponding to the current thread.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* NB. In GNUstep the library internals use the GSCurrentThread()
|
|
||||||
* function as a more efficient mechanism for doing this job - so
|
|
||||||
* you cannot use a category to override this method and expect
|
|
||||||
* the library internals to use your implementation.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
+ (NSThread*) currentThread
|
+ (NSThread*) currentThread
|
||||||
{
|
{
|
||||||
NSThread *t = nil;
|
NSThread *t = nil;
|
||||||
|
@ -462,13 +443,6 @@ gnustep_base_thread_callback(void)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Create a new thread - use this method rather than alloc-init. The new
|
|
||||||
* thread will begin executing the message given by aSelector, aTarget, and
|
|
||||||
* anArgument. This should have no return value, and must set up an
|
|
||||||
* autorelease pool if retain/release memory management is used. It should
|
|
||||||
* free this pool before it finishes execution.</p>
|
|
||||||
*/
|
|
||||||
+ (void) detachNewThreadSelector: (SEL)aSelector
|
+ (void) detachNewThreadSelector: (SEL)aSelector
|
||||||
toTarget: (id)aTarget
|
toTarget: (id)aTarget
|
||||||
withObject: (id)anArgument
|
withObject: (id)anArgument
|
||||||
|
@ -487,13 +461,6 @@ gnustep_base_thread_callback(void)
|
||||||
RELEASE(thread);
|
RELEASE(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Terminates the current thread.<br />
|
|
||||||
* Normally you don't need to call this method explicitly,
|
|
||||||
* since exiting the method with which the thread was detached
|
|
||||||
* causes this method to be called automatically.
|
|
||||||
*/
|
|
||||||
+ (void) exit
|
+ (void) exit
|
||||||
{
|
{
|
||||||
NSThread *t;
|
NSThread *t;
|
||||||
|
@ -505,6 +472,7 @@ gnustep_base_thread_callback(void)
|
||||||
* Set the thread to be inactive to avoid any possibility of recursion.
|
* Set the thread to be inactive to avoid any possibility of recursion.
|
||||||
*/
|
*/
|
||||||
t->_active = NO;
|
t->_active = NO;
|
||||||
|
t->_finished = YES;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let observers know this thread is exiting.
|
* Let observers know this thread is exiting.
|
||||||
|
@ -517,6 +485,8 @@ gnustep_base_thread_callback(void)
|
||||||
object: t
|
object: t
|
||||||
userInfo: nil];
|
userInfo: nil];
|
||||||
|
|
||||||
|
[(GSRunLoopThreadInfo*)t->_runLoopInfo invalidate];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* destroy the thread object.
|
* destroy the thread object.
|
||||||
*/
|
*/
|
||||||
|
@ -558,14 +528,11 @@ gnustep_base_thread_callback(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
+ (BOOL) isMainThread
|
||||||
* Returns a flag to say whether the application is multi-threaded or not.<br />
|
{
|
||||||
* An application is considered to be multi-threaded if any thread other
|
return (GSCurrentThread() == defaultThread ? YES : NO);
|
||||||
* than the main thread has been started, irrespective of whether that
|
}
|
||||||
* thread has since terminated.<br />
|
|
||||||
* NB. This method returns YES if called within a handler processing
|
|
||||||
* <code>NSWillBecomeMultiThreadedNotification</code>
|
|
||||||
*/
|
|
||||||
+ (BOOL) isMultiThreaded
|
+ (BOOL) isMultiThreaded
|
||||||
{
|
{
|
||||||
return entered_multi_threaded_state;
|
return entered_multi_threaded_state;
|
||||||
|
@ -710,6 +677,7 @@ gnustep_base_thread_callback(void)
|
||||||
_exception_handler = NULL;
|
_exception_handler = NULL;
|
||||||
_cancelled = NO;
|
_cancelled = NO;
|
||||||
_active = NO;
|
_active = NO;
|
||||||
|
_finished = NO;
|
||||||
_name = nil;
|
_name = nil;
|
||||||
init_autorelease_thread_vars(&_autorelease_vars);
|
init_autorelease_thread_vars(&_autorelease_vars);
|
||||||
return self;
|
return self;
|
||||||
|
@ -725,6 +693,11 @@ gnustep_base_thread_callback(void)
|
||||||
return _active;
|
return _active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL) isFinished
|
||||||
|
{
|
||||||
|
return _finished;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL) isMainThread
|
- (BOOL) isMainThread
|
||||||
{
|
{
|
||||||
return (self == defaultThread ? YES : NO);
|
return (self == defaultThread ? YES : NO);
|
||||||
|
@ -833,6 +806,13 @@ pthread_detach(pthread_self());
|
||||||
NSStringFromClass([self class]),
|
NSStringFromClass([self class]),
|
||||||
NSStringFromSelector(_cmd)];
|
NSStringFromSelector(_cmd)];
|
||||||
}
|
}
|
||||||
|
if (_finished == YES)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInternalInconsistencyException
|
||||||
|
format: @"[%@-$@] called on finished thread",
|
||||||
|
NSStringFromClass([self class]),
|
||||||
|
NSStringFromSelector(_cmd)];
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure the notification is posted BEFORE the new thread starts.
|
/* Make sure the notification is posted BEFORE the new thread starts.
|
||||||
*/
|
*/
|
||||||
|
@ -898,10 +878,9 @@ pthread_detach(pthread_self());
|
||||||
|
|
||||||
- (void) dealloc
|
- (void) dealloc
|
||||||
{
|
{
|
||||||
|
[self invalidate];
|
||||||
DESTROY(lock);
|
DESTROY(lock);
|
||||||
DESTROY(loop);
|
DESTROY(loop);
|
||||||
[performers makeObjectsPerformSelector: @selector(invalidate)];
|
|
||||||
DESTROY(performers);
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
if (event != INVALID_HANDLE_VALUE)
|
if (event != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
|
@ -951,6 +930,14 @@ pthread_detach(pthread_self());
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) invalidate
|
||||||
|
{
|
||||||
|
[lock lock];
|
||||||
|
[performers makeObjectsPerformSelector: @selector(invalidate)];
|
||||||
|
[performers removeAllObjects];
|
||||||
|
[lock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) fire
|
- (void) fire
|
||||||
{
|
{
|
||||||
NSArray *toDo;
|
NSArray *toDo;
|
||||||
|
@ -1054,11 +1041,7 @@ GSRunLoopInfoForThread(NSThread *aThread)
|
||||||
DESTROY(receiver);
|
DESTROY(receiver);
|
||||||
DESTROY(argument);
|
DESTROY(argument);
|
||||||
DESTROY(modes);
|
DESTROY(modes);
|
||||||
if (lock == nil)
|
if (lock != nil)
|
||||||
{
|
|
||||||
RELEASE(self);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
NSConditionLock *l = lock;
|
NSConditionLock *l = lock;
|
||||||
|
|
||||||
|
@ -1068,6 +1051,28 @@ GSRunLoopInfoForThread(NSThread *aThread)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) invalidate
|
||||||
|
{
|
||||||
|
if (invalidated == NO)
|
||||||
|
{
|
||||||
|
invalidated = YES;
|
||||||
|
DESTROY(receiver);
|
||||||
|
if (lock != nil)
|
||||||
|
{
|
||||||
|
NSConditionLock *l = lock;
|
||||||
|
|
||||||
|
[lock lock];
|
||||||
|
lock = nil;
|
||||||
|
[l unlockWithCondition: 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isInvalidated
|
||||||
|
{
|
||||||
|
return invalidated;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSArray*) modes
|
- (NSArray*) modes
|
||||||
{
|
{
|
||||||
return modes;
|
return modes;
|
||||||
|
@ -1120,12 +1125,18 @@ GSRunLoopInfoForThread(NSThread *aThread)
|
||||||
info = GSRunLoopInfoForThread(aThread);
|
info = GSRunLoopInfoForThread(aThread);
|
||||||
if (t == aThread)
|
if (t == aThread)
|
||||||
{
|
{
|
||||||
|
/* Perform in current thread.
|
||||||
|
*/
|
||||||
if (aFlag == YES || info->loop == nil)
|
if (aFlag == YES || info->loop == nil)
|
||||||
{
|
{
|
||||||
|
/* Wait until done or no run loop.
|
||||||
|
*/
|
||||||
[self performSelector: aSelector withObject: anObject];
|
[self performSelector: aSelector withObject: anObject];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Don't wait ... schedule operation in run loop.
|
||||||
|
*/
|
||||||
[info->loop performSelector: aSelector
|
[info->loop performSelector: aSelector
|
||||||
target: self
|
target: self
|
||||||
argument: anObject
|
argument: anObject
|
||||||
|
@ -1138,6 +1149,11 @@ GSRunLoopInfoForThread(NSThread *aThread)
|
||||||
GSPerformHolder *h;
|
GSPerformHolder *h;
|
||||||
NSConditionLock *l = nil;
|
NSConditionLock *l = nil;
|
||||||
|
|
||||||
|
if ([t isFinished] == YES)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInternalInconsistencyException
|
||||||
|
format: @"perform on finished thread"];
|
||||||
|
}
|
||||||
if (aFlag == YES)
|
if (aFlag == YES)
|
||||||
{
|
{
|
||||||
l = [[NSConditionLock alloc] init];
|
l = [[NSConditionLock alloc] init];
|
||||||
|
@ -1154,6 +1170,12 @@ GSRunLoopInfoForThread(NSThread *aThread)
|
||||||
[l lockWhenCondition: 1];
|
[l lockWhenCondition: 1];
|
||||||
[l unlock];
|
[l unlock];
|
||||||
RELEASE(l);
|
RELEASE(l);
|
||||||
|
if ([h isInvalidated] == YES)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInternalInconsistencyException
|
||||||
|
format: @"perform on finished thread"];
|
||||||
|
RELEASE(h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RELEASE(h);
|
RELEASE(h);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue