From 945ca4abfb42cf3aa336653fdca851d9659f1938 Mon Sep 17 00:00:00 2001 From: Richard Frith-MacDonald Date: Mon, 1 Aug 2016 07:40:36 +0000 Subject: [PATCH] use fairStart to get a fairer distribution of I/O across multiple handles git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@40045 72102866-910b-0410-8b05-ffd578937521 --- Source/win32/GSRunLoopCtxt.m | 214 ++++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 94 deletions(-) diff --git a/Source/win32/GSRunLoopCtxt.m b/Source/win32/GSRunLoopCtxt.m index 1186e39b4..298f17d99 100644 --- a/Source/win32/GSRunLoopCtxt.m +++ b/Source/win32/GSRunLoopCtxt.m @@ -382,23 +382,32 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = wait_timeout = 0; } - i = 0; - handleArray[i++] = threadInfo->event; // Signal from other thread - hEnum = NSEnumerateMapTable(handleMap); - while (NSNextMapEnumeratorPair(&hEnum, &handle, (void**)&watcher)) + handleArray[0] = threadInfo->event; // Signal from other thread + num_handles = NSCountMapTable(handleMap) + 1; + if (num_handles >= MAXIMUM_WAIT_OBJECTS) { - if (i < MAXIMUM_WAIT_OBJECTS-1) + NSLog(@"Too many handles to wait for ... only using %d of %d", + MAXIMUM_WAIT_OBJECTS-1, num_handles); + num_handles = MAXIMUM_WAIT_OBJECTS-1; + } + count = num_handles - 1; // Count of handles excluding thread event + if (count > 0) + { + i = 1 + (fairStart++ % count); + hEnum = NSEnumerateMapTable(handleMap); + while (count-- > 0 + && NSNextMapEnumeratorPair(&hEnum, &handle, (void**)&watcher)) { + if (i >= num_handles) + { + i = 1; + } handleArray[i++] = (HANDLE)handle; } - else - { - NSLog(@"Too many handles to wait for ... only using %d of %d", - i, num_handles); - } + NSEndMapTableEnumeration(&hEnum); } - NSEndMapTableEnumeration(&hEnum); - num_handles = i; + + completed = NO; /* Clear all the windows messages first before we wait, * since MsgWaitForMultipleObjects only signals on NEW messages @@ -406,11 +415,17 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = if ([self processAllWindowsMessages: num_winMsgs within: contexts] == YES) { // Processed something ... no need to wait. - wait_return = WAIT_OBJECT_0; + wait_timeout = 0; + num_winMsgs = 0; existingMessages = YES; } - else if (num_winMsgs > 0) + + if (num_winMsgs > 0) { + NSDebugMLLog(@"NSRunLoop", + @"wait for messages and %d handles for %d milliseconds", + num_handles, wait_timeout); + /* * Wait for signalled events or window messages. */ @@ -419,6 +434,9 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = } else if (num_handles > 0) { + NSDebugMLLog(@"NSRunLoop", + @"wait for %d handles for %d milliseconds", num_handles, wait_timeout); + /* * We are not interested in windows messages ... just wait for * signalled events. @@ -428,19 +446,22 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = } else { + NSDebugMLLog(@"NSRunLoop", + @"wait for %d milliseconds", wait_timeout); SleepEx(wait_timeout, TRUE); - wait_return = WAIT_OBJECT_0; + wait_return = WAIT_TIMEOUT; } - NSDebugMLLog(@"NSRunLoop", @"wait returned %d", wait_return); // check wait errors - if (wait_return == WAIT_FAILED) + if (WAIT_FAILED == wait_return + || (wait_return >= WAIT_ABANDONED_0 + && wait_return < WAIT_ABANDONED_0 + num_handles)) { int i; BOOL found = NO; NSDebugMLLog(@"NSRunLoop", @"WaitForMultipleObjects() error in " - @"-acceptInputForMode:beforeDate: %@", [NSError _last]); + @"-pollUntil:within: %@", [NSError _last]); /* * Check each handle in turn until either we find one which has an * event signalled, or we find the one which caused the original @@ -461,7 +482,7 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = if (found == NO) { NSLog(@"WaitForMultipleObjects() error in " - @"-acceptInputForMode:beforeDate: %@", [NSError _last]); + @"-pollUntil:within: %@", [NSError _last]); abort (); } } @@ -476,98 +497,103 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks = GSRunLoopWatcher *watcher; watcher = (GSRunLoopWatcher*)GSIArrayItemAtIndex(_trigger, count).obj; - if (watcher->_invalidated == NO) - { - NSDebugMLLog(@"NSRunLoop", @"trigger watcher %@", watcher); - i = [contexts count]; - while (i-- > 0) - { - GSRunLoopCtxt *c = [contexts objectAtIndex: i]; + if (watcher->_invalidated == NO) + { + NSDebugMLLog(@"NSRunLoop", @"trigger watcher %@", watcher); + i = [contexts count]; + while (i-- > 0) + { + GSRunLoopCtxt *c = [contexts objectAtIndex: i]; - if (c != self) - { - [c endEvent: (void*)watcher for: watcher]; - } - } - /* - * The watcher is still valid - so call its - * receivers event handling method. - */ - [watcher->receiver receivedEvent: watcher->data - type: watcher->type - extra: watcher->data - forMode: mode]; - } - GSPrivateNotifyASAP(mode); + if (c != self) + { + [c endEvent: (void*)watcher for: watcher]; + } + } + /* + * The watcher is still valid - so call its + * receivers event handling method. + */ + [watcher->receiver receivedEvent: watcher->data + type: watcher->type + extra: watcher->data + forMode: mode]; + } + GSPrivateNotifyASAP(mode); } - if (existingMessages) + if (WAIT_TIMEOUT == wait_return) { - NSDebugMLLog(@"NSRunLoop", @"processed windows messages"); - return YES; + // there is no event to handle + if (existingMessages) + { + NSDebugMLLog(@"NSRunLoop", @"processed windows messages"); + } + else + { + NSDebugMLLog(@"NSRunLoop", @"timeout without events"); + completed = YES; + return NO; + } } - - // if there are windows message - if (wait_return == WAIT_OBJECT_0 + num_handles) + else if (WAIT_OBJECT_0 + num_handles == wait_return) { + // one or more windows message NSDebugMLLog(@"NSRunLoop", @"processing windows messages"); - return [self processAllWindowsMessages: num_winMsgs within: contexts]; + [self processAllWindowsMessages: num_winMsgs within: contexts]; } - - // if there aren't events - if (wait_return == WAIT_TIMEOUT) + else if ((i = wait_return - WAIT_OBJECT_0) >= 0 && i < num_handles) { - NSDebugMLLog(@"NSRunLoop", @"timeout without events"); - completed = YES; - return NO; - } - - /* - * Look the event that WaitForMultipleObjects() says is ready; - * get the corresponding fd for that handle event and notify - * the corresponding object for the ready fd. - */ - i = wait_return - WAIT_OBJECT_0; + /* Look the event that WaitForMultipleObjects() says is ready; + * get the corresponding fd for that handle event and notify + * the corresponding object for the ready fd. + */ + NSDebugMLLog(@"NSRunLoop", @"Handle signalled %d", i); + + handle = handleArray[i]; - NSDebugMLLog(@"NSRunLoop", @"Event listen %d", i); - - handle = handleArray[i]; + if (handle == threadInfo->event) + { + watcher = nil; + NSDebugMLLog(@"NSRunLoop", @"Fire perform on thread"); + [threadInfo fire]; + } + else + { + watcher = (GSRunLoopWatcher*)NSMapGet(handleMap, (void*)handle); + NSDebugMLLog(@"NSRunLoop", @"Fire watcher %@", watcher); + } + if (watcher != nil && watcher->_invalidated == NO) + { + i = [contexts count]; + while (i-- > 0) + { + GSRunLoopCtxt *c = [contexts objectAtIndex: i]; - if (handle == threadInfo->event) - { - watcher = nil; - NSDebugMLLog(@"NSRunLoop", @"Fire perform on thread"); - [threadInfo fire]; + if (c != self) + { + [c endEvent: (void*)handle for: watcher]; + } + } + /* + * The watcher is still valid - so call its receivers + * event handling method. + */ + [watcher->receiver receivedEvent: watcher->data + type: watcher->type + extra: (void*)handle + forMode: mode]; + } } else { - watcher = (GSRunLoopWatcher*)NSMapGet(handleMap, (void*)handle); - } - if (watcher != nil && watcher->_invalidated == NO) - { - i = [contexts count]; - while (i-- > 0) - { - GSRunLoopCtxt *c = [contexts objectAtIndex: i]; - - if (c != self) - { - [c endEvent: (void*)handle for: watcher]; - } - } - /* - * The watcher is still valid - so call its receivers - * event handling method. - */ - NSDebugMLLog(@"NSRunLoop", @"Event callback found"); - [watcher->receiver receivedEvent: watcher->data - type: watcher->type - extra: (void*)handle - forMode: mode]; + NSDebugMLLog(@"NSRunLoop", @"unexpected result %d", wait_return); + GSPrivateNotifyASAP(mode); + completed = NO; + return NO; } GSPrivateNotifyASAP(mode); - completed = YES; return YES; }