From 18ef693deca139db1be92ee6769cac19baf588d9 Mon Sep 17 00:00:00 2001 From: rfm Date: Tue, 4 Nov 2014 09:08:47 +0000 Subject: [PATCH] try to make thread synchronisation I/O cleaner and perhaps safer if we do something like run out of file descriptors for the pipe. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@38153 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 7 +++++++ Source/NSThread.m | 36 +++++++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 097f1897a..f8ffed879 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2014-11-04 Richard Frith-Macdonald + + * Source/NSThread.m: When handling perform in another thread, check + more carefully for inter-thread communications (pipe on unix, event + on windows) and make sure we invalidate performers safely outside + the lock protected region when I/O is complete. + 2014-11-01 Richard Frith-Macdonald * Source/GSHTTPURLHandle.m: Fix leak of handle when starting a new diff --git a/Source/NSThread.m b/Source/NSThread.m index 9aa8fe3f4..a00b1e252 100644 --- a/Source/NSThread.m +++ b/Source/NSThread.m @@ -897,12 +897,20 @@ static void *nsthreadLauncher(void* thread) @implementation GSRunLoopThreadInfo - (void) addPerformer: (id)performer { + BOOL signalled = NO; + [lock lock]; - [performers addObject: performer]; #if defined(__MINGW__) - if (SetEvent(event) == 0) + if (INVALID_HANDLE_VALUE != event) { - NSLog(@"Set event failed - %@", [NSError _last]); + if (SetEvent(event) == 0) + { + NSLog(@"Set event failed - %@", [NSError _last]); + } + else + { + signalled = YES; + } } #else /* The write could concievably fail if the pipe is full. @@ -911,19 +919,30 @@ static void *nsthreadLauncher(void* thread) * and its runloop might stop during that ... so we need to check that * outputFd is still valid. */ - while (outputFd >= 0 && write(outputFd, "0", 1) != 1) + while (outputFd >= 0 + && NO == (signalled = (write(outputFd, "0", 1) == 1) ? YES : NO)) { [lock unlock]; [lock lock]; } #endif + if (YES == signalled) + { + [performers addObject: performer]; + } [lock unlock]; + if (NO == signalled) + { + /* We failed to add the performer ... so we must invalidate it in + * case there is code waiting for it to complete. + */ + [performer invalidate]; + } } - (void) dealloc { [self invalidate]; - DESTROY(performers); DESTROY(lock); DESTROY(loop); [super dealloc]; @@ -990,9 +1009,11 @@ static void *nsthreadLauncher(void* thread) - (void) invalidate { + NSArray *p; + [lock lock]; - [performers makeObjectsPerformSelector: @selector(invalidate)]; - [performers removeAllObjects]; + p = [performers autorelease]; + performers = nil; #ifdef __MINGW__ if (event != INVALID_HANDLE_VALUE) { @@ -1012,6 +1033,7 @@ static void *nsthreadLauncher(void* thread) } #endif [lock unlock]; + [p makeObjectsPerformSelector: @selector(invalidate)]; } - (void) fire