Various tweaks.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@12123 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2002-01-16 14:00:59 +00:00
parent 0e2bd154dc
commit 22cb892946
4 changed files with 468 additions and 411 deletions

View file

@ -1,3 +1,13 @@
2002-01-16 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSRunLoop.m: Wrap code in exception handlers to reset current
runloop mode if an exception occurs ... may remove this again if the
performance is too bad.
Use initialiser for NSTimer to avoid having to put timers into the
autorelease pool.
* Headers/Foundation/NSTimer.h: Expose GNUstep initialiser since
OpenStep and MacOS-X don't have one.
Wed Jan 16 13:46:24 2002 Nicola Pero <nicola@brainstorm.co.uk> Wed Jan 16 13:46:24 2002 Nicola Pero <nicola@brainstorm.co.uk>
Fixed dynamical loading of frameworks. Fixed dynamical loading of frameworks.

View file

@ -40,9 +40,9 @@
BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */ BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */
BOOL _repeats; BOOL _repeats;
NSTimeInterval _interval; NSTimeInterval _interval;
id _target; id _target;
SEL _selector; SEL _selector;
id _info; id _info;
} }
/* Creating timer objects. */ /* Creating timer objects. */
@ -51,18 +51,18 @@
invocation: (NSInvocation*)invocation invocation: (NSInvocation*)invocation
repeats: (BOOL)f; repeats: (BOOL)f;
+ (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti + (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti
target: object target: (id)object
selector: (SEL)selector selector: (SEL)selector
userInfo: info userInfo: (id)info
repeats: (BOOL)f; repeats: (BOOL)f;
+ (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti + (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti
invocation: (NSInvocation*)invocation invocation: (NSInvocation*)invocation
repeats: (BOOL)f; repeats: (BOOL)f;
+ (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti + (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti
target: object target: (id)object
selector: (SEL)selector selector: (SEL)selector
userInfo: info userInfo: (id)info
repeats: (BOOL)f; repeats: (BOOL)f;
- (void) fire; - (void) fire;
@ -76,6 +76,13 @@
- (NSDate*) fireDate; - (NSDate*) fireDate;
- (id) userInfo; - (id) userInfo;
#ifndef NO_GNUSTEP
- (id) initWithTimeInterval: (NSTimeInterval)ti
targetOrInvocation: (id)object
selector: (SEL)selector
userInfo: (id)info
repeats: (BOOL)f;
#endif
@end @end
#endif #endif

View file

@ -244,8 +244,8 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
@end @end
/* /*
* The GSTimedPerformer class is used to hold information about * The GSTimedPerformer class is used to hold information about
* messages which are due to be sent to objects at a particular time. * messages which are due to be sent to objects at a particular time.
*/ */
@interface GSTimedPerformer: NSObject <GCFinalization> @interface GSTimedPerformer: NSObject <GCFinalization>
{ {
@ -268,6 +268,7 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
- (void) dealloc - (void) dealloc
{ {
[self gcFinalize]; [self gcFinalize];
TEST_RELEASE(timer);
RELEASE(target); RELEASE(target);
RELEASE(argument); RELEASE(argument);
[super dealloc]; [super dealloc];
@ -275,7 +276,7 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
- (void) fire - (void) fire
{ {
timer = nil; DESTROY(timer);
[target performSelector: selector withObject: argument]; [target performSelector: selector withObject: argument];
[[[NSRunLoop currentRunLoop] _timedPerformers] [[[NSRunLoop currentRunLoop] _timedPerformers]
removeObjectIdenticalTo: self]; removeObjectIdenticalTo: self];
@ -284,7 +285,9 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
- (void) gcFinalize - (void) gcFinalize
{ {
if (timer != nil) if (timer != nil)
[timer invalidate]; {
[timer invalidate];
}
} }
- (id) initWithSelector: (SEL)aSelector - (id) initWithSelector: (SEL)aSelector
@ -293,16 +296,17 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
delay: (NSTimeInterval)delay delay: (NSTimeInterval)delay
{ {
self = [super init]; self = [super init];
if (self) if (self != nil)
{ {
selector = aSelector; selector = aSelector;
target = RETAIN(aTarget); target = RETAIN(aTarget);
argument = RETAIN(anArgument); argument = RETAIN(anArgument);
timer = [NSTimer timerWithTimeInterval: delay timer = [[NSTimer allocWithZone: NSDefaultMallocZone()]
target: self initWithTimeInterval: delay
selector: @selector(fire) targetOrInvocation: self
userInfo: nil selector: @selector(fire)
repeats: NO]; userInfo: nil
repeats: NO];
} }
return self; return self;
} }
@ -830,20 +834,23 @@ const NSMapTableValueCallBacks ArrayMapValueCallBacks =
/* This is the designated initializer. */ /* This is the designated initializer. */
- (id) init - (id) init
{ {
[super init]; self = [super init];
_mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks, if (self != nil)
ArrayMapValueCallBacks, 0); {
_mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks, _mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
ArrayMapValueCallBacks, 0); ArrayMapValueCallBacks, 0);
_mode_2_performers = NSCreateMapTable (NSObjectMapKeyCallBacks, _mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks,
ArrayMapValueCallBacks, 0); ArrayMapValueCallBacks, 0);
_timedPerformers = [[NSMutableArray alloc] initWithCapacity: 8]; _mode_2_performers = NSCreateMapTable (NSObjectMapKeyCallBacks,
_efdMap = NSCreateMapTable (NSIntMapKeyCallBacks, ArrayMapValueCallBacks, 0);
WatcherMapValueCallBacks, 0); _timedPerformers = [[NSMutableArray alloc] initWithCapacity: 8];
_rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks, _efdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0); WatcherMapValueCallBacks, 0);
_wfdMap = NSCreateMapTable (NSIntMapKeyCallBacks, _rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0); WatcherMapValueCallBacks, 0);
_wfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0);
}
return self; return self;
} }
@ -894,9 +901,10 @@ const NSMapTableValueCallBacks ArrayMapValueCallBacks =
} }
/* Fire appropriate timers and determine the earliest time that anything /**
watched for becomes useless. */ * Fire appropriate timers and determine the earliest time that anything
* watched for becomes useless.
*/
- (NSDate*) limitDateForMode: (NSString*)mode - (NSDate*) limitDateForMode: (NSString*)mode
{ {
id saved_mode; id saved_mode;
@ -910,116 +918,125 @@ const NSMapTableValueCallBacks ArrayMapValueCallBacks =
saved_mode = _current_mode; saved_mode = _current_mode;
_current_mode = mode; _current_mode = mode;
timers = NSMapGet(_mode_2_timers, mode); NS_DURING
if (timers)
{ {
while (GSIArrayCount(timers) != 0) timers = NSMapGet(_mode_2_timers, mode);
if (timers)
{ {
min_timer = GSIArrayItemAtIndex(timers, 0).obj; while (GSIArrayCount(timers) != 0)
if (timerInvalidated(min_timer) == YES)
{ {
GSIArrayRemoveItemAtIndex(timers, 0); min_timer = GSIArrayItemAtIndex(timers, 0).obj;
min_timer = nil; if (timerInvalidated(min_timer) == YES)
continue;
}
if ([timerDate(min_timer) timeIntervalSinceNow] > 0)
{
break;
}
GSIArrayRemoveItemAtIndexNoRelease(timers, 0);
/* Firing will also increment its fireDate, if it is repeating. */
[min_timer fire];
if (timerInvalidated(min_timer) == NO)
{
GSIArrayInsertSortedNoRetain(timers,
(GSIArrayItem)min_timer, aSort);
}
else
{
RELEASE(min_timer);
}
min_timer = nil;
GSNotifyASAP(); /* Post notifications. */
}
}
/* Is this right? At the moment we invalidate and discard watchers
whose limit-dates have passed. */
watchers = NSMapGet(_mode_2_watchers, mode);
if (watchers)
{
while (GSIArrayCount(watchers) != 0)
{
min_watcher = GSIArrayItemAtIndex(watchers, 0).obj;
if (min_watcher->_invalidated == YES)
{
GSIArrayRemoveItemAtIndex(watchers, 0);
min_watcher = nil;
continue;
}
if ([min_watcher->_date timeIntervalSinceNow] > 0)
{
break;
}
else
{
id obj;
NSDate *nxt = nil;
/*
* If the receiver or its delegate wants to know about
* timeouts - inform it and give it a chance to set a
* revised limit date.
*/
GSIArrayRemoveItemAtIndexNoRelease(watchers, 0);
obj = min_watcher->receiver;
if ([obj respondsToSelector:
@selector(timedOutEvent:type:forMode:)])
{ {
nxt = [obj timedOutEvent: min_watcher->data GSIArrayRemoveItemAtIndex(timers, 0);
type: min_watcher->type min_timer = nil;
forMode: _current_mode]; continue;
} }
else if ([obj respondsToSelector: @selector(delegate)])
if ([timerDate(min_timer) timeIntervalSinceNow] > 0)
{ {
obj = [obj delegate]; break;
if (obj != nil && [obj respondsToSelector: }
@selector(timedOutEvent:type:forMode:)])
GSIArrayRemoveItemAtIndexNoRelease(timers, 0);
/* Firing will also increment its fireDate, if it is repeating. */
[min_timer fire];
if (timerInvalidated(min_timer) == NO)
{
GSIArrayInsertSortedNoRetain(timers,
(GSIArrayItem)min_timer, aSort);
}
else
{
RELEASE(min_timer);
}
min_timer = nil;
GSNotifyASAP(); /* Post notifications. */
}
}
/* Is this right? At the moment we invalidate and discard watchers
whose limit-dates have passed. */
watchers = NSMapGet(_mode_2_watchers, mode);
if (watchers)
{
while (GSIArrayCount(watchers) != 0)
{
min_watcher = GSIArrayItemAtIndex(watchers, 0).obj;
if (min_watcher->_invalidated == YES)
{
GSIArrayRemoveItemAtIndex(watchers, 0);
min_watcher = nil;
continue;
}
if ([min_watcher->_date timeIntervalSinceNow] > 0)
{
break;
}
else
{
id obj;
NSDate *nxt = nil;
/*
* If the receiver or its delegate wants to know about
* timeouts - inform it and give it a chance to set a
* revised limit date.
*/
GSIArrayRemoveItemAtIndexNoRelease(watchers, 0);
obj = min_watcher->receiver;
if ([obj respondsToSelector:
@selector(timedOutEvent:type:forMode:)])
{ {
nxt = [obj timedOutEvent: min_watcher->data nxt = [obj timedOutEvent: min_watcher->data
type: min_watcher->type type: min_watcher->type
forMode: _current_mode]; forMode: _current_mode];
} }
else if ([obj respondsToSelector: @selector(delegate)])
{
obj = [obj delegate];
if (obj != nil && [obj respondsToSelector:
@selector(timedOutEvent:type:forMode:)])
{
nxt = [obj timedOutEvent: min_watcher->data
type: min_watcher->type
forMode: _current_mode];
}
}
if (nxt && [nxt timeIntervalSinceNow] > 0.0)
{
/*
* If the watcher has been given a revised limit date -
* re-insert it into the queue in the correct place.
*/
ASSIGN(min_watcher->_date, nxt);
GSIArrayInsertSortedNoRetain(watchers,
(GSIArrayItem)min_watcher, aSort);
}
else
{
/*
* If the watcher is now useless - invalidate and
* release it.
*/
min_watcher->_invalidated = YES;
RELEASE(min_watcher);
}
min_watcher = nil;
} }
if (nxt && [nxt timeIntervalSinceNow] > 0.0)
{
/*
* If the watcher has been given a revised limit date -
* re-insert it into the queue in the correct place.
*/
ASSIGN(min_watcher->_date, nxt);
GSIArrayInsertSortedNoRetain(watchers,
(GSIArrayItem)min_watcher, aSort);
}
else
{
/*
* If the watcher is now useless - invalidate and
* release it.
*/
min_watcher->_invalidated = YES;
RELEASE(min_watcher);
}
min_watcher = nil;
} }
} }
_current_mode = saved_mode;
} }
NS_HANDLER
{
_current_mode = saved_mode;
[localException raise];
}
NS_ENDHANDLER
_current_mode = saved_mode;
RELEASE(arp); RELEASE(arp);
/* /*
@ -1087,309 +1104,329 @@ const NSMapTableValueCallBacks ArrayMapValueCallBacks =
} }
_current_mode = mode; _current_mode = mode;
/* Find out how much time we should wait, and set SELECT_TIMEOUT. */ NS_DURING
if (!limit_date)
{ {
/* Don't wait at all. */ /* Find out how much time we should wait, and set SELECT_TIMEOUT. */
timeout.tv_sec = 0; if (!limit_date)
timeout.tv_usec = 0;
select_timeout = &timeout;
}
else if ((ti = [limit_date timeIntervalSinceNow])
< LONG_MAX && ti > 0.0)
{
/* Wait until the LIMIT_DATE. */
if (debug_run_loop)
printf ("\tNSRunLoop accept input before %f (seconds from now %f)\n",
[limit_date timeIntervalSinceReferenceDate], ti);
/* If LIMIT_DATE has already past, return immediately. */
timeout.tv_sec = ti;
timeout.tv_usec = (ti - timeout.tv_sec) * 1000000.0;
select_timeout = &timeout;
}
else if (ti <= 0.0)
{
/* The LIMIT_DATE has already past; return immediately without
polling any inputs. */
GSCheckTasks();
[self _checkPerformers];
GSNotifyASAP();
if (debug_run_loop)
printf ("\tNSRunLoop limit date past, returning\n");
_current_mode = saved_mode;
RELEASE(arp);
return;
}
else
{
/* Wait forever. */
if (debug_run_loop)
printf ("\tNSRunLoop accept input waiting forever\n");
select_timeout = NULL;
}
/*
* Get ready to listen to file descriptors.
* Initialize the set of FDS we'll pass to select(), and make sure we
* have empty maps for keeping track of which watcher is associated
* with which file descriptor.
* The maps may not have been emptied if a previous call to this
* method was terminated by an exception.
*/
memset(&exception_fds, '\0', sizeof(exception_fds));
memset(&read_fds, '\0', sizeof(read_fds));
memset(&write_fds, '\0', sizeof(write_fds));
NSResetMapTable(_efdMap);
NSResetMapTable(_rfdMap);
NSResetMapTable(_wfdMap);
/*
* Do the pre-listening set-up for the file descriptors of this mode.
*/
{
GSIArray watchers;
watchers = NSMapGet(_mode_2_watchers, mode);
if (watchers)
{
unsigned i = GSIArrayCount(watchers);
while (i-- > 0)
{
GSRunLoopWatcher *info;
int fd;
info = GSIArrayItemAtIndex(watchers, i).obj;
if (info->_invalidated == YES)
{
GSIArrayRemoveItemAtIndex(watchers, i);
continue;
}
switch (info->type)
{
case ET_EDESC:
fd = (int)info->data;
if (fd > end_inputs)
end_inputs = fd;
FD_SET (fd, &exception_fds);
NSMapInsert(_efdMap, (void*)fd, info);
num_inputs++;
break;
case ET_RDESC:
fd = (int)info->data;
if (fd > end_inputs)
end_inputs = fd;
FD_SET (fd, &read_fds);
NSMapInsert(_rfdMap, (void*)fd, info);
num_inputs++;
break;
case ET_WDESC:
fd = (int)info->data;
if (fd > end_inputs)
end_inputs = fd;
FD_SET (fd, &write_fds);
NSMapInsert(_wfdMap, (void*)fd, info);
num_inputs++;
break;
case ET_RPORT:
if ([info->receiver isValid] == NO)
{
/*
* We must remove an invalidated port.
*/
info->_invalidated = YES;
GSIArrayRemoveItemAtIndex(watchers, i);
}
else
{
id port = info->receiver;
int port_fd_count = 128; // xxx #define this constant
int port_fd_array[port_fd_count];
if ([port respondsToSelector: @selector(getFds:count:)])
[port getFds: port_fd_array count: &port_fd_count];
if (debug_run_loop)
printf("\tNSRunLoop listening to %d sockets\n",
port_fd_count);
while (port_fd_count--)
{
fd = port_fd_array[port_fd_count];
FD_SET (port_fd_array[port_fd_count], &read_fds);
if (fd > end_inputs)
end_inputs = fd;
NSMapInsert(_rfdMap,
(void*)port_fd_array[port_fd_count], info);
num_inputs++;
}
}
break;
}
}
}
}
end_inputs++;
/*
* If there are notifications in the 'idle' queue, we try an instantaneous
* select so that, if there is no input pending, we can service the queue.
* Similarly, if a task has completed, we need to deliver it's notifications.
*/
if (GSCheckTasks() || GSNotifyMore())
{
timeout.tv_sec = 0;
timeout.tv_usec = 0;
select_timeout = &timeout;
select_return = select (end_inputs, &read_fds, &write_fds, &exception_fds,
select_timeout);
}
else
select_return = select (end_inputs, &read_fds, &write_fds, &exception_fds,
select_timeout);
if (debug_run_loop)
printf ("\tNSRunLoop select returned %d\n", select_return);
if (select_return < 0)
{
if (errno == EINTR)
{ {
GSCheckTasks(); /* Don't wait at all. */
select_return = 0; timeout.tv_sec = 0;
timeout.tv_usec = 0;
select_timeout = &timeout;
}
else if ((ti = [limit_date timeIntervalSinceNow])
< LONG_MAX && ti > 0.0)
{
/* Wait until the LIMIT_DATE. */
if (debug_run_loop)
printf ("\tNSRunLoop accept input before %f (sec from now %f)\n",
[limit_date timeIntervalSinceReferenceDate], ti);
/* If LIMIT_DATE has already past, return immediately. */
timeout.tv_sec = ti;
timeout.tv_usec = (ti - timeout.tv_sec) * 1000000.0;
select_timeout = &timeout;
}
else if (ti <= 0.0)
{
/* The LIMIT_DATE has already past; return immediately without
polling any inputs. */
GSCheckTasks();
[self _checkPerformers];
GSNotifyASAP();
if (debug_run_loop)
printf ("\tNSRunLoop limit date past, returning\n");
_current_mode = saved_mode;
RELEASE(arp);
return;
} }
#ifdef __MINGW__
else if (errno == 0)
{
/* MinGW often returns an errno == 0. Not sure why */
select_return = 0;
}
#endif
else else
{ {
/* Some exceptional condition happened. */ /* Wait forever. */
/* xxx We can do something with exception_fds, instead of if (debug_run_loop)
aborting here. */ printf ("\tNSRunLoop accept input waiting forever\n");
NSLog (@"select() error in -acceptInputForMode:beforeDate: '%s'", select_timeout = NULL;
GSLastErrorStr(errno));
abort ();
} }
}
if (select_return == 0) /*
{ * Get ready to listen to file descriptors.
* Initialize the set of FDS we'll pass to select(), and make sure we
* have empty maps for keeping track of which watcher is associated
* with which file descriptor.
* The maps may not have been emptied if a previous call to this
* method was terminated by an exception.
*/
memset(&exception_fds, '\0', sizeof(exception_fds));
memset(&read_fds, '\0', sizeof(read_fds));
memset(&write_fds, '\0', sizeof(write_fds));
NSResetMapTable(_efdMap); NSResetMapTable(_efdMap);
NSResetMapTable(_rfdMap); NSResetMapTable(_rfdMap);
NSResetMapTable(_wfdMap); NSResetMapTable(_wfdMap);
GSNotifyIdle();
[self _checkPerformers];
_current_mode = saved_mode;
RELEASE(arp);
return;
}
/*
* Look at all the file descriptors select() says are ready for action;
* notify the corresponding object for each of the ready fd's.
* NB. It is possible for a watcher to be missing from the map - if
* the event handler of a previous watcher has 'run' the loop again
* before returning.
* NB. Each time this roop is entered, the starting position (_fdStart)
* is incremented - this is to ensure a fair distribtion over all
* inputs where multiple inputs are in use. Note - _fdStart can be
* modified while we are in the loop (by recursive calls).
*/
if (_fdStart >= end_inputs)
{
_fdStart = 0;
fdIndex = 0;
fdEnd = 0;
}
else
{
_fdStart++;
fdIndex = _fdStart;
fdEnd = _fdStart;
}
do
{
BOOL found = NO;
if (FD_ISSET (fdIndex, &exception_fds)) /*
{ * Do the pre-listening set-up for the file descriptors of this mode.
GSRunLoopWatcher *watcher; */
{
GSIArray watchers;
watcher = (GSRunLoopWatcher*)NSMapGet(_efdMap, (void*)fdIndex); watchers = NSMapGet(_mode_2_watchers, mode);
if (watcher != nil && watcher->_invalidated == NO) if (watchers)
{
unsigned i = GSIArrayCount(watchers);
while (i-- > 0)
{
GSRunLoopWatcher *info;
int fd;
info = GSIArrayItemAtIndex(watchers, i).obj;
if (info->_invalidated == YES)
{
GSIArrayRemoveItemAtIndex(watchers, i);
continue;
}
switch (info->type)
{
case ET_EDESC:
fd = (int)info->data;
if (fd > end_inputs)
end_inputs = fd;
FD_SET (fd, &exception_fds);
NSMapInsert(_efdMap, (void*)fd, info);
num_inputs++;
break;
case ET_RDESC:
fd = (int)info->data;
if (fd > end_inputs)
end_inputs = fd;
FD_SET (fd, &read_fds);
NSMapInsert(_rfdMap, (void*)fd, info);
num_inputs++;
break;
case ET_WDESC:
fd = (int)info->data;
if (fd > end_inputs)
end_inputs = fd;
FD_SET (fd, &write_fds);
NSMapInsert(_wfdMap, (void*)fd, info);
num_inputs++;
break;
case ET_RPORT:
if ([info->receiver isValid] == NO)
{
/*
* We must remove an invalidated port.
*/
info->_invalidated = YES;
GSIArrayRemoveItemAtIndex(watchers, i);
}
else
{
id port = info->receiver;
int port_fd_count = 128; // xxx #define this constant
int port_fd_array[port_fd_count];
if ([port respondsToSelector:
@selector(getFds:count:)])
{
[port getFds: port_fd_array
count: &port_fd_count];
}
if (debug_run_loop)
{
printf("\tNSRunLoop listening to %d sockets\n",
port_fd_count);
}
while (port_fd_count--)
{
fd = port_fd_array[port_fd_count];
FD_SET (port_fd_array[port_fd_count], &read_fds);
if (fd > end_inputs)
{
end_inputs = fd;
}
NSMapInsert(_rfdMap,
(void*)port_fd_array[port_fd_count], info);
num_inputs++;
}
}
break;
}
}
}
}
end_inputs++;
/*
* If there are notifications in the 'idle' queue, we try an
* instantaneous select so that, if there is no input pending,
* we can service the queue. Similarly, if a task has completed,
* we need to deliver it's notifications.
*/
if (GSCheckTasks() || GSNotifyMore())
{
timeout.tv_sec = 0;
timeout.tv_usec = 0;
select_timeout = &timeout;
select_return = select (end_inputs, &read_fds, &write_fds,
&exception_fds, select_timeout);
}
else
{
select_return = select (end_inputs, &read_fds, &write_fds,
&exception_fds, select_timeout);
}
if (debug_run_loop)
{
printf ("\tNSRunLoop select returned %d\n", select_return);
}
if (select_return < 0)
{
if (errno == EINTR)
{ {
/* GSCheckTasks();
* The watcher is still valid - so call it's receivers select_return = 0;
* event handling method.
*/
(*watcher->handleEvent)(watcher->receiver,
eventSel, watcher->data, watcher->type,
(void*)(gsaddr)fdIndex, _current_mode);
} }
GSNotifyASAP(); #ifdef __MINGW__
found = YES; else if (errno == 0)
}
if (FD_ISSET (fdIndex, &write_fds))
{
GSRunLoopWatcher *watcher;
watcher = NSMapGet(_wfdMap, (void*)fdIndex);
if (watcher != nil && watcher->_invalidated == NO)
{ {
/* /* MinGW often returns an errno == 0. Not sure why */
* The watcher is still valid - so call it's receivers select_return = 0;
* event handling method.
*/
(*watcher->handleEvent)(watcher->receiver,
eventSel, watcher->data, watcher->type,
(void*)(gsaddr)fdIndex, _current_mode);
} }
GSNotifyASAP(); #endif
found = YES; else
}
if (FD_ISSET (fdIndex, &read_fds))
{
GSRunLoopWatcher *watcher;
watcher = (GSRunLoopWatcher*)NSMapGet(_rfdMap, (void*)fdIndex);
if (watcher != nil && watcher->_invalidated == NO)
{ {
/* /* Some exceptional condition happened. */
* The watcher is still valid - so call it's receivers /* xxx We can do something with exception_fds, instead of
* event handling method. aborting here. */
*/ NSLog (@"select() error in -acceptInputForMode:beforeDate: '%s'",
(*watcher->handleEvent)(watcher->receiver, GSLastErrorStr(errno));
abort ();
}
}
if (select_return == 0)
{
NSResetMapTable(_efdMap);
NSResetMapTable(_rfdMap);
NSResetMapTable(_wfdMap);
GSNotifyIdle();
[self _checkPerformers];
_current_mode = saved_mode;
RELEASE(arp);
return;
}
/*
* Look at all the file descriptors select() says are ready for action;
* notify the corresponding object for each of the ready fd's.
* NB. It is possible for a watcher to be missing from the map - if
* the event handler of a previous watcher has 'run' the loop again
* before returning.
* NB. Each time this roop is entered, the starting position (_fdStart)
* is incremented - this is to ensure a fair distribtion over all
* inputs where multiple inputs are in use. Note - _fdStart can be
* modified while we are in the loop (by recursive calls).
*/
if (_fdStart >= end_inputs)
{
_fdStart = 0;
fdIndex = 0;
fdEnd = 0;
}
else
{
_fdStart++;
fdIndex = _fdStart;
fdEnd = _fdStart;
}
do
{
BOOL found = NO;
if (FD_ISSET (fdIndex, &exception_fds))
{
GSRunLoopWatcher *watcher;
watcher = (GSRunLoopWatcher*)NSMapGet(_efdMap, (void*)fdIndex);
if (watcher != nil && watcher->_invalidated == NO)
{
/*
* The watcher is still valid - so call it's receivers
* event handling method.
*/
(*watcher->handleEvent)(watcher->receiver,
eventSel, watcher->data, watcher->type, eventSel, watcher->data, watcher->type,
(void*)(gsaddr)fdIndex, _current_mode); (void*)(gsaddr)fdIndex, _current_mode);
}
GSNotifyASAP();
found = YES;
}
if (FD_ISSET (fdIndex, &write_fds))
{
GSRunLoopWatcher *watcher;
watcher = NSMapGet(_wfdMap, (void*)fdIndex);
if (watcher != nil && watcher->_invalidated == NO)
{
/*
* The watcher is still valid - so call it's receivers
* event handling method.
*/
(*watcher->handleEvent)(watcher->receiver,
eventSel, watcher->data, watcher->type,
(void*)(gsaddr)fdIndex, _current_mode);
}
GSNotifyASAP();
found = YES;
}
if (FD_ISSET (fdIndex, &read_fds))
{
GSRunLoopWatcher *watcher;
watcher = (GSRunLoopWatcher*)NSMapGet(_rfdMap, (void*)fdIndex);
if (watcher != nil && watcher->_invalidated == NO)
{
/*
* The watcher is still valid - so call it's receivers
* event handling method.
*/
(*watcher->handleEvent)(watcher->receiver,
eventSel, watcher->data, watcher->type,
(void*)(gsaddr)fdIndex, _current_mode);
}
GSNotifyASAP();
found = YES;
}
if (found == YES && --select_return == 0)
{
break;
}
if (++fdIndex >= end_inputs)
{
fdIndex = 0;
} }
GSNotifyASAP();
found = YES;
}
if (found == YES && --select_return == 0)
{
break;
}
if (++fdIndex >= end_inputs)
{
fdIndex = 0;
} }
while (fdIndex != fdEnd);
/* Clean up before returning. */
NSResetMapTable(_efdMap);
NSResetMapTable(_rfdMap);
NSResetMapTable(_wfdMap);
[self _checkPerformers];
GSNotifyASAP();
_current_mode = saved_mode;
} }
while (fdIndex != fdEnd); NS_HANDLER
{
_current_mode = saved_mode;
/* Clean up before returning. */ [localException raise];
NSResetMapTable(_efdMap); }
NSResetMapTable(_rfdMap); NS_ENDHANDLER
NSResetMapTable(_wfdMap);
[self _checkPerformers];
GSNotifyASAP();
_current_mode = saved_mode;
RELEASE(arp); RELEASE(arp);
} }

View file

@ -46,7 +46,10 @@ static Class NSDate_class;
} }
} }
/* This is the designated initializer. */ /*
* <init />
* Initialise a newly allocated NSTimer object.
*/
- (id) initWithTimeInterval: (NSTimeInterval)seconds - (id) initWithTimeInterval: (NSTimeInterval)seconds
targetOrInvocation: (id)t targetOrInvocation: (id)t
selector: (SEL)sel selector: (SEL)sel