From e26f4054b07bb1aabb560c8e83fe4b3d72865574 Mon Sep 17 00:00:00 2001 From: rfm Date: Thu, 15 Jan 2009 15:06:04 +0000 Subject: [PATCH] Small optimisation and cleanup when getting methods to perform in loop. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@27603 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 9 +++++++ Source/GSRunLoopCtxt.h | 6 +++++ Source/NSRunLoop.m | 21 +++++----------- Source/unix/GSRunLoopCtxt.m | 49 +++++++++++++++++++++++++++++++++++- Source/win32/GSRunLoopCtxt.m | 16 ++++++++++++ 5 files changed, 85 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index bd6f40294..16d6a6fac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-01-15 Richard Frith-Macdonald + + * Source/NSRunLoop.m: + * Source/unix/GSRunLoopCtxt.m: + * Source/GSRunLoopCtxt.h: + * Source/win32/GSRunLoopCtxt.m: + Introduce new method to quickly check for notification of methods + to perform in the current loop. + 2009-01-14 Richard Frith-Macdonald * Source\NSGarbageCollector.m: Avoid compiler warning diff --git a/Source/GSRunLoopCtxt.h b/Source/GSRunLoopCtxt.h index db21d8ee7..95b9f2760 100644 --- a/Source/GSRunLoopCtxt.h +++ b/Source/GSRunLoopCtxt.h @@ -59,6 +59,12 @@ typedef struct{ struct pollfd *pollfds; #endif } +/* Check to see of the thread has been awakened, blocking until it + * does get awakened or until the limit date has been reached. + * A date in the past (or nil) results in a check follwed by an + * immediate return. + */ ++ (BOOL) awakenedBefore: (NSDate*)when; - (void) endEvent: (void*)data for: (GSRunLoopWatcher*)watcher; - (void) endPoll; diff --git a/Source/NSRunLoop.m b/Source/NSRunLoop.m index 28781746b..97f38c412 100644 --- a/Source/NSRunLoop.m +++ b/Source/NSRunLoop.m @@ -1085,7 +1085,8 @@ static inline BOOL timerInvalidated(NSTimer *t) * just poll inputs and return, * otherwise block until input is available or until the * earliest limit date has passed (whichever comes first).
- * If the supplied mode is nil, uses NSDefaultRunLoopMode. + * If the supplied mode is nil, uses NSDefaultRunLoopMode.
+ * If there are no input sources in the mode, returns immediately. */ - (void) acceptInputForMode: (NSString*)mode beforeDate: (NSDate*)limit_date @@ -1129,20 +1130,10 @@ static inline BOOL timerInvalidated(NSTimer *t) NSDebugMLLog(@"NSRunLoop", @"no inputs in mode %@", mode); GSPrivateNotifyASAP(); GSPrivateNotifyIdle(); - /* - * Pause for as long as possible (up to the limit date) - * Call the polling method so we notice thread notifications - * that methods should be performed in this loop. + /* Pause until the limit date or until we might have + * a method to perform in this thread. */ - ti = [limit_date timeIntervalSinceNow]; - if (context == nil) - { - context = [[GSRunLoopCtxt alloc] initWithMode: mode - extra: _extra]; - NSMapInsert(_contextMap, context->mode, context); - RELEASE(context); - } - [context pollUntil: (int)(ti * 1000) within: nil]; + [GSRunLoopCtxt awakenedBefore: nil]; GSPrivateCheckTasks(); if (context != nil) { @@ -1233,7 +1224,7 @@ static inline BOOL timerInvalidated(NSTimer *t) d = [self limitDateForMode: mode]; if (d == nil) { - NSDebugMLLog(@"NSRunLoop", @"run mode with nothing to don %@", mode); + NSDebugMLLog(@"NSRunLoop", @"run mode with nothing to do %@", mode); /* * Notify if any tasks have completed. */ diff --git a/Source/unix/GSRunLoopCtxt.m b/Source/unix/GSRunLoopCtxt.m index 5794ede04..deac3936c 100644 --- a/Source/unix/GSRunLoopCtxt.m +++ b/Source/unix/GSRunLoopCtxt.m @@ -626,6 +626,27 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt) return YES; } ++ (BOOL) awakenedBefore: (NSDate*)when +{ + GSRunLoopThreadInfo *threadInfo = GSRunLoopInfoForThread(nil); + NSTimeInterval ti = (when == nil) ? 0.0 : [when timeIntervalSinceNow]; + int milliseconds = (ti <= 0.0) ? 0 : (int)(ti*1000); + struct pollfd pollfds; + + /* Watch for signals from other threads. + */ + pollfds.fd = threadInfo->inputFd; + pollfds.events = POLLIN; + pollfds.revents = 0; + if (poll(&pollfds, 1, milliseconds) == 1) + { + NSDebugMLLog(@"NSRunLoop", @"Fire perform on thread"); + [threadInfo fire]; + return YES; + } + return NO; +} + #else - (BOOL) pollUntil: (int)milliseconds within: (NSArray*)contexts @@ -684,7 +705,7 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt) NSResetMapTable(_wfdMap); GSIArrayRemoveAllItems(_trigger); - /* Watch for signals from otyher threads. + /* Watch for signals from other threads. */ fd = threadInfo->inputFd; if (fd > fdEnd) @@ -1003,5 +1024,31 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt) return YES; } ++ (BOOL) awakenedBefore: (NSDate*)when +{ + GSRunLoopThreadInfo *threadInfo = GSRunLoopInfoForThread(nil); + NSTimeInterval ti = (when == nil) ? 0.0 : [when timeIntervalSinceNow]; + int milliseconds = (ti <= 0.0) ? 0 : (int)(ti*1000); + struct timeval timeout; + fd_set read_fds; // Mask for read-ready fds. + fd_set exception_fds; // Mask for exception fds. + fd_set write_fds; // Mask for write-ready fds. + + memset(&exception_fds, '\0', sizeof(exception_fds)); + memset(&read_fds, '\0', sizeof(read_fds)); + memset(&write_fds, '\0', sizeof(write_fds)); + timeout.tv_sec = milliseconds/1000; + timeout.tv_usec = (milliseconds - 1000 * timeout.tv_sec) * 1000; + FD_SET (threadInof->inputFd, &read_fds); + if (select (threadInfo->inputFd, &read_fds, &write_fds, + &exception_fds, &timeout) > 0) + { + NSDebugMLLog(@"NSRunLoop", @"Fire perform on thread"); + [threadInfo fire]; + return YES; + } + return NO; +} + #endif @end diff --git a/Source/win32/GSRunLoopCtxt.m b/Source/win32/GSRunLoopCtxt.m index a2eea773b..5eeb4fd2b 100644 --- a/Source/win32/GSRunLoopCtxt.m +++ b/Source/win32/GSRunLoopCtxt.m @@ -563,4 +563,20 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = return YES; } ++ (BOOL) awakenedBefore: (NSDate*)when +{ + GSRunLoopThreadInfo *threadInfo = GSRunLoopInfoForThread(nil); + NSTimeInterval ti = (when == nil) ? 0.0 : [when timeIntervalSinceNow]; + int milliseconds = (ti <= 0.0) ? 0 : (int)(ti*1000); + HANDLE h = threadInfo->event; + + if (WaitForMultipleObjects(1, &h, NO, milliseconds) != WAIT_TIMEOUT) + { + NSDebugMLLog(@"NSRunLoop", @"Fire perform on thread"); + [threadInfo fire]; + return YES; + } + return NO; +} + @end