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
This commit is contained in:
Richard Frith-MacDonald 2016-08-01 07:40:36 +00:00
parent 6f890a5095
commit 945ca4abfb

View file

@ -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.
*/
NSDebugMLLog(@"NSRunLoop", @"Handle signalled %d", i);
/*
* 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;
handle = handleArray[i];
NSDebugMLLog(@"NSRunLoop", @"Event listen %d", 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];
handle = handleArray[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;
}