Restructure handling of thread exit to avoid setting up separate

notification handlers for each connection.  Optimise a little.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@20380 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2004-11-25 17:00:45 +00:00
parent aa686b1411
commit d3bbcd8394
2 changed files with 48 additions and 27 deletions

View file

@ -1,6 +1,11 @@
2004-11-25 Richard Frith-Macdonald <rfm@gnu.org> 2004-11-25 Richard Frith-Macdonald <rfm@gnu.org>
* Tools/gdomap.c: make respond to --help as to -H * Tools/gdomap.c: make respond to --help as to -H
* Source/NSConnection.m: ([_threadWillExit:]) change to be a class
method rather then instance method. Implement removeal of runloop
of exiting thread unconditionally from all threads...
the code in [removeRunLoop:] is safely lock protected.
Use GSRunLoopForThread() for performance throughout.
2004-11-24 15:08 Patrick McFarland <unknown@panax.com> 2004-11-24 15:08 Patrick McFarland <unknown@panax.com>

View file

@ -78,6 +78,8 @@
#include "Foundation/NSDebug.h" #include "Foundation/NSDebug.h"
#include "GSInvocation.h" #include "GSInvocation.h"
extern NSRunLoop *GSRunLoopForThread(NSThread*);
#define F_LOCK(X) {NSDebugFLLog(@"GSConnection",@"Lock %@",X);[X lock];} #define F_LOCK(X) {NSDebugFLLog(@"GSConnection",@"Lock %@",X);[X lock];}
#define F_UNLOCK(X) {NSDebugFLLog(@"GSConnection",@"Unlock %@",X);[X unlock];} #define F_UNLOCK(X) {NSDebugFLLog(@"GSConnection",@"Unlock %@",X);[X unlock];}
#define M_LOCK(X) {NSDebugMLLog(@"GSConnection",@"Lock %@",X);[X lock];} #define M_LOCK(X) {NSDebugMLLog(@"GSConnection",@"Lock %@",X);[X lock];}
@ -211,7 +213,7 @@ stringFromMsgType(int type)
- (void) _service_rootObject: (NSPortCoder*)rmc; - (void) _service_rootObject: (NSPortCoder*)rmc;
- (void) _service_shutdown: (NSPortCoder*)rmc; - (void) _service_shutdown: (NSPortCoder*)rmc;
- (void) _service_typeForSelector: (NSPortCoder*)rmc; - (void) _service_typeForSelector: (NSPortCoder*)rmc;
- (void) _threadWillExit: (NSNotification*)notification; + (void) _threadWillExit: (NSNotification*)notification;
@end @end
#define _proxiesGate _refGate #define _proxiesGate _refGate
@ -488,6 +490,8 @@ static NSLock *cached_proxies_gate = nil;
{ {
if (self == [NSConnection class]) if (self == [NSConnection class])
{ {
NSNotificationCenter *nc;
connectionClass = self; connectionClass = self;
dateClass = [NSDate class]; dateClass = [NSDate class];
distantObjectClass = [NSDistantObject class]; distantObjectClass = [NSDistantObject class];
@ -520,6 +524,16 @@ static NSLock *cached_proxies_gate = nil;
{ {
root_object_map_gate = [GSLazyLock new]; root_object_map_gate = [GSLazyLock new];
} }
/*
* When any thread exits, we must check to see if we are using its
* runloop, and remove ourselves from it if necessary.
*/
nc = [NSNotificationCenter defaultCenter];
[nc addObserver: self
selector: @selector(_threadWillExit:)
name: NSThreadWillExitNotification
object: nil];
} }
} }
@ -639,7 +653,7 @@ static NSLock *cached_proxies_gate = nil;
{ {
if ([_runLoops indexOfObjectIdenticalTo: loop] == NSNotFound) if ([_runLoops indexOfObjectIdenticalTo: loop] == NSNotFound)
{ {
unsigned c = [_requestModes count]; unsigned c = [_requestModes count];
while (c-- > 0) while (c-- > 0)
{ {
@ -892,7 +906,7 @@ static NSLock *cached_proxies_gate = nil;
* Set up request modes array and make sure the receiving port * Set up request modes array and make sure the receiving port
* is added to the run loop to get data. * is added to the run loop to get data.
*/ */
loop = [runLoopClass currentRunLoop]; loop = GSRunLoopForThread(nil);
_runLoops = [[NSMutableArray alloc] initWithObjects: &loop count: 1]; _runLoops = [[NSMutableArray alloc] initWithObjects: &loop count: 1];
_requestModes = [[NSMutableArray alloc] initWithCapacity: 2]; _requestModes = [[NSMutableArray alloc] initWithCapacity: 2];
[self addRequestMode: NSDefaultRunLoopMode]; [self addRequestMode: NSDefaultRunLoopMode];
@ -953,15 +967,6 @@ static NSLock *cached_proxies_gate = nil;
object: s]; object: s];
} }
/*
* When any thread exits, we must check to see if we are using its
* runloop, and remove ourselves from it if necessary.
*/
[nCenter addObserver: self
selector: @selector(_threadWillExit:)
name: NSThreadWillExitNotification
object: nil];
/* In order that connections may be deallocated - there is an /* In order that connections may be deallocated - there is an
implementation of [-release] to automatically remove the connection implementation of [-release] to automatically remove the connection
from this array when it is the only thing retaining it. */ from this array when it is the only thing retaining it. */
@ -969,7 +974,7 @@ static NSLock *cached_proxies_gate = nil;
M_UNLOCK(connection_table_gate); M_UNLOCK(connection_table_gate);
[nCenter postNotificationName: NSConnectionDidInitializeNotification [nCenter postNotificationName: NSConnectionDidInitializeNotification
object: self]; object: self];
return self; return self;
} }
@ -1092,7 +1097,6 @@ static NSLock *cached_proxies_gate = nil;
} }
M_UNLOCK(_proxiesGate); M_UNLOCK(_proxiesGate);
#if 1
/* /*
* If we are invalidated, we shouldn't be receiving any event and * If we are invalidated, we shouldn't be receiving any event and
* should not need to be in any run loops. * should not need to be in any run loops.
@ -1101,7 +1105,6 @@ static NSLock *cached_proxies_gate = nil;
{ {
[self removeRunLoop: [_runLoops lastObject]]; [self removeRunLoop: [_runLoops lastObject]];
} }
#endif
/* /*
* Invalidate the current conversation so we don't leak. * Invalidate the current conversation so we don't leak.
@ -1400,7 +1403,7 @@ static NSLock *cached_proxies_gate = nil;
*/ */
- (void) runInNewThread - (void) runInNewThread
{ {
[self removeRunLoop: [runLoopClass currentRunLoop]]; [self removeRunLoop: GSRunLoopForThread(nil)];
[NSThread detachNewThreadSelector: @selector(_runInNewThread) [NSThread detachNewThreadSelector: @selector(_runInNewThread)
toTarget: self toTarget: self
withObject: nil]; withObject: nil];
@ -1750,7 +1753,8 @@ static void retEncoder (DOContext *ctxt)
const char *type; const char *type;
retval_t retframe; retval_t retframe;
DOContext ctxt; DOContext ctxt;
NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; NSThread *thread = GSCurrentThread();
NSRunLoop *runLoop = GSRunLoopForThread(thread);
memset(&ctxt, 0, sizeof(ctxt)); memset(&ctxt, 0, sizeof(ctxt));
ctxt.connection = self; ctxt.connection = self;
@ -1893,7 +1897,8 @@ static void retEncoder (DOContext *ctxt)
BOOL needsResponse; BOOL needsResponse;
const char *type; const char *type;
DOContext ctxt; DOContext ctxt;
NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; NSThread *thread = GSCurrentThread();
NSRunLoop *runLoop = GSRunLoopForThread(thread);
if ([_runLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound) if ([_runLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
{ {
@ -2238,7 +2243,7 @@ static void retEncoder (DOContext *ctxt)
- (void) _runInNewThread - (void) _runInNewThread
{ {
NSRunLoop *loop = [runLoopClass currentRunLoop]; NSRunLoop *loop = GSRunLoopForThread(nil);
[self addRunLoop: loop]; [self addRunLoop: loop];
[loop run]; [loop run];
@ -2356,7 +2361,8 @@ static void callEncoder (DOContext *ctxt)
*/ */
NS_DURING NS_DURING
{ {
NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; NSThread *thread = GSCurrentThread();
NSRunLoop *runLoop = GSRunLoopForThread(thread);
NSParameterAssert (_isValid); NSParameterAssert (_isValid);
if ([_runLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound) if ([_runLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
@ -2619,7 +2625,8 @@ static void callEncoder (DOContext *ctxt)
NSTimeInterval last_interval = 0.0001; NSTimeInterval last_interval = 0.0001;
NSTimeInterval delay_interval = last_interval; NSTimeInterval delay_interval = last_interval;
NSDate *delay_date = nil; NSDate *delay_date = nil;
NSRunLoop *runLoop = [runLoopClass currentRunLoop]; NSThread *thread = GSCurrentThread();
NSRunLoop *runLoop = GSRunLoopForThread(thread);
BOOL isLocked = NO; BOOL isLocked = NO;
/* /*
@ -3535,17 +3542,26 @@ static void callEncoder (DOContext *ctxt)
} }
/** /**
* On thread exit, we need to be removed from the runloop of the thread * On thread exit, we need all connections to be removed from the runloop
* or we will retain that and cause a memory leak. * of the thread or they will retain that and cause a memory leak.
*/ */
- (void) _threadWillExit: (NSNotification*)notification + (void) _threadWillExit: (NSNotification*)notification
{ {
extern NSRunLoop *GSRunLoopForThread(NSThread*);
NSRunLoop *runLoop = GSRunLoopForThread([notification object]); NSRunLoop *runLoop = GSRunLoopForThread([notification object]);
if ([_runLoops indexOfObjectIdenticalTo: runLoop] != NSNotFound) if (runLoop != nil)
{ {
[self removeRunLoop: runLoop]; NSHashEnumerator enumerator;
NSConnection *c;
M_LOCK(connection_table_gate);
enumerator = NSEnumerateHashTable(connection_table);
while ((c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
{
[c removeRunLoop: runLoop];
}
NSEndHashTableEnumeration(&enumerator);
M_UNLOCK(connection_table_gate);
} }
} }