1999-04-21 20:16:25 +00:00
|
|
|
|
/* Implementation of object for waiting on several input seurces
|
1999-04-20 16:28:04 +00:00
|
|
|
|
Copyright (C) 1996-1999 Free Software Foundation, Inc.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
Original by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
|
|
|
|
Created: March 1996
|
|
|
|
|
OPENSTEP version by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
Created: August 1997
|
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1996-04-10 18:20:36 +00:00
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1996-04-10 18:20:36 +00:00
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
|
#include <config.h>
|
1998-12-20 21:27:47 +00:00
|
|
|
|
#include <base/preface.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <Foundation/NSMapTable.h>
|
|
|
|
|
#include <Foundation/NSDate.h>
|
|
|
|
|
#include <Foundation/NSValue.h>
|
|
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
|
|
|
|
#include <Foundation/NSPort.h>
|
|
|
|
|
#include <Foundation/NSTimer.h>
|
|
|
|
|
#include <Foundation/NSNotificationQueue.h>
|
1996-04-10 18:20:36 +00:00
|
|
|
|
#include <Foundation/NSRunLoop.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <Foundation/NSThread.h>
|
1998-11-06 19:46:23 +00:00
|
|
|
|
#include <Foundation/NSDebug.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
1999-06-02 04:20:52 +00:00
|
|
|
|
#if !defined(__WIN32__) || defined(__CYGWIN__)
|
1998-07-21 17:56:48 +00:00
|
|
|
|
#include <time.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#endif /* !__WIN32__ */
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <string.h> /* for memset() */
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
static int debug_run_loop = 0;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
static NSDate *theFuture = nil;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The 'RunLoopWatcher' class was written to permit the (relatively)
|
|
|
|
|
* easy addition of new events to be watched for in the runloop.
|
|
|
|
|
*
|
|
|
|
|
* To add a new type of event, the 'RunLoopEventType' enumeration must be
|
|
|
|
|
* extended, and the methods must be modified to handle the new type.
|
|
|
|
|
*
|
|
|
|
|
* The internal variables if the RunLoopWatcher are used as follows -
|
1999-04-20 16:28:04 +00:00
|
|
|
|
*
|
|
|
|
|
* The '_date' variable contains a date after which the event is useless
|
|
|
|
|
* and the watcher can be removed from the runloop.
|
|
|
|
|
*
|
|
|
|
|
* If '_invalidated' is set, the watcher should be disabled and should
|
1997-09-01 21:59:51 +00:00
|
|
|
|
* be removed from the runloop when next encountered.
|
|
|
|
|
*
|
|
|
|
|
* The 'data' variable is used to identify the resource/event that the
|
|
|
|
|
* watcher is interested in.
|
|
|
|
|
*
|
|
|
|
|
* The 'receiver' is the object which should be told when the event
|
|
|
|
|
* occurs. This object is retained so that we know it will continue
|
|
|
|
|
* to exist and can handle a callback.
|
|
|
|
|
*
|
|
|
|
|
* The 'type' variable indentifies the type of event watched for.
|
1999-04-19 14:29:52 +00:00
|
|
|
|
* NSRunLoops [-acceptInputForMode: beforeDate: ] method MUST contain
|
1997-09-01 21:59:51 +00:00
|
|
|
|
* code to watch for events of each type.
|
|
|
|
|
*
|
|
|
|
|
* To set this variable, the method adding the RunLoopWatcher to the
|
|
|
|
|
* runloop must ask the 'receiver' (or its delegate) to supply a date
|
1999-04-19 14:29:52 +00:00
|
|
|
|
* using the '[-limitDateForMode: ]' message.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
*
|
1998-11-12 08:41:44 +00:00
|
|
|
|
* NB. This class is private to NSRunLoop and must not be subclassed.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
static SEL eventSel = @selector(receivedEvent:type:extra:forMode:);
|
|
|
|
|
|
|
|
|
|
@interface RunLoopWatcher: NSObject
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-11-12 08:41:44 +00:00
|
|
|
|
@public
|
1999-04-22 11:24:57 +00:00
|
|
|
|
NSDate *_date; /* First to match layout of NSTimer */
|
1999-04-20 16:28:04 +00:00
|
|
|
|
BOOL _invalidated; /* 2nd to match layout of NSTimer */
|
|
|
|
|
IMP handleEvent; /* New-style event handling */
|
1998-10-29 08:46:30 +00:00
|
|
|
|
void *data;
|
|
|
|
|
id receiver;
|
|
|
|
|
RunLoopEventType type;
|
|
|
|
|
unsigned count;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
- initWithType: (RunLoopEventType)type
|
|
|
|
|
receiver: (id)anObj
|
|
|
|
|
data: (void*)data;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation RunLoopWatcher
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1999-04-22 11:24:57 +00:00
|
|
|
|
RELEASE(_date);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[super dealloc];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-03-02 08:58:30 +00:00
|
|
|
|
- (id) initWithType: (RunLoopEventType)aType
|
|
|
|
|
receiver: (id)anObj
|
|
|
|
|
data: (void*)item
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
_invalidated = NO;
|
1999-03-02 08:58:30 +00:00
|
|
|
|
|
1998-11-12 08:41:44 +00:00
|
|
|
|
switch (aType)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
case ET_RDESC: type = aType; break;
|
|
|
|
|
case ET_WDESC: type = aType; break;
|
|
|
|
|
case ET_RPORT: type = aType; break;
|
|
|
|
|
default:
|
1998-11-12 08:41:44 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"NSRunLoop - unknown event type"];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1999-05-20 09:29:02 +00:00
|
|
|
|
receiver = anObj;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if ([receiver respondsToSelector: eventSel] == YES)
|
|
|
|
|
handleEvent = [receiver methodForSelector: eventSel];
|
1999-03-02 08:58:30 +00:00
|
|
|
|
else
|
1999-04-20 16:28:04 +00:00
|
|
|
|
handleEvent = 0;
|
1998-11-12 08:41:44 +00:00
|
|
|
|
data = item;
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return self;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Two optimisation functions that depend on a hack that the layout of
|
|
|
|
|
* the NSTimer class is known to be the same as RunLoopWatcher for the
|
|
|
|
|
* first two elements.
|
|
|
|
|
*/
|
1999-04-22 11:24:57 +00:00
|
|
|
|
static inline NSDate* timerDate(NSTimer* timer)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
return ((RunLoopWatcher*)timer)->_date;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
static inline BOOL timerInvalidated(NSTimer* timer)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
return ((RunLoopWatcher*)timer)->_invalidated;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Setup for inline operation of arrays.
|
|
|
|
|
*/
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
#define GSI_ARRAY_TYPES GSUNION_OBJ
|
1999-04-20 16:28:04 +00:00
|
|
|
|
|
|
|
|
|
#if GS_WITH_GC == 0
|
1999-06-21 08:30:26 +00:00
|
|
|
|
#define GSI_ARRAY_RELEASE(X) [(X).obj release]
|
|
|
|
|
#define GSI_ARRAY_RETAIN(X) [(X).obj retain]
|
1999-04-20 16:28:04 +00:00
|
|
|
|
#else
|
1999-06-21 08:30:26 +00:00
|
|
|
|
#define GSI_ARRAY_RELEASE(X)
|
|
|
|
|
#define GSI_ARRAY_RETAIN(X) (X).obj
|
1999-04-20 16:28:04 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
#include <base/GSIArray.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
|
1999-04-28 23:02:15 +00:00
|
|
|
|
{
|
|
|
|
|
return [((RunLoopWatcher *)(i0.obj))->_date
|
|
|
|
|
compare: ((RunLoopWatcher *)(i1.obj))->_date];
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-04-02 14:27:40 +00:00
|
|
|
|
|
|
|
|
|
@interface NSRunLoop (TimedPerformers)
|
|
|
|
|
- (NSMutableArray*) _timedPerformers;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop (TimedPerformers)
|
|
|
|
|
- (NSMutableArray*) _timedPerformers
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return _timedPerformers;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* The RunLoopPerformer class is used to hold information about
|
|
|
|
|
* messages which are due to be sent to objects once a particular
|
|
|
|
|
* runloop iteration has passed.
|
|
|
|
|
*/
|
1999-03-02 08:58:30 +00:00
|
|
|
|
@interface RunLoopPerformer: NSObject <GCFinalization>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
SEL selector;
|
|
|
|
|
id target;
|
|
|
|
|
id argument;
|
|
|
|
|
unsigned order;
|
|
|
|
|
NSArray *modes;
|
|
|
|
|
NSTimer *timer;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) fire;
|
|
|
|
|
- initWithSelector: (SEL)aSelector
|
1998-10-29 08:46:30 +00:00
|
|
|
|
target: (id)target
|
|
|
|
|
argument: (id)argument
|
1997-09-01 21:59:51 +00:00
|
|
|
|
order: (unsigned int)order
|
|
|
|
|
modes: (NSArray*)modes;
|
|
|
|
|
- (BOOL) matchesSelector: (SEL)aSelector
|
1998-10-29 08:46:30 +00:00
|
|
|
|
target: (id)aTarget
|
|
|
|
|
argument: (id)anArgument;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (NSArray*) modes;
|
|
|
|
|
- (unsigned int) order;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
- (void) setTimer: (NSTimer*)timer;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation RunLoopPerformer
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1999-03-02 08:58:30 +00:00
|
|
|
|
[self gcFinalize];
|
|
|
|
|
RELEASE(target);
|
|
|
|
|
RELEASE(argument);
|
|
|
|
|
RELEASE(modes);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[super dealloc];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
- (void) fire
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (timer != nil)
|
|
|
|
|
{
|
|
|
|
|
timer = nil;
|
1999-03-02 08:58:30 +00:00
|
|
|
|
AUTORELEASE(RETAIN(self));
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[[[NSRunLoop currentInstance] _timedPerformers]
|
1998-04-02 14:27:40 +00:00
|
|
|
|
removeObjectIdenticalTo: self];
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[target performSelector: selector withObject: argument];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-03-02 08:58:30 +00:00
|
|
|
|
- (void) gcFinalize
|
|
|
|
|
{
|
|
|
|
|
[timer invalidate];
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- initWithSelector: (SEL)aSelector
|
1998-10-29 08:46:30 +00:00
|
|
|
|
target: (id)aTarget
|
|
|
|
|
argument: (id)anArgument
|
1997-09-01 21:59:51 +00:00
|
|
|
|
order: (unsigned int)theOrder
|
|
|
|
|
modes: (NSArray*)theModes
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
self = [super init];
|
|
|
|
|
if (self)
|
|
|
|
|
{
|
|
|
|
|
selector = aSelector;
|
1999-03-02 08:58:30 +00:00
|
|
|
|
target = RETAIN(aTarget);
|
|
|
|
|
argument = RETAIN(anArgument);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
order = theOrder;
|
|
|
|
|
modes = [theModes copy];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return self;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) matchesSelector: (SEL)aSelector
|
1998-10-29 08:46:30 +00:00
|
|
|
|
target: (id)aTarget
|
|
|
|
|
argument: (id)anArgument
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (selector == aSelector)
|
|
|
|
|
{
|
|
|
|
|
if (target == aTarget)
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
if ([argument isEqual: anArgument])
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) modes
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return modes;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned int) order
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return order;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-04-02 14:27:40 +00:00
|
|
|
|
- (void) setTimer: (NSTimer*)t
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
timer = t;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSObject (TimedPerformers)
|
|
|
|
|
|
|
|
|
|
+ (void) cancelPreviousPerformRequestsWithTarget: (id)target
|
|
|
|
|
selector: (SEL)aSelector
|
|
|
|
|
object: (id)arg
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSMutableArray *array;
|
|
|
|
|
int i;
|
|
|
|
|
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RETAIN(target);
|
|
|
|
|
RETAIN(arg);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
array = [[NSRunLoop currentInstance] _timedPerformers];
|
|
|
|
|
for (i = [array count]; i > 0; i--)
|
|
|
|
|
{
|
|
|
|
|
if ([[array objectAtIndex: i-1] matchesSelector: aSelector
|
|
|
|
|
target: target
|
|
|
|
|
argument: arg])
|
|
|
|
|
{
|
|
|
|
|
[array removeObjectAtIndex: i-1];
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RELEASE(arg);
|
|
|
|
|
RELEASE(target);
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) performSelector: (SEL)aSelector
|
|
|
|
|
withObject: (id)argument
|
|
|
|
|
afterDelay: (NSTimeInterval)seconds
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSMutableArray *array;
|
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
|
|
|
|
|
array = [[NSRunLoop currentInstance] _timedPerformers];
|
|
|
|
|
item = [[RunLoopPerformer alloc] initWithSelector: aSelector
|
|
|
|
|
target: self
|
|
|
|
|
argument: argument
|
|
|
|
|
order: 0
|
|
|
|
|
modes: nil];
|
|
|
|
|
[array addObject: item];
|
|
|
|
|
[item setTimer: [NSTimer scheduledTimerWithTimeInterval: seconds
|
|
|
|
|
target: item
|
|
|
|
|
selector: @selector(fire)
|
|
|
|
|
userInfo: nil
|
|
|
|
|
repeats: NO]];
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RELEASE(item);
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) performSelector: (SEL)aSelector
|
|
|
|
|
withObject: (id)argument
|
|
|
|
|
afterDelay: (NSTimeInterval)seconds
|
|
|
|
|
inModes: (NSArray*)modes
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSRunLoop *loop;
|
|
|
|
|
NSMutableArray *array;
|
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
NSTimer *timer;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (modes == nil || [modes count] == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
loop = [NSRunLoop currentInstance];
|
|
|
|
|
array = [loop _timedPerformers];
|
|
|
|
|
item = [[RunLoopPerformer alloc] initWithSelector: aSelector
|
|
|
|
|
target: self
|
|
|
|
|
argument: argument
|
|
|
|
|
order: 0
|
|
|
|
|
modes: nil];
|
|
|
|
|
[array addObject: item];
|
|
|
|
|
timer = [NSTimer timerWithTimeInterval: seconds
|
|
|
|
|
target: item
|
|
|
|
|
selector: @selector(fire)
|
|
|
|
|
userInfo: nil
|
|
|
|
|
repeats: NO];
|
|
|
|
|
[item setTimer: timer];
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RELEASE(item);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
for (i = 0; i < [modes count]; i++)
|
|
|
|
|
{
|
|
|
|
|
[loop addTimer: timer forMode: [modes objectAtIndex: i]];
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@interface NSRunLoop (Private)
|
|
|
|
|
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (void) _addWatcher: (RunLoopWatcher*)item
|
|
|
|
|
forMode: (NSString*)mode;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (void) _checkPerformers;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (RunLoopWatcher*) _getWatcher: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
- (NSMutableArray*) _performers;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (void) _removeWatcher: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop (Private)
|
|
|
|
|
|
|
|
|
|
/* Add a watcher to the list for the specified mode. Keep the list in
|
|
|
|
|
limit-date order. */
|
|
|
|
|
- (void) _addWatcher: (RunLoopWatcher*) item forMode: (NSString*)mode
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArray watchers;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
id obj;
|
1998-10-29 08:46:30 +00:00
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
watchers = NSMapGet(_mode_2_watchers, mode);
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if (watchers == 0)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
NSZone *z = [self zone];
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
watchers = NSZoneMalloc(z, sizeof(GSIArray_t));
|
|
|
|
|
GSIArrayInitWithZoneAndCapacity(watchers, z, 8);
|
1999-03-02 08:58:30 +00:00
|
|
|
|
NSMapInsert(_mode_2_watchers, mode, watchers);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* If the receiver or its delegate (if any) respond to
|
1999-04-19 14:29:52 +00:00
|
|
|
|
* 'limitDateForMode: ' then we ask them for the limit date for
|
1998-10-29 08:46:30 +00:00
|
|
|
|
* this watcher.
|
|
|
|
|
*/
|
1998-11-12 08:41:44 +00:00
|
|
|
|
obj = item->receiver;
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if ([obj respondsToSelector: @selector(limitDateForMode:)])
|
|
|
|
|
{
|
1998-11-12 08:41:44 +00:00
|
|
|
|
NSDate *d = [obj limitDateForMode: mode];
|
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
|
item->_date = RETAIN(d);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else if ([obj respondsToSelector: @selector(delegate)])
|
|
|
|
|
{
|
|
|
|
|
obj = [obj delegate];
|
1999-05-06 19:37:45 +00:00
|
|
|
|
if (obj != nil && [obj respondsToSelector: @selector(limitDateForMode:)])
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1998-11-12 08:41:44 +00:00
|
|
|
|
NSDate *d = [obj limitDateForMode: mode];
|
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
|
item->_date = RETAIN(d);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1999-04-20 16:28:04 +00:00
|
|
|
|
else
|
1999-04-22 11:24:57 +00:00
|
|
|
|
item->_date = RETAIN(theFuture);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
1999-04-22 11:24:57 +00:00
|
|
|
|
item->_date = RETAIN(theFuture);
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayInsertSorted(watchers, (GSIArrayItem)item, aSort);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _checkPerformers
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
NSArray *array = [NSArray arrayWithArray: _performers];
|
|
|
|
|
int count = [array count];
|
|
|
|
|
unsigned pos;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
item = (RunLoopPerformer*)[array objectAtIndex: i];
|
|
|
|
|
|
|
|
|
|
pos = [_performers indexOfObjectIdenticalTo: item];
|
|
|
|
|
if (pos != NSNotFound)
|
|
|
|
|
{
|
|
|
|
|
if ([[item modes] containsObject: _current_mode])
|
|
|
|
|
{
|
|
|
|
|
[_performers removeObjectAtIndex: pos];
|
|
|
|
|
[item fire];
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop(GNUstepExtensions)
|
|
|
|
|
|
|
|
|
|
+ currentInstance
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self currentRunLoop];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSString*) currentMode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [[NSRunLoop currentRunLoop] currentMode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) run
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[[NSRunLoop currentRunLoop] run];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) runUntilDate: date
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[[NSRunLoop currentRunLoop] runUntilDate: date];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) runUntilDate: date forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[[NSRunLoop currentRunLoop] runUntilDate: date forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) runOnceBeforeDate: date
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [[NSRunLoop currentRunLoop] runOnceBeforeDate: date];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) runOnceBeforeDate: date forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [[NSRunLoop currentRunLoop] runOnceBeforeDate: date forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) addEvent: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
watcher: (id<RunLoopEvents>)watcher
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
RunLoopWatcher *info;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
{
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
info = [self _getWatcher: data type: type forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-11-12 08:41:44 +00:00
|
|
|
|
if (info && info->receiver == (id)watcher)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
|
|
|
|
/* Increment usage count for this watcher. */
|
1998-11-12 08:41:44 +00:00
|
|
|
|
info->count++;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Remove any existing handler for another watcher. */
|
|
|
|
|
[self _removeWatcher: data type: type forMode: mode];
|
|
|
|
|
|
|
|
|
|
/* Create new object to hold information. */
|
|
|
|
|
info = [[RunLoopWatcher alloc] initWithType: type
|
|
|
|
|
receiver: watcher
|
|
|
|
|
data: data];
|
1998-11-26 10:39:37 +00:00
|
|
|
|
/* Add the object to the array for the mode. */
|
1999-04-19 14:29:52 +00:00
|
|
|
|
[self _addWatcher: info forMode: mode];
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RELEASE(info); /* Now held in array. */
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) addReadDescriptor: (int)fd
|
|
|
|
|
object: (id <FdListening>)listener
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self addEvent: (void*)fd
|
|
|
|
|
type: ET_RDESC
|
|
|
|
|
watcher: (id<RunLoopEvents>)listener
|
|
|
|
|
forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add our new handler information to the array. */
|
|
|
|
|
- (void) addWriteDescriptor: (int)fd
|
|
|
|
|
object: (id <FdSpeaking>)speaker
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self addEvent: (void*)fd
|
|
|
|
|
type: ET_WDESC
|
|
|
|
|
watcher: (id<RunLoopEvents>)speaker
|
|
|
|
|
forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeEvent: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode
|
1997-09-09 15:30:24 +00:00
|
|
|
|
all: (BOOL)removeAll
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
{
|
|
|
|
|
mode = _current_mode;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (removeAll)
|
|
|
|
|
{
|
|
|
|
|
[self _removeWatcher: data type: type forMode: mode];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RunLoopWatcher *info;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
info = [self _getWatcher: data type: type forMode: mode];
|
1997-09-09 15:30:24 +00:00
|
|
|
|
|
1998-11-12 08:41:44 +00:00
|
|
|
|
if (info)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1998-11-12 08:41:44 +00:00
|
|
|
|
if (info->count == 0)
|
|
|
|
|
{
|
|
|
|
|
[self _removeWatcher: data type: type forMode: mode];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
info->count--;
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeReadDescriptor: (int)fd
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return [self removeEvent: (void*)fd type: ET_RDESC forMode: mode all: NO];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeWriteDescriptor: (int)fd
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return [self removeEvent: (void*)fd type: ET_WDESC forMode: mode all: NO];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) runOnceBeforeDate: date
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self runOnceBeforeDate: date forMode: _current_mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Running the run loop once through for timers and input listening. */
|
|
|
|
|
|
|
|
|
|
- (BOOL) runOnceBeforeDate: date forMode: (NSString*)mode
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return [self runMode: mode beforeDate: date];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) runUntilDate: date forMode: (NSString*)mode
|
|
|
|
|
{
|
1999-06-25 10:22:55 +00:00
|
|
|
|
double ti = [date timeIntervalSinceNow];
|
|
|
|
|
BOOL mayDoMore = YES;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
/* Positive values are in the future. */
|
1998-03-05 00:37:44 +00:00
|
|
|
|
while (ti > 0 && mayDoMore == YES)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop run until date %f seconds from now\n", ti);
|
1998-03-05 00:37:44 +00:00
|
|
|
|
mayDoMore = [self runMode: mode beforeDate: date];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
ti = [date timeIntervalSinceNow];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1996-04-10 18:20:36 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
#if GS_WITH_GC == 0
|
|
|
|
|
static SEL wRelSel = @selector(release);
|
|
|
|
|
static SEL wRetSel = @selector(retain);
|
|
|
|
|
static IMP wRelImp;
|
|
|
|
|
static IMP wRetImp;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wRelease(void* t, id w)
|
|
|
|
|
{
|
|
|
|
|
(*wRelImp)(w, wRelSel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static id
|
|
|
|
|
wRetain(void* t, id w)
|
|
|
|
|
{
|
|
|
|
|
return (*wRetImp)(w, wRetSel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|
|
|
|
{
|
|
|
|
|
(NSMT_retain_func_t) wRetain,
|
|
|
|
|
(NSMT_release_func_t) wRelease,
|
|
|
|
|
(NSMT_describe_func_t) 0
|
|
|
|
|
};
|
|
|
|
|
#else
|
|
|
|
|
#define WatcherMapValueCallBacks NSOwnedPointerMapValueCallBacks
|
|
|
|
|
#endif
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
static void*
|
1999-06-21 08:30:26 +00:00
|
|
|
|
aRetain(void* t, GSIArray a)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
1999-06-21 08:30:26 +00:00
|
|
|
|
aRelease(void* t, GSIArray a)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayEmpty(a);
|
1999-04-20 16:28:04 +00:00
|
|
|
|
NSZoneFree(a->zone, (void*)a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const NSMapTableValueCallBacks ArrayMapValueCallBacks =
|
|
|
|
|
{
|
|
|
|
|
(NSMT_retain_func_t) aRetain,
|
|
|
|
|
(NSMT_release_func_t) aRelease,
|
|
|
|
|
(NSMT_describe_func_t) 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSRunLoop class])
|
|
|
|
|
{
|
|
|
|
|
[self currentRunLoop];
|
|
|
|
|
theFuture = RETAIN([NSDate distantFuture]);
|
|
|
|
|
#if GS_WITH_GC == 0
|
|
|
|
|
wRelImp = [[RunLoopWatcher class] instanceMethodForSelector: wRelSel];
|
|
|
|
|
wRetImp = [[RunLoopWatcher class] instanceMethodForSelector: wRetSel];
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-03-02 08:58:30 +00:00
|
|
|
|
+ (NSRunLoop*) currentRunLoop
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
static NSString *key = @"NSRunLoopThreadKey";
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSMutableDictionary *d;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSRunLoop* r;
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
d = GSCurrentThreadDictionary();
|
|
|
|
|
r = [d objectForKey: key];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (r == nil)
|
|
|
|
|
{
|
|
|
|
|
r = [NSRunLoop new];
|
1999-04-19 14:29:52 +00:00
|
|
|
|
[d setObject: r forKey: key];
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RELEASE(r);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
1996-04-10 18:20:36 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* This is the designated initializer. */
|
1999-03-02 08:58:30 +00:00
|
|
|
|
- (id) init
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
[super init];
|
|
|
|
|
_current_mode = NSDefaultRunLoopMode;
|
|
|
|
|
_mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
1999-04-20 16:28:04 +00:00
|
|
|
|
ArrayMapValueCallBacks, 0);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
_mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks,
|
1999-04-20 16:28:04 +00:00
|
|
|
|
ArrayMapValueCallBacks, 0);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
_performers = [[NSMutableArray alloc] initWithCapacity: 8];
|
|
|
|
|
_timedPerformers = [[NSMutableArray alloc] initWithCapacity: 8];
|
|
|
|
|
_rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
WatcherMapValueCallBacks, 0);
|
|
|
|
|
_wfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
WatcherMapValueCallBacks, 0);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return self;
|
1996-04-10 18:20:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (void) dealloc
|
1999-03-02 08:58:30 +00:00
|
|
|
|
{
|
|
|
|
|
[self gcFinalize];
|
|
|
|
|
RELEASE(_performers);
|
|
|
|
|
RELEASE(_timedPerformers);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) gcFinalize
|
1996-04-10 18:20:36 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSFreeMapTable(_mode_2_timers);
|
|
|
|
|
NSFreeMapTable(_mode_2_watchers);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSFreeMapTable(_rfdMap);
|
|
|
|
|
NSFreeMapTable(_wfdMap);
|
1996-04-10 18:20:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (NSString*) currentMode
|
|
|
|
|
{
|
|
|
|
|
return _current_mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Adding timers. They are removed when they are invalid. */
|
|
|
|
|
|
|
|
|
|
- (void) addTimer: timer
|
|
|
|
|
forMode: (NSString*)mode
|
1996-04-10 18:20:36 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArray timers;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
timers = NSMapGet(_mode_2_timers, mode);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (!timers)
|
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
NSZone *z = [self zone];
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
timers = NSZoneMalloc(z, sizeof(GSIArray_t));
|
|
|
|
|
GSIArrayInitWithZoneAndCapacity(timers, z, 8);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSMapInsert(_mode_2_timers, mode, timers);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayInsertSorted(timers, (GSIArrayItem)timer, aSort);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Fire appropriate timers and determine the earliest time that anything
|
|
|
|
|
watched for becomes useless. */
|
|
|
|
|
|
1999-04-21 20:16:25 +00:00
|
|
|
|
- (NSDate*) limitDateForMode: (NSString*)mode
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-06-25 10:22:55 +00:00
|
|
|
|
CREATE_AUTORELEASE_POOL(arp);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
id saved_mode;
|
1999-04-22 11:24:57 +00:00
|
|
|
|
NSDate *when;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArray timers;
|
|
|
|
|
GSIArray watchers;
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSTimer *min_timer = nil;
|
|
|
|
|
RunLoopWatcher *min_watcher = nil;
|
|
|
|
|
|
|
|
|
|
saved_mode = _current_mode;
|
|
|
|
|
_current_mode = mode;
|
|
|
|
|
|
|
|
|
|
timers = NSMapGet(_mode_2_timers, mode);
|
|
|
|
|
if (timers)
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
while (GSIArrayCount(timers) != 0)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
min_timer = GSIArrayItemAtIndex(timers, 0).obj;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if (timerInvalidated(min_timer) == YES)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayRemoveItemAtIndex(timers, 0);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
min_timer = nil;
|
|
|
|
|
continue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
|
if ([timerDate(min_timer) timeIntervalSinceNow] > 0)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayRemoveItemAtIndexNoRelease(timers, 0);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* Firing will also increment its fireDate, if it is repeating. */
|
|
|
|
|
[min_timer fire];
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if (timerInvalidated(min_timer) == NO)
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayInsertSortedNoRetain(timers,
|
|
|
|
|
(GSIArrayItem)min_timer, aSort);
|
1999-04-20 16:28:04 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
RELEASE(min_timer);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
min_timer = nil;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
GSNotifyASAP(); /* Post notifications. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* Is this right? At the moment we invalidate and discard watchers
|
|
|
|
|
whose limit-dates have passed. */
|
|
|
|
|
watchers = NSMapGet(_mode_2_watchers, mode);
|
|
|
|
|
if (watchers)
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
while (GSIArrayCount(watchers) != 0)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
min_watcher = GSIArrayItemAtIndex(watchers, 0).obj;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if (min_watcher->_invalidated == YES)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayRemoveItemAtIndex(watchers, 0);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
min_watcher = nil;
|
|
|
|
|
continue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
|
if ([min_watcher->_date timeIntervalSinceNow] > 0)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
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.
|
|
|
|
|
*/
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayRemoveItemAtIndexNoRelease(watchers, 0);
|
1998-11-12 08:41:44 +00:00
|
|
|
|
obj = min_watcher->receiver;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
if ([obj respondsToSelector:
|
1998-10-29 08:46:30 +00:00
|
|
|
|
@selector(timedOutEvent:type:forMode:)])
|
|
|
|
|
{
|
1998-11-12 08:41:44 +00:00
|
|
|
|
nxt = [obj timedOutEvent: min_watcher->data
|
|
|
|
|
type: min_watcher->type
|
|
|
|
|
forMode: _current_mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1999-04-19 14:29:52 +00:00
|
|
|
|
else if ([obj respondsToSelector: @selector(delegate)])
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
|
|
|
|
obj = [obj delegate];
|
1999-05-06 19:37:45 +00:00
|
|
|
|
if (obj != nil && [obj respondsToSelector:
|
1998-10-29 08:46:30 +00:00
|
|
|
|
@selector(timedOutEvent:type:forMode:)])
|
|
|
|
|
{
|
1998-11-12 08:41:44 +00:00
|
|
|
|
nxt = [obj timedOutEvent: min_watcher->data
|
|
|
|
|
type: min_watcher->type
|
|
|
|
|
forMode: _current_mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
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.
|
|
|
|
|
*/
|
1999-04-22 11:24:57 +00:00
|
|
|
|
ASSIGN(min_watcher->_date, nxt);
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayInsertSortedNoRetain(watchers,
|
|
|
|
|
(GSIArrayItem)min_watcher, aSort);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
1999-04-22 11:24:57 +00:00
|
|
|
|
* If the watcher is now useless - invalidate and
|
|
|
|
|
* release it.
|
1998-10-29 08:46:30 +00:00
|
|
|
|
*/
|
1999-04-20 16:28:04 +00:00
|
|
|
|
min_watcher->_invalidated = YES;
|
1999-04-22 11:24:57 +00:00
|
|
|
|
RELEASE(min_watcher);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
min_watcher = nil;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-21 20:16:25 +00:00
|
|
|
|
_current_mode = saved_mode;
|
1999-06-25 10:22:55 +00:00
|
|
|
|
RELEASE(arp);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/*
|
1999-04-21 20:16:25 +00:00
|
|
|
|
* If there are timers - set limit date to the earliest of them.
|
1998-10-29 08:46:30 +00:00
|
|
|
|
* If there are watchers, set the limit date to that of the earliest
|
|
|
|
|
* watcher (or leave it as the date of the earliest timer if that is
|
|
|
|
|
* before the watchers limit).
|
|
|
|
|
*/
|
1999-04-21 20:16:25 +00:00
|
|
|
|
if (min_timer)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-21 20:16:25 +00:00
|
|
|
|
when = timerDate(min_timer);
|
1999-04-22 11:24:57 +00:00
|
|
|
|
if (min_watcher != nil
|
|
|
|
|
&& [min_watcher->_date compare: when] == NSOrderedAscending)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
when = min_watcher->_date;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1999-04-21 20:16:25 +00:00
|
|
|
|
}
|
|
|
|
|
else if (min_watcher)
|
|
|
|
|
{
|
|
|
|
|
when = min_watcher->_date;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return nil; /* Nothing waiting to be done. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-21 20:16:25 +00:00
|
|
|
|
if (debug_run_loop)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-22 11:24:57 +00:00
|
|
|
|
printf ("\tNSRunLoop limit date %f\n",
|
|
|
|
|
[when timeIntervalSinceReferenceDate]);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
|
return when;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-12 17:54:10 +00:00
|
|
|
|
- (RunLoopWatcher*) _getWatcher: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArray watchers;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
{
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
}
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
watchers = NSMapGet(_mode_2_watchers, mode);
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if (watchers)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
unsigned i = GSIArrayCount(watchers);
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
while (i-- > 0)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
RunLoopWatcher *info;
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
info = GSIArrayItemAtIndex(watchers, i).obj;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if (info->type == type && info->data == data)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
|
|
|
|
return info;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return nil;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _removeWatcher: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArray watchers;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
{
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
}
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
watchers = NSMapGet(_mode_2_watchers, mode);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (watchers)
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
unsigned i = GSIArrayCount(watchers);
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
while (i-- > 0)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
RunLoopWatcher *info;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
info = GSIArrayItemAtIndex(watchers, i).obj;
|
1998-11-12 08:41:44 +00:00
|
|
|
|
if (info->type == type && info->data == data)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
info->_invalidated = YES;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayRemoveItemAtIndex(watchers, i);
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
/* Listen to input sources.
|
|
|
|
|
If LIMIT_DATE is nil, then don't wait; i.e. call select() with 0 timeout */
|
|
|
|
|
|
|
|
|
|
- (void) acceptInputForMode: (NSString*)mode
|
|
|
|
|
beforeDate: limit_date
|
|
|
|
|
{
|
1999-06-25 10:22:55 +00:00
|
|
|
|
CREATE_AUTORELEASE_POOL(arp);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSTimeInterval ti;
|
|
|
|
|
struct timeval timeout;
|
|
|
|
|
void *select_timeout;
|
|
|
|
|
fd_set fds; /* The file descriptors we will listen to. */
|
|
|
|
|
fd_set read_fds; /* Copy for listening to read-ready fds. */
|
|
|
|
|
fd_set exception_fds; /* Copy for listening to exception fds. */
|
|
|
|
|
fd_set write_fds; /* Copy for listening for write-ready fds. */
|
|
|
|
|
int select_return;
|
|
|
|
|
int fd_index;
|
|
|
|
|
id saved_mode;
|
|
|
|
|
int num_inputs = 0;
|
|
|
|
|
|
1998-11-19 21:26:27 +00:00
|
|
|
|
NSAssert(mode, NSInvalidArgumentException);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
saved_mode = _current_mode;
|
|
|
|
|
_current_mode = mode;
|
|
|
|
|
|
|
|
|
|
/* Find out how much time we should wait, and set SELECT_TIMEOUT. */
|
|
|
|
|
if (!limit_date)
|
|
|
|
|
{
|
|
|
|
|
/* Don't wait at all. */
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
select_timeout = &timeout;
|
|
|
|
|
}
|
1999-04-19 14:29:52 +00:00
|
|
|
|
else if ((ti = [limit_date timeIntervalSinceNow])
|
|
|
|
|
< LONG_MAX && ti > 0.0)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
/* 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. */
|
1999-04-21 20:16:25 +00:00
|
|
|
|
[self _checkPerformers];
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop limit date past, returning\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
|
_current_mode = saved_mode;
|
1999-06-25 10:22:55 +00:00
|
|
|
|
RELEASE(arp);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Wait forever. */
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop accept input waiting forever\n");
|
|
|
|
|
select_timeout = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
1999-02-17 14:31:13 +00:00
|
|
|
|
memset(&fds, '\0', sizeof(fds));
|
|
|
|
|
memset(&write_fds, '\0', sizeof(write_fds));
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSResetMapTable(_rfdMap);
|
|
|
|
|
NSResetMapTable(_wfdMap);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
/* Do the pre-listening set-up for the file descriptors of this mode. */
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArray watchers;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
watchers = NSMapGet(_mode_2_watchers, mode);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (watchers) {
|
|
|
|
|
int i;
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
for (i = GSIArrayCount(watchers); i > 0; i--) {
|
1999-04-20 16:28:04 +00:00
|
|
|
|
RunLoopWatcher *info;
|
|
|
|
|
int fd;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
info = GSIArrayItemAtIndex(watchers, i-1).obj;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if (info->_invalidated == YES) {
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayRemoveItemAtIndex(watchers, i-1);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
1998-11-12 08:41:44 +00:00
|
|
|
|
switch (info->type) {
|
1999-04-19 14:29:52 +00:00
|
|
|
|
case ET_WDESC:
|
1998-11-12 08:41:44 +00:00
|
|
|
|
fd = (int)info->data;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
FD_SET (fd, &write_fds);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSMapInsert(_wfdMap, (void*)fd, info);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
num_inputs++;
|
|
|
|
|
break;
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
case ET_RDESC:
|
1998-11-12 08:41:44 +00:00
|
|
|
|
fd = (int)info->data;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
FD_SET (fd, &fds);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSMapInsert(_rfdMap, (void*)fd, info);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
num_inputs++;
|
|
|
|
|
break;
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
case ET_RPORT:
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-11-12 08:41:44 +00:00
|
|
|
|
id port = info->receiver;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
int port_fd_count = 128; // xxx #define this constant
|
|
|
|
|
int port_fd_array[port_fd_count];
|
|
|
|
|
|
|
|
|
|
if ([port respondsTo: @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_SET (port_fd_array[port_fd_count], &fds);
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSMapInsert(_rfdMap,
|
1997-09-01 21:59:51 +00:00
|
|
|
|
(void*)port_fd_array[port_fd_count],
|
|
|
|
|
info);
|
|
|
|
|
num_inputs++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wait for incoming data, listening to the file descriptors in _FDS. */
|
|
|
|
|
read_fds = fds;
|
|
|
|
|
exception_fds = fds;
|
|
|
|
|
|
|
|
|
|
/* Detect if the NSRunLoop is idle, and if necessary - dispatch the
|
|
|
|
|
notifications from NSNotificationQueue's idle queue? */
|
1999-04-20 16:28:04 +00:00
|
|
|
|
if (num_inputs == 0 && GSNotifyMore())
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
select_timeout = &timeout;
|
|
|
|
|
select_return = select (FD_SETSIZE, &read_fds, &write_fds, &exception_fds,
|
|
|
|
|
select_timeout);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
select_return = select (FD_SETSIZE, &read_fds, &write_fds, &exception_fds,
|
|
|
|
|
select_timeout);
|
|
|
|
|
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop select returned %d\n", select_return);
|
|
|
|
|
|
|
|
|
|
if (select_return < 0)
|
|
|
|
|
{
|
1998-11-06 19:46:23 +00:00
|
|
|
|
if (errno == EINTR)
|
|
|
|
|
{
|
|
|
|
|
select_return = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Some exceptional condition happened. */
|
|
|
|
|
/* xxx We can do something with exception_fds, instead of
|
|
|
|
|
aborting here. */
|
1999-04-19 14:29:52 +00:00
|
|
|
|
perror ("[NSRunLoop acceptInputForMode: beforeDate: ] select()");
|
1998-11-06 19:46:23 +00:00
|
|
|
|
abort ();
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-11-06 19:46:23 +00:00
|
|
|
|
if (select_return == 0)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSResetMapTable(_rfdMap);
|
|
|
|
|
NSResetMapTable(_wfdMap);
|
1999-04-20 16:28:04 +00:00
|
|
|
|
GSNotifyIdle();
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[self _checkPerformers];
|
|
|
|
|
_current_mode = saved_mode;
|
1999-06-25 10:22:55 +00:00
|
|
|
|
RELEASE(arp);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
/*
|
|
|
|
|
* Look at all the file descriptors select() says are ready for reading;
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
for (fd_index = 0; fd_index < FD_SETSIZE; fd_index++)
|
|
|
|
|
{
|
|
|
|
|
if (FD_ISSET (fd_index, &write_fds))
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
RunLoopWatcher *watcher;
|
|
|
|
|
|
|
|
|
|
watcher = NSMapGet(_wfdMap, (void*)fd_index);
|
1999-05-18 07:24:30 +00:00
|
|
|
|
if (watcher != nil && watcher->_invalidated == NO)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The watcher is still valid - so call it's receivers
|
|
|
|
|
* event handling method.
|
|
|
|
|
*/
|
|
|
|
|
if (watcher->handleEvent != 0)
|
|
|
|
|
{
|
|
|
|
|
(*watcher->handleEvent)(watcher->receiver,
|
|
|
|
|
eventSel, watcher->data, watcher->type,
|
|
|
|
|
(void*)(gsaddr)fd_index, _current_mode);
|
|
|
|
|
}
|
|
|
|
|
else if (watcher->type == ET_WDESC)
|
|
|
|
|
{
|
|
|
|
|
[watcher->receiver readyForWritingOnFileDescriptor:
|
|
|
|
|
(int)(gsaddr)fd_index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GSNotifyASAP();
|
|
|
|
|
if (--select_return == 0)
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
if (FD_ISSET (fd_index, &read_fds))
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
RunLoopWatcher *watcher;
|
|
|
|
|
|
|
|
|
|
watcher = (RunLoopWatcher*)NSMapGet(_rfdMap, (void*)fd_index);
|
1999-05-18 07:24:30 +00:00
|
|
|
|
if (watcher != nil && watcher->_invalidated == NO)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The watcher is still valid - so call it's receivers
|
|
|
|
|
* event handling method.
|
|
|
|
|
*/
|
|
|
|
|
if (watcher->handleEvent != 0)
|
|
|
|
|
{
|
|
|
|
|
(*watcher->handleEvent)(watcher->receiver,
|
|
|
|
|
eventSel, watcher->data, watcher->type,
|
|
|
|
|
(void*)(gsaddr)fd_index, _current_mode);
|
|
|
|
|
}
|
|
|
|
|
else if (watcher->type == ET_RDESC || watcher->type == ET_RPORT)
|
|
|
|
|
{
|
|
|
|
|
[watcher->receiver readyForReadingOnFileDescriptor:
|
|
|
|
|
(int)(gsaddr)fd_index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GSNotifyASAP();
|
|
|
|
|
if (--select_return == 0)
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-04-19 14:29:52 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Clean up before returning. */
|
1999-04-19 14:29:52 +00:00
|
|
|
|
NSResetMapTable(_rfdMap);
|
|
|
|
|
NSResetMapTable(_wfdMap);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
[self _checkPerformers];
|
1999-04-20 16:28:04 +00:00
|
|
|
|
GSNotifyASAP();
|
1997-09-01 21:59:51 +00:00
|
|
|
|
_current_mode = saved_mode;
|
1999-06-25 10:22:55 +00:00
|
|
|
|
RELEASE(arp);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) runMode: (NSString*)mode beforeDate: date
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
id d;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
|
NSAssert(mode && date, NSInvalidArgumentException);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* If date has already passed, simply return. */
|
|
|
|
|
if ([date timeIntervalSinceNow] < 0)
|
|
|
|
|
{
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
{
|
|
|
|
|
printf ("\tNSRunLoop run mode with date already past\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* Find out how long we can wait before first limit date. */
|
|
|
|
|
d = [self limitDateForMode: mode];
|
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
{
|
|
|
|
|
printf ("\tNSRunLoop run mode with nothing to do\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-06-25 10:22:55 +00:00
|
|
|
|
/*
|
|
|
|
|
* Use the earlier of the two dates we have.
|
|
|
|
|
* Retain the date in case the firing of a timer (or some other event)
|
|
|
|
|
* releases it.
|
|
|
|
|
*/
|
1999-04-21 20:16:25 +00:00
|
|
|
|
d = [d earlierDate: date];
|
1999-04-22 11:24:57 +00:00
|
|
|
|
RETAIN(d);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* Wait, listening to our input sources. */
|
|
|
|
|
[self acceptInputForMode: mode beforeDate: d];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
|
RELEASE(d);
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return YES;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) run
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
[self runUntilDate: theFuture];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) runUntilDate: date
|
|
|
|
|
{
|
|
|
|
|
[self runUntilDate: date forMode: _current_mode];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* NSRunLoop mode strings. */
|
|
|
|
|
|
|
|
|
|
id NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop (OPENSTEP)
|
|
|
|
|
|
|
|
|
|
- (void) addPort: (NSPort*)port
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self addEvent: (void*)port
|
|
|
|
|
type: ET_RPORT
|
|
|
|
|
watcher: (id<RunLoopEvents>)port
|
|
|
|
|
forMode: (NSString*)mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) cancelPerformSelector: (SEL)aSelector
|
|
|
|
|
target: target
|
|
|
|
|
argument: argument
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
int count = [_performers count];
|
|
|
|
|
int i;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RETAIN(target);
|
|
|
|
|
RETAIN(argument);
|
1998-10-29 08:46:30 +00:00
|
|
|
|
for (i = count; i > 0; i--)
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
item = (RunLoopPerformer*)[_performers objectAtIndex: (i-1)];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
if ([item matchesSelector: aSelector target: target argument: argument])
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
[_performers removeObjectAtIndex: (i-1)];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RELEASE(argument);
|
|
|
|
|
RELEASE(target);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) configureAsServer
|
|
|
|
|
{
|
|
|
|
|
/* Nothing to do here */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) performSelector: (SEL)aSelector
|
|
|
|
|
target: target
|
|
|
|
|
argument: argument
|
|
|
|
|
order: (unsigned int)order
|
|
|
|
|
modes: (NSArray*)modes
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
int count = [_performers count];
|
|
|
|
|
|
|
|
|
|
item = [[RunLoopPerformer alloc] initWithSelector: aSelector
|
|
|
|
|
target: target
|
|
|
|
|
argument: argument
|
|
|
|
|
order: order
|
|
|
|
|
modes: modes];
|
|
|
|
|
/* Add new item to list - reverse ordering */
|
|
|
|
|
if (count == 0)
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
[_performers addObject: item];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int i;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
if ([[_performers objectAtIndex: i] order] <= order)
|
1998-10-29 08:46:30 +00:00
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
[_performers insertObject: item atIndex: i];
|
1998-10-29 08:46:30 +00:00
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (i == count)
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
[_performers addObject: item];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-03-02 08:58:30 +00:00
|
|
|
|
RELEASE(item);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removePort: (NSPort*)port
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1999-04-19 14:29:52 +00:00
|
|
|
|
return [self removeEvent: (void*)port type: ET_RPORT forMode: mode all: NO];
|
1996-04-10 18:20:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|