mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
thread exit improvements
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28638 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
a456517b42
commit
b3bb5d96da
2 changed files with 65 additions and 35 deletions
|
@ -5,6 +5,9 @@
|
|||
* config.mak.in:
|
||||
* Source/GNUmakefile:
|
||||
Attempt to tidy up config now that pthreads are mandatory.
|
||||
* Source/NSThread.m:
|
||||
Fix various bugs related to thread exit, Prevent crashes at program
|
||||
termination ...nastily obvious on mingw.
|
||||
|
||||
2009-09-07 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
|
|
|
@ -288,35 +288,59 @@ inline static void objc_thread_add (void)
|
|||
*/
|
||||
static BOOL entered_multi_threaded_state = NO;
|
||||
|
||||
static NSThread *defaultThread;
|
||||
static NSLock *thread_creation_lock;
|
||||
|
||||
/**
|
||||
* Pthread cleanup call; used to free the current NSThread object when the
|
||||
* thread exits.
|
||||
*/
|
||||
static void releaseThread(void *thread)
|
||||
{
|
||||
[(NSThread*)thread release];
|
||||
}
|
||||
|
||||
static pthread_key_t thread_object_key;
|
||||
|
||||
/**
|
||||
* These functions are serious examples of premature optimisation.
|
||||
* Pthread cleanup call.
|
||||
*
|
||||
* We should normally not get here ... because threads should exit properly
|
||||
* and clean up, so that this function doesn't get called. However if a
|
||||
* thread terminates for some reason without calling the exit method, we
|
||||
* can at least log it.
|
||||
*
|
||||
* We can't do anything more than that since at the point
|
||||
* when this function is called, the thread specific data is no longer
|
||||
* available, so the currentThread method will always fail and the
|
||||
* repercussions of that would well be a crash.
|
||||
*
|
||||
* As a special case, we ignore the exit of the default thread ... that one
|
||||
* will usually terminate without calling the exit method as it ends the
|
||||
* whole process by returning from the 'main' function.
|
||||
*/
|
||||
static void exitedThread(void *thread)
|
||||
{
|
||||
if (thread != defaultThread)
|
||||
{
|
||||
fprintf(stderr, "WARNING thread %p terminated without calling +exit!\n",
|
||||
thread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* These functions needed because sending messages to classes is a seriously
|
||||
* slow process with gcc and the gnu runtime.
|
||||
*/
|
||||
inline NSThread*
|
||||
GSCurrentThread(void)
|
||||
{
|
||||
return [NSThread currentThread];
|
||||
if (defaultThread == nil)
|
||||
{
|
||||
[NSThread currentThread];
|
||||
}
|
||||
return (NSThread*)pthread_getspecific(thread_object_key);
|
||||
}
|
||||
|
||||
NSMutableDictionary*
|
||||
GSDictionaryForThread(NSThread *t)
|
||||
{
|
||||
if (nil == t)
|
||||
{
|
||||
t = [NSThread currentThread];
|
||||
}
|
||||
return [t threadDictionary];
|
||||
if (nil == t)
|
||||
{
|
||||
t = GSCurrentThread();
|
||||
}
|
||||
return [t threadDictionary];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -410,21 +434,23 @@ static void setThreadForCurrentThread(NSThread *t)
|
|||
|
||||
return stack;
|
||||
}
|
||||
+ (BOOL)_createThreadForCurrentPthread
|
||||
|
||||
+ (BOOL) _createThreadForCurrentPthread
|
||||
{
|
||||
NSThread *t = pthread_getspecific(thread_object_key);
|
||||
|
||||
if (t == nil)
|
||||
{
|
||||
[thread_creation_lock lock];
|
||||
t = pthread_getspecific(thread_object_key);
|
||||
if (t == nil)
|
||||
[thread_creation_lock lock];
|
||||
t = pthread_getspecific(thread_object_key);
|
||||
if (t == nil)
|
||||
{
|
||||
t = [self new];
|
||||
pthread_setspecific(thread_object_key, t);
|
||||
[thread_creation_lock unlock];
|
||||
return YES;
|
||||
t = [self new];
|
||||
pthread_setspecific(thread_object_key, t);
|
||||
[thread_creation_lock unlock];
|
||||
return YES;
|
||||
}
|
||||
[thread_creation_lock unlock];
|
||||
[thread_creation_lock unlock];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
@ -453,7 +479,7 @@ static void setThreadForCurrentThread(NSThread *t)
|
|||
|
||||
+ (void) exit
|
||||
{
|
||||
NSThread *t;
|
||||
NSThread *t;
|
||||
|
||||
t = GSCurrentThread();
|
||||
if (t->_active == YES)
|
||||
|
@ -480,11 +506,11 @@ static void setThreadForCurrentThread(NSThread *t)
|
|||
#if GS_WITH_GC && defined(HAVE_GC_REGISTER_MY_THREAD)
|
||||
GC_unregister_my_thread();
|
||||
#endif
|
||||
pthread_setspecific(thread_object_key, nil);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static NSThread *defaultThread;
|
||||
/*
|
||||
* Class initialization
|
||||
*/
|
||||
|
@ -492,13 +518,12 @@ static NSThread *defaultThread;
|
|||
{
|
||||
if (self == [NSThread class])
|
||||
{
|
||||
|
||||
if (pthread_key_create(&thread_object_key, releaseThread))
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Unable to create thread key!"];
|
||||
}
|
||||
thread_creation_lock = [NSLock new];
|
||||
if (pthread_key_create(&thread_object_key, exitedThread))
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Unable to create thread key!"];
|
||||
}
|
||||
thread_creation_lock = [NSLock new];
|
||||
/*
|
||||
* Ensure that the default thread exists.
|
||||
*/
|
||||
|
@ -667,6 +692,7 @@ static NSThread *defaultThread;
|
|||
|
||||
- (id) init
|
||||
{
|
||||
init_autorelease_thread_vars(&_autorelease_vars);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -1251,7 +1277,7 @@ GSRunLoopInfoForThread(NSThread *aThread)
|
|||
BOOL
|
||||
GSRegisterCurrentThread (void)
|
||||
{
|
||||
return [NSThread _createThreadForCurrentPthread];
|
||||
return [NSThread _createThreadForCurrentPthread];
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
|
@ -1291,5 +1317,6 @@ GSUnregisterCurrentThread (void)
|
|||
object: thread
|
||||
userInfo: nil];
|
||||
|
||||
pthread_setspecific(thread_object_key, nil);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue