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>
Fixed dynamical loading of frameworks.

View file

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

View file

@ -244,8 +244,8 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
@end
/*
* The GSTimedPerformer class is used to hold information about
* messages which are due to be sent to objects at a particular time.
* The GSTimedPerformer class is used to hold information about
* messages which are due to be sent to objects at a particular time.
*/
@interface GSTimedPerformer: NSObject <GCFinalization>
{
@ -268,6 +268,7 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
- (void) dealloc
{
[self gcFinalize];
TEST_RELEASE(timer);
RELEASE(target);
RELEASE(argument);
[super dealloc];
@ -275,7 +276,7 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
- (void) fire
{
timer = nil;
DESTROY(timer);
[target performSelector: selector withObject: argument];
[[[NSRunLoop currentRunLoop] _timedPerformers]
removeObjectIdenticalTo: self];
@ -284,7 +285,9 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
- (void) gcFinalize
{
if (timer != nil)
[timer invalidate];
{
[timer invalidate];
}
}
- (id) initWithSelector: (SEL)aSelector
@ -293,16 +296,17 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
delay: (NSTimeInterval)delay
{
self = [super init];
if (self)
if (self != nil)
{
selector = aSelector;
target = RETAIN(aTarget);
argument = RETAIN(anArgument);
timer = [NSTimer timerWithTimeInterval: delay
target: self
selector: @selector(fire)
userInfo: nil
repeats: NO];
timer = [[NSTimer allocWithZone: NSDefaultMallocZone()]
initWithTimeInterval: delay
targetOrInvocation: self
selector: @selector(fire)
userInfo: nil
repeats: NO];
}
return self;
}
@ -830,20 +834,23 @@ const NSMapTableValueCallBacks ArrayMapValueCallBacks =
/* This is the designated initializer. */
- (id) init
{
[super init];
_mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
ArrayMapValueCallBacks, 0);
_mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks,
ArrayMapValueCallBacks, 0);
_mode_2_performers = NSCreateMapTable (NSObjectMapKeyCallBacks,
ArrayMapValueCallBacks, 0);
_timedPerformers = [[NSMutableArray alloc] initWithCapacity: 8];
_efdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0);
_rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0);
_wfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0);
self = [super init];
if (self != nil)
{
_mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
ArrayMapValueCallBacks, 0);
_mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks,
ArrayMapValueCallBacks, 0);
_mode_2_performers = NSCreateMapTable (NSObjectMapKeyCallBacks,
ArrayMapValueCallBacks, 0);
_timedPerformers = [[NSMutableArray alloc] initWithCapacity: 8];
_efdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0);
_rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0);
_wfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
WatcherMapValueCallBacks, 0);
}
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
{
id saved_mode;
@ -910,116 +918,125 @@ const NSMapTableValueCallBacks ArrayMapValueCallBacks =
saved_mode = _current_mode;
_current_mode = mode;
timers = NSMapGet(_mode_2_timers, mode);
if (timers)
NS_DURING
{
while (GSIArrayCount(timers) != 0)
timers = NSMapGet(_mode_2_timers, mode);
if (timers)
{
min_timer = GSIArrayItemAtIndex(timers, 0).obj;
if (timerInvalidated(min_timer) == YES)
while (GSIArrayCount(timers) != 0)
{
GSIArrayRemoveItemAtIndex(timers, 0);
min_timer = nil;
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:)])
min_timer = GSIArrayItemAtIndex(timers, 0).obj;
if (timerInvalidated(min_timer) == YES)
{
nxt = [obj timedOutEvent: min_watcher->data
type: min_watcher->type
forMode: _current_mode];
GSIArrayRemoveItemAtIndex(timers, 0);
min_timer = nil;
continue;
}
else if ([obj respondsToSelector: @selector(delegate)])
if ([timerDate(min_timer) timeIntervalSinceNow] > 0)
{
obj = [obj delegate];
if (obj != nil && [obj respondsToSelector:
@selector(timedOutEvent:type:forMode:)])
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
type: min_watcher->type
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);
/*
@ -1087,309 +1104,329 @@ const NSMapTableValueCallBacks ArrayMapValueCallBacks =
}
_current_mode = mode;
/* Find out how much time we should wait, and set SELECT_TIMEOUT. */
if (!limit_date)
NS_DURING
{
/* Don't wait at all. */
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 (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)
/* Find out how much time we should wait, and set SELECT_TIMEOUT. */
if (!limit_date)
{
GSCheckTasks();
select_return = 0;
/* Don't wait at all. */
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
{
/* Some exceptional condition happened. */
/* xxx We can do something with exception_fds, instead of
aborting here. */
NSLog (@"select() error in -acceptInputForMode:beforeDate: '%s'",
GSLastErrorStr(errno));
abort ();
/* Wait forever. */
if (debug_run_loop)
printf ("\tNSRunLoop accept input waiting forever\n");
select_timeout = NULL;
}
}
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(_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;
/*
* Do the pre-listening set-up for the file descriptors of this mode.
*/
{
GSIArray watchers;
watcher = (GSRunLoopWatcher*)NSMapGet(_efdMap, (void*)fdIndex);
if (watcher != nil && watcher->_invalidated == NO)
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)
{
/*
* 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);
GSCheckTasks();
select_return = 0;
}
GSNotifyASAP();
found = YES;
}
if (FD_ISSET (fdIndex, &write_fds))
{
GSRunLoopWatcher *watcher;
watcher = NSMapGet(_wfdMap, (void*)fdIndex);
if (watcher != nil && watcher->_invalidated == NO)
#ifdef __MINGW__
else if (errno == 0)
{
/*
* 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);
/* MinGW often returns an errno == 0. Not sure why */
select_return = 0;
}
GSNotifyASAP();
found = YES;
}
if (FD_ISSET (fdIndex, &read_fds))
{
GSRunLoopWatcher *watcher;
watcher = (GSRunLoopWatcher*)NSMapGet(_rfdMap, (void*)fdIndex);
if (watcher != nil && watcher->_invalidated == NO)
#endif
else
{
/*
* The watcher is still valid - so call it's receivers
* event handling method.
*/
(*watcher->handleEvent)(watcher->receiver,
/* Some exceptional condition happened. */
/* xxx We can do something with exception_fds, instead of
aborting here. */
NSLog (@"select() error in -acceptInputForMode:beforeDate: '%s'",
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,
(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);
/* Clean up before returning. */
NSResetMapTable(_efdMap);
NSResetMapTable(_rfdMap);
NSResetMapTable(_wfdMap);
[self _checkPerformers];
GSNotifyASAP();
_current_mode = saved_mode;
NS_HANDLER
{
_current_mode = saved_mode;
[localException raise];
}
NS_ENDHANDLER
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
targetOrInvocation: (id)t
selector: (SEL)sel