1996-03-12 15:39:13 +00:00
|
|
|
|
/* Implementation of object for waiting on several input sources
|
1997-01-06 22:21:02 +00:00
|
|
|
|
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1996-03-12 15:39:13 +00:00
|
|
|
|
Created: March 1996
|
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1996-03-12 15:39:13 +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.
|
|
|
|
|
|
|
|
|
|
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-01-06 22:21:02 +00:00
|
|
|
|
/* October 1996 - extensions to permit file descriptors to be watched
|
|
|
|
|
for being readable or writable added by Richard Frith-Macdonald
|
|
|
|
|
(richard@brainstorm.co.uk) */
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
/* This is the beginning of a RunLoop implementation.
|
|
|
|
|
It is still in the early stages of development, and will most likely
|
|
|
|
|
evolve quite a bit more before the interface settles.
|
|
|
|
|
|
|
|
|
|
Does it strike anyone else that NSNotificationCenter,
|
|
|
|
|
NSNotificationQueue, NSNotification, NSRunLoop, the "notifications"
|
|
|
|
|
a run loop sends the objects on which it is listening, NSEvent, and
|
|
|
|
|
the event queue maintained by NSApplication are all much more
|
|
|
|
|
intertwined/similar than OpenStep gives them credit for?
|
|
|
|
|
|
|
|
|
|
I wonder if these classes could be re-organized a little to make a
|
|
|
|
|
more uniform, "grand-unified" mechanism for: events,
|
|
|
|
|
event-listening, event-queuing, and event-distributing. It could
|
|
|
|
|
be quite pretty.
|
|
|
|
|
|
|
|
|
|
(GNUstep would definitely provide classes that were compatible with
|
|
|
|
|
all these OpenStep classes, but those classes could be wrappers
|
|
|
|
|
around fundamentally cleaner GNU classes. RMS has advised using an
|
|
|
|
|
underlying organization/implementation different from NeXT's
|
|
|
|
|
whenever that makes sense---it helps legally distinguish our work.)
|
|
|
|
|
|
|
|
|
|
Thoughts and insights, anyone?
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Alternate names: InputDemuxer, InputListener, EventListener.
|
|
|
|
|
Alternate names for Notification classes: Dispatcher, EventDistributor, */
|
|
|
|
|
|
1996-04-17 15:34:35 +00:00
|
|
|
|
#include <gnustep/base/preface.h>
|
1996-10-31 17:54:57 +00:00
|
|
|
|
#include <gnustep/base/Bag.h>
|
1996-04-17 15:23:00 +00:00
|
|
|
|
#include <gnustep/base/RunLoop.h>
|
|
|
|
|
#include <gnustep/base/Heap.h>
|
1996-03-12 15:39:13 +00:00
|
|
|
|
#include <Foundation/NSMapTable.h>
|
|
|
|
|
#include <Foundation/NSDate.h>
|
|
|
|
|
#include <Foundation/NSValue.h>
|
|
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
|
|
|
|
#include <Foundation/NSTimer.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <Foundation/NSNotificationQueue.h>
|
1997-09-13 17:52:31 +00:00
|
|
|
|
|
|
|
|
|
#ifdef _AIX
|
|
|
|
|
#include <sys/select.h>
|
|
|
|
|
#endif /* AIX */
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
#ifndef __WIN32__
|
1996-03-12 15:39:13 +00:00
|
|
|
|
#include <sys/time.h>
|
1996-07-15 18:41:44 +00:00
|
|
|
|
#endif /* !__WIN32__ */
|
1997-09-13 17:52:31 +00:00
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
#include <limits.h>
|
1996-03-18 14:00:47 +00:00
|
|
|
|
#include <string.h> /* for memset() */
|
|
|
|
|
|
|
|
|
|
/* On some systems FD_ZERO is a macro that uses bzero().
|
|
|
|
|
Just define it to use memset(). */
|
|
|
|
|
#define bzero(PTR, LEN) memset (PTR, 0, LEN)
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
1996-10-31 17:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Local class to hold information about file descriptors to be watched
|
|
|
|
|
and the objects to which messages are to be sent when the descriptors
|
|
|
|
|
are readable or writable. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@interface FdInfo: NSObject
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
id receiver;
|
|
|
|
|
}
|
|
|
|
|
-(int)getFd;
|
|
|
|
|
-setFd:(int)desc;
|
|
|
|
|
-getReceiver;
|
|
|
|
|
-setReceiver:anObj;
|
|
|
|
|
-initWithFd:(int)desc andReceiver:anObj;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation FdInfo
|
|
|
|
|
-(int)getFd {
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
- setFd: (int)desc {
|
|
|
|
|
fd = desc;
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
-getReceiver {
|
|
|
|
|
return receiver;
|
|
|
|
|
}
|
|
|
|
|
-setReceiver: anObj {
|
|
|
|
|
if (receiver != nil) {
|
|
|
|
|
[receiver release];
|
|
|
|
|
}
|
|
|
|
|
receiver = [anObj retain];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
-initWithFd:(int)desc andReceiver:anObj { /* Designated initializer */
|
|
|
|
|
[super init];
|
|
|
|
|
[self setFd: desc];
|
|
|
|
|
return [self setReceiver: anObj];
|
|
|
|
|
}
|
|
|
|
|
-init {
|
|
|
|
|
return [self initWithFd:-1 andReceiver:nil];
|
|
|
|
|
}
|
|
|
|
|
-(void)dealloc {
|
|
|
|
|
if (receiver != nil) {
|
|
|
|
|
[receiver release];
|
|
|
|
|
}
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Adding and removing file descriptors. */
|
|
|
|
|
|
|
|
|
|
@implementation RunLoop(GNUstepExtensions)
|
|
|
|
|
|
|
|
|
|
- (void) addReadDescriptor: (int)fd
|
|
|
|
|
object: (id <FdListening>)listener
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
1996-10-31 17:54:57 +00:00
|
|
|
|
{
|
|
|
|
|
Bag *fd_listeners;
|
|
|
|
|
FdInfo *info;
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
|
1996-10-31 17:54:57 +00:00
|
|
|
|
/* Remove any existing handler for the specified descriptor. */
|
|
|
|
|
[self removeReadDescriptor: fd forMode: mode];
|
|
|
|
|
|
|
|
|
|
/* Create new object to hold information. */
|
|
|
|
|
info = [[FdInfo alloc] initWithFd: fd andReceiver: listener];
|
|
|
|
|
|
|
|
|
|
/* Ensure we have a bag to put it in. */
|
|
|
|
|
fd_listeners = NSMapGet (_mode_2_fd_listeners, mode);
|
|
|
|
|
if (!fd_listeners)
|
|
|
|
|
{
|
|
|
|
|
fd_listeners = [Bag new];
|
|
|
|
|
NSMapInsert (_mode_2_fd_listeners, mode, fd_listeners);
|
|
|
|
|
[fd_listeners release];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add our new handler information to the bag. */
|
|
|
|
|
[fd_listeners addObject: info];
|
|
|
|
|
[info release];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) addWriteDescriptor: (int)fd
|
|
|
|
|
object: (id <FdSpeaking>)speaker
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
1996-10-31 17:54:57 +00:00
|
|
|
|
{
|
|
|
|
|
Bag *fd_speakers;
|
|
|
|
|
FdInfo *info;
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
|
1996-10-31 17:54:57 +00:00
|
|
|
|
/* Remove any existing handler for the specified descriptor. */
|
|
|
|
|
[self removeWriteDescriptor: fd forMode: mode];
|
|
|
|
|
|
|
|
|
|
/* Create new object to hold information. */
|
|
|
|
|
info = [[FdInfo alloc] initWithFd: fd andReceiver: speaker];
|
|
|
|
|
|
|
|
|
|
/* Ensure we have a bag to put it in. */
|
|
|
|
|
fd_speakers = NSMapGet (_mode_2_fd_speakers, mode);
|
|
|
|
|
if (!fd_speakers)
|
|
|
|
|
{
|
|
|
|
|
fd_speakers = [Bag new];
|
|
|
|
|
NSMapInsert (_mode_2_fd_speakers, mode, fd_speakers);
|
|
|
|
|
[fd_speakers release];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add our new handler information to the bag. */
|
|
|
|
|
[fd_speakers addObject: info];
|
|
|
|
|
[info release];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeReadDescriptor: (int)fd
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
1996-10-31 17:54:57 +00:00
|
|
|
|
{
|
|
|
|
|
Bag* fd_listeners;
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
|
1996-10-31 17:54:57 +00:00
|
|
|
|
fd_listeners = NSMapGet (_mode_2_fd_listeners, mode);
|
|
|
|
|
if (fd_listeners)
|
|
|
|
|
{
|
|
|
|
|
void* es = [fd_listeners newEnumState];
|
|
|
|
|
id info;
|
|
|
|
|
|
|
|
|
|
while ((info=[fd_listeners nextObjectWithEnumState: &es])!=NO_OBJECT)
|
|
|
|
|
{
|
|
|
|
|
if ([info getFd] == fd)
|
|
|
|
|
{
|
|
|
|
|
[fd_listeners removeObject: info];
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[fd_listeners freeEnumState: &es];
|
1996-10-31 17:54:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeWriteDescriptor: (int)fd
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
1996-10-31 17:54:57 +00:00
|
|
|
|
{
|
|
|
|
|
Bag* fd_speakers;
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
|
1996-10-31 17:54:57 +00:00
|
|
|
|
fd_speakers = NSMapGet (_mode_2_fd_speakers, mode);
|
|
|
|
|
if (fd_speakers)
|
|
|
|
|
{
|
|
|
|
|
void* es = [fd_speakers newEnumState];
|
|
|
|
|
id info;
|
|
|
|
|
|
|
|
|
|
while ((info=[fd_speakers nextObjectWithEnumState: &es])!=NO_OBJECT)
|
|
|
|
|
{
|
|
|
|
|
if ([info getFd] == fd)
|
|
|
|
|
{
|
|
|
|
|
[fd_speakers removeObject: info];
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[fd_speakers freeEnumState: &es];
|
1996-10-31 17:54:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1996-03-29 14:47:38 +00:00
|
|
|
|
static int debug_run_loop = 0;
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
|
|
|
|
@implementation RunLoop
|
|
|
|
|
|
|
|
|
|
static RunLoop *current_run_loop;
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [RunLoop class])
|
|
|
|
|
current_run_loop = [self new];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is the designated initializer. */
|
|
|
|
|
- init
|
|
|
|
|
{
|
1996-03-18 19:32:45 +00:00
|
|
|
|
[super init];
|
|
|
|
|
_current_mode = RunLoopDefaultMode;
|
|
|
|
|
_mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
_mode_2_in_ports = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
_mode_2_fd_listeners = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
1996-10-31 17:54:57 +00:00
|
|
|
|
_mode_2_fd_speakers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
1996-03-12 15:39:13 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- (NSString*) currentMode
|
1996-03-12 15:39:13 +00:00
|
|
|
|
{
|
1996-03-18 19:32:45 +00:00
|
|
|
|
return _current_mode;
|
1996-03-12 15:39:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
|
|
|
|
/* Adding and removing port objects. */
|
|
|
|
|
|
|
|
|
|
- (void) addPort: port
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
1996-03-18 19:32:45 +00:00
|
|
|
|
{
|
1996-03-18 20:29:34 +00:00
|
|
|
|
/* xxx Perhaps this should be a Bag instead; I think this currently works
|
|
|
|
|
when a port is added more than once, but it doesn't work prettily. */
|
1996-03-18 19:32:45 +00:00
|
|
|
|
Array *in_ports;
|
|
|
|
|
|
|
|
|
|
in_ports = NSMapGet (_mode_2_in_ports, mode);
|
|
|
|
|
if (!in_ports)
|
|
|
|
|
{
|
|
|
|
|
in_ports = [Array new];
|
|
|
|
|
NSMapInsert (_mode_2_in_ports, mode, in_ports);
|
|
|
|
|
[in_ports release];
|
|
|
|
|
}
|
|
|
|
|
[in_ports addObject: port];
|
1996-03-12 15:39:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
- (void) removePort: port
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
1996-03-18 19:32:45 +00:00
|
|
|
|
{
|
|
|
|
|
/* xxx Perhaps this should be a Bag instead. */
|
|
|
|
|
Array *in_ports;
|
|
|
|
|
|
|
|
|
|
in_ports = NSMapGet (_mode_2_in_ports, mode);
|
|
|
|
|
if (in_ports)
|
|
|
|
|
/* xxx Careful, this is only suppose to "undo" one -addPort:.
|
|
|
|
|
If we change the -removeObject implementation later to remove
|
|
|
|
|
all instances of port, we'll have to change this code here. */
|
|
|
|
|
[in_ports removeObject: port];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Adding timers. They are removed when they are invalid. */
|
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
- (void) addTimer: timer
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
1996-03-12 15:39:13 +00:00
|
|
|
|
{
|
1996-03-18 19:32:45 +00:00
|
|
|
|
Heap *timers;
|
|
|
|
|
|
|
|
|
|
timers = NSMapGet (_mode_2_timers, mode);
|
|
|
|
|
if (!timers)
|
|
|
|
|
{
|
|
|
|
|
timers = [Heap new];
|
|
|
|
|
NSMapInsert (_mode_2_timers, mode, timers);
|
|
|
|
|
[timers release];
|
|
|
|
|
}
|
|
|
|
|
/* xxx Should we make sure it isn't already there? */
|
|
|
|
|
[timers addObject: timer];
|
1996-03-12 15:39:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
/* Fire appropriate timers. */
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- limitDateForMode: (NSString*)mode
|
1996-03-12 15:39:13 +00:00
|
|
|
|
{
|
1996-03-18 19:32:45 +00:00
|
|
|
|
/* Linux doesn't always return double from methods, even though
|
|
|
|
|
I'm using -lieee. */
|
|
|
|
|
Heap *timers;
|
1996-03-12 15:39:13 +00:00
|
|
|
|
NSTimer *min_timer = nil;
|
1996-03-18 19:32:45 +00:00
|
|
|
|
id saved_mode;
|
|
|
|
|
|
|
|
|
|
saved_mode = _current_mode;
|
|
|
|
|
_current_mode = mode;
|
|
|
|
|
|
|
|
|
|
timers = NSMapGet (_mode_2_timers, mode);
|
|
|
|
|
if (!timers)
|
1997-01-06 22:21:02 +00:00
|
|
|
|
{
|
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
/* Does this properly handle timers that have been sent -invalidate? */
|
1997-01-06 22:21:02 +00:00
|
|
|
|
while ((min_timer = [timers minObject]) != nil)
|
1996-03-12 15:39:13 +00:00
|
|
|
|
{
|
1997-01-06 22:21:02 +00:00
|
|
|
|
if (![min_timer isValid])
|
|
|
|
|
{
|
|
|
|
|
[timers removeFirstObject];
|
|
|
|
|
min_timer = nil;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([[min_timer fireDate] timeIntervalSinceNow] > 0)
|
|
|
|
|
break;
|
|
|
|
|
|
1996-10-31 17:59:25 +00:00
|
|
|
|
[min_timer retain];
|
1996-03-18 19:32:45 +00:00
|
|
|
|
[timers removeFirstObject];
|
1996-03-12 15:39:13 +00:00
|
|
|
|
/* Firing will also increment its fireDate, if it is repeating. */
|
1997-01-06 22:21:02 +00:00
|
|
|
|
[min_timer fire];
|
1996-03-12 15:39:13 +00:00
|
|
|
|
if ([min_timer isValid])
|
|
|
|
|
{
|
1997-05-03 19:18:55 +00:00
|
|
|
|
[timers addObject: min_timer];
|
1996-03-12 15:39:13 +00:00
|
|
|
|
}
|
1996-10-31 17:59:25 +00:00
|
|
|
|
[min_timer release];
|
1997-01-06 22:21:02 +00:00
|
|
|
|
min_timer = nil;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[NSNotificationQueue runLoopASAP]; /* Post notifications. */
|
1996-03-12 15:39:13 +00:00
|
|
|
|
}
|
1997-01-06 22:21:02 +00:00
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
if (min_timer == nil)
|
|
|
|
|
return nil;
|
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
if (debug_run_loop)
|
1997-01-06 22:21:02 +00:00
|
|
|
|
printf ("\tRunLoop limit date %f\n",
|
1996-03-12 15:39:13 +00:00
|
|
|
|
[[min_timer fireDate] timeIntervalSinceReferenceDate]);
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
return [min_timer fireDate];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
|
|
|
|
|
1997-09-13 17:52:31 +00:00
|
|
|
|
/*
|
|
|
|
|
Because WIN32 is so vastly different from UNIX in the way it
|
|
|
|
|
waits on file descriptors, sockets, and the event queue, I have
|
|
|
|
|
separated them out into complete separate methods. This will make
|
|
|
|
|
it much easier to maintain and read versus if it was all jumbled
|
|
|
|
|
together into a single method.
|
|
|
|
|
|
|
|
|
|
Note that only one of the two methods will actually be compiled.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#if defined(__WIN32__) || (_WIN32)
|
|
|
|
|
|
|
|
|
|
/* Private method
|
|
|
|
|
Perform WIN32 style mechanism to wait on multiple inputs */
|
|
|
|
|
- (void) acceptWIN32InputForMode: (NSString*)mode
|
|
|
|
|
beforeDate: limit_date
|
|
|
|
|
{
|
|
|
|
|
DWORD wait_count = 0;
|
|
|
|
|
HANDLE handle_list[MAXIMUM_WAIT_OBJECTS - 1];
|
|
|
|
|
DWORD wait_timeout;
|
|
|
|
|
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;
|
|
|
|
|
NSMapTable *fd_2_object;
|
|
|
|
|
NSTimeInterval ti;
|
|
|
|
|
id saved_mode;
|
|
|
|
|
DWORD wait_return;
|
|
|
|
|
id ports;
|
|
|
|
|
int num_of_ports;
|
|
|
|
|
int port_fd_count = 128; // xxx #define this constant
|
|
|
|
|
int port_fd_array[port_fd_count];
|
|
|
|
|
|
|
|
|
|
assert (mode);
|
|
|
|
|
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;
|
|
|
|
|
wait_timeout = 0;
|
|
|
|
|
}
|
|
|
|
|
else if ((ti = [limit_date timeIntervalSinceNow]) < LONG_MAX
|
|
|
|
|
&& ti > 0.0)
|
|
|
|
|
{
|
|
|
|
|
/* Wait until the LIMIT_DATE. */
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tRunLoop accept input before %f (seconds from now %f)\n",
|
|
|
|
|
[limit_date timeIntervalSinceReferenceDate], ti);
|
|
|
|
|
/* If LIMIT_DATE has already past, return immediately. */
|
|
|
|
|
if (ti < 0)
|
|
|
|
|
{
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tRunLoop limit date past, returning\n");
|
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
timeout.tv_sec = ti;
|
|
|
|
|
timeout.tv_usec = (ti - timeout.tv_sec) * 1000000.0;
|
|
|
|
|
select_timeout = &timeout;
|
|
|
|
|
wait_timeout = ti * 1000;
|
|
|
|
|
}
|
|
|
|
|
else if (ti <= 0.0)
|
|
|
|
|
{
|
|
|
|
|
/* The LIMIT_DATE has already past; return immediately without
|
|
|
|
|
polling any inputs. */
|
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Wait forever. */
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tRunLoop accept input waiting forever\n");
|
|
|
|
|
select_timeout = NULL;
|
|
|
|
|
wait_timeout = INFINITE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
/* Get ready to listen to file descriptors.
|
|
|
|
|
Initialize the set of FDS we'll pass to select(), and create
|
|
|
|
|
an empty map for keeping track of which object is associated
|
|
|
|
|
with which file descriptor. */
|
|
|
|
|
FD_ZERO (&fds);
|
|
|
|
|
FD_ZERO (&write_fds);
|
|
|
|
|
fd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
|
|
|
|
|
/* If a port is invalid, remove it from this mode. */
|
|
|
|
|
ports = NSMapGet (_mode_2_in_ports, mode);
|
|
|
|
|
{
|
|
|
|
|
id port;
|
|
|
|
|
int i;
|
|
|
|
|
for (i = [ports count]-1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
port = [ports objectAtIndex: i];
|
|
|
|
|
if (![port isValid])
|
|
|
|
|
[ports removeObjectAtIndex: i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
num_of_ports = 0;
|
|
|
|
|
|
|
|
|
|
/* Do the pre-listening set-up for the ports of this mode. */
|
|
|
|
|
{
|
|
|
|
|
if (ports)
|
|
|
|
|
{
|
|
|
|
|
id port;
|
|
|
|
|
int i;
|
|
|
|
|
int fd_count = port_fd_count;
|
|
|
|
|
int fd_array[port_fd_count];
|
|
|
|
|
|
|
|
|
|
/* Ask our ports for the list of file descriptors they
|
|
|
|
|
want us to listen to; add these to FD_LISTEN_SET.
|
|
|
|
|
Save the list of ports for later use. */
|
|
|
|
|
for (i = [ports count]-1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
port = [ports objectAtIndex: i];
|
|
|
|
|
if ([port respondsTo: @selector(getFds:count:)])
|
|
|
|
|
[port getFds: fd_array count: &fd_count];
|
|
|
|
|
else
|
|
|
|
|
fd_count = 0;
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf("\tRunLoop listening to %d sockets\n", fd_count);
|
|
|
|
|
num_of_ports += fd_count;
|
|
|
|
|
if (num_of_ports > port_fd_count)
|
|
|
|
|
{
|
|
|
|
|
/* xxx Uh oh our array isn't big enough */
|
|
|
|
|
perror ("RunLoop attempt to listen to too many ports\n");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
while (fd_count--)
|
|
|
|
|
{
|
|
|
|
|
int j = num_of_ports - fd_count - 1;
|
|
|
|
|
port_fd_array[j] = fd_array[fd_count];
|
|
|
|
|
FD_SET (port_fd_array[j], &fds);
|
|
|
|
|
NSMapInsert (fd_2_object,
|
|
|
|
|
(void*)port_fd_array[j],
|
|
|
|
|
port);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf("\tRunLoop listening to %d total ports\n", num_of_ports);
|
|
|
|
|
|
|
|
|
|
/* Wait for incoming data, listening to the file descriptors in _FDS. */
|
|
|
|
|
read_fds = fds;
|
|
|
|
|
exception_fds = fds;
|
|
|
|
|
select_return = select (FD_SETSIZE, &read_fds, &write_fds, &exception_fds,
|
|
|
|
|
select_timeout);
|
|
|
|
|
|
|
|
|
|
if (select_return < 0)
|
|
|
|
|
{
|
|
|
|
|
/* Some exceptional condition happened. */
|
|
|
|
|
/* xxx We can do something with exception_fds, instead of
|
|
|
|
|
aborting here. */
|
|
|
|
|
perror ("[TcpInPort receivePacketWithTimeout:] select()");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
else if (select_return == 0)
|
|
|
|
|
{
|
|
|
|
|
NSFreeMapTable (fd_2_object);
|
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Look at all the file descriptors select() says are ready for reading;
|
|
|
|
|
notify the corresponding object for each of the ready fd's. */
|
|
|
|
|
if (ports)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = num_of_ports - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
if (FD_ISSET (port_fd_array[i], &read_fds))
|
|
|
|
|
{
|
|
|
|
|
id fd_object = (id) NSMapGet (fd_2_object,
|
|
|
|
|
(void*)port_fd_array[i]);
|
|
|
|
|
assert (fd_object);
|
|
|
|
|
[fd_object readyForReadingOnFileDescriptor:
|
|
|
|
|
port_fd_array[i]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clean up before returning. */
|
|
|
|
|
NSFreeMapTable (fd_2_object);
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
/* Wait for incoming data */
|
|
|
|
|
wait_return = MsgWaitForMultipleObjects(wait_count, handle_list, FALSE,
|
|
|
|
|
wait_timeout, QS_ALLINPUT);
|
|
|
|
|
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tRunLoop MsgWaitForMultipleObjects returned %ld\n", wait_return);
|
|
|
|
|
|
|
|
|
|
if (wait_return == 0xFFFFFFFF)
|
|
|
|
|
{
|
|
|
|
|
/* Some exceptional condition happened. */
|
|
|
|
|
NSLog(@"RunLoop error, MsgWaitForMultipleObjects returned %d\n",
|
|
|
|
|
GetLastError());
|
|
|
|
|
}
|
|
|
|
|
else if (wait_return == (WAIT_OBJECT_0 + wait_count))
|
|
|
|
|
{
|
|
|
|
|
/* Event in the event queue */
|
|
|
|
|
if (_event_queue)
|
|
|
|
|
[_event_queue readyForReadingOnEventQueue];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* We handle the other wait objects here */
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
/* Private method
|
|
|
|
|
Perform UNIX style mechanism to wait on multiple inputs */
|
|
|
|
|
- (void) acceptUNIXInputForMode: (NSString*)mode
|
|
|
|
|
beforeDate: limit_date
|
1996-03-12 15:39:13 +00:00
|
|
|
|
{
|
|
|
|
|
NSTimeInterval ti;
|
|
|
|
|
struct timeval timeout;
|
|
|
|
|
void *select_timeout;
|
1996-03-18 19:32:45 +00:00
|
|
|
|
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. */
|
1996-10-31 17:54:57 +00:00
|
|
|
|
fd_set write_fds; /* Copy for listening for write-ready fds. */
|
1996-03-12 15:39:13 +00:00
|
|
|
|
int select_return;
|
1996-10-31 17:54:57 +00:00
|
|
|
|
int fd_index;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSMapTable *rfd_2_object;
|
|
|
|
|
NSMapTable *wfd_2_object;
|
1996-03-18 19:32:45 +00:00
|
|
|
|
id saved_mode;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
int num_inputs = 0;
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
1996-03-18 20:29:34 +00:00
|
|
|
|
assert (mode);
|
1996-03-18 19:32:45 +00:00
|
|
|
|
saved_mode = _current_mode;
|
|
|
|
|
_current_mode = mode;
|
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
/* Find out how much time we should wait, and set SELECT_TIMEOUT. */
|
1996-03-19 17:10:41 +00:00
|
|
|
|
if (!limit_date)
|
1996-03-12 15:39:13 +00:00
|
|
|
|
{
|
1996-03-19 17:10:41 +00:00
|
|
|
|
/* 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. */
|
1996-03-12 15:39:13 +00:00
|
|
|
|
if (debug_run_loop)
|
1996-03-19 00:59:05 +00:00
|
|
|
|
printf ("\tRunLoop accept input before %f (seconds from now %f)\n",
|
1996-03-12 15:39:13 +00:00
|
|
|
|
[limit_date timeIntervalSinceReferenceDate], ti);
|
|
|
|
|
/* If LIMIT_DATE has already past, return immediately. */
|
|
|
|
|
if (ti < 0)
|
|
|
|
|
{
|
|
|
|
|
if (debug_run_loop)
|
1996-03-19 00:59:05 +00:00
|
|
|
|
printf ("\tRunLoop limit date past, returning\n");
|
1997-01-06 22:21:02 +00:00
|
|
|
|
_current_mode = saved_mode;
|
1996-03-12 15:39:13 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
timeout.tv_sec = ti;
|
1996-10-31 16:54:41 +00:00
|
|
|
|
timeout.tv_usec = (ti - timeout.tv_sec) * 1000000.0;
|
1996-03-12 15:39:13 +00:00
|
|
|
|
select_timeout = &timeout;
|
|
|
|
|
}
|
1996-03-19 17:10:41 +00:00
|
|
|
|
else if (ti <= 0.0)
|
|
|
|
|
{
|
|
|
|
|
/* The LIMIT_DATE has already past; return immediately without
|
|
|
|
|
polling any inputs. */
|
1997-01-06 22:21:02 +00:00
|
|
|
|
_current_mode = saved_mode;
|
1996-03-19 17:10:41 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
1996-03-12 15:39:13 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
1996-03-19 17:10:41 +00:00
|
|
|
|
/* Wait forever. */
|
1996-03-12 15:39:13 +00:00
|
|
|
|
if (debug_run_loop)
|
1996-03-19 00:59:05 +00:00
|
|
|
|
printf ("\tRunLoop accept input waiting forever\n");
|
1996-03-12 15:39:13 +00:00
|
|
|
|
select_timeout = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
/* Get ready to listen to file descriptors.
|
|
|
|
|
Initialize the set of FDS we'll pass to select(), and create
|
|
|
|
|
an empty map for keeping track of which object is associated
|
|
|
|
|
with which file descriptor. */
|
|
|
|
|
FD_ZERO (&fds);
|
1996-10-31 17:54:57 +00:00
|
|
|
|
FD_ZERO (&write_fds);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
rfd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
wfd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks,
|
1996-03-18 19:32:45 +00:00
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
/* Do the pre-listening set-up for the file descriptors of this mode. */
|
|
|
|
|
{
|
1996-10-31 17:54:57 +00:00
|
|
|
|
Bag* fdInfo;
|
|
|
|
|
|
|
|
|
|
fdInfo = NSMapGet (_mode_2_fd_speakers, mode);
|
|
|
|
|
if (fdInfo) {
|
|
|
|
|
void* es = [fdInfo newEnumState];
|
|
|
|
|
id info;
|
|
|
|
|
|
|
|
|
|
while ((info=[fdInfo nextObjectWithEnumState: &es])!=NO_OBJECT) {
|
|
|
|
|
int fd = [info getFd];
|
|
|
|
|
|
|
|
|
|
FD_SET (fd, &write_fds);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSMapInsert (wfd_2_object, (void*)fd, [info getReceiver]);
|
|
|
|
|
num_inputs++;
|
1996-10-31 17:54:57 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[fdInfo freeEnumState: &es];
|
1996-10-31 17:54:57 +00:00
|
|
|
|
}
|
|
|
|
|
fdInfo = NSMapGet (_mode_2_fd_listeners, mode);
|
|
|
|
|
if (fdInfo) {
|
|
|
|
|
void* es = [fdInfo newEnumState];
|
|
|
|
|
id info;
|
|
|
|
|
|
|
|
|
|
while ((info=[fdInfo nextObjectWithEnumState: &es])!=NO_OBJECT) {
|
|
|
|
|
int fd = [info getFd];
|
|
|
|
|
|
|
|
|
|
FD_SET (fd, &fds);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSMapInsert (rfd_2_object, (void*)fd, [info getReceiver]);
|
|
|
|
|
num_inputs++;
|
1996-10-31 17:54:57 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[fdInfo freeEnumState: &es];
|
1996-10-31 17:54:57 +00:00
|
|
|
|
}
|
1996-03-18 19:32:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Do the pre-listening set-up for the ports of this mode. */
|
|
|
|
|
{
|
1996-10-31 17:54:57 +00:00
|
|
|
|
id ports = NSMapGet (_mode_2_in_ports, mode);
|
1996-03-18 19:32:45 +00:00
|
|
|
|
if (ports)
|
|
|
|
|
{
|
|
|
|
|
id port;
|
|
|
|
|
int i;
|
1996-10-31 17:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* If a port is invalid, remove it from this mode. */
|
|
|
|
|
for (i = [ports count]-1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
port = [ports objectAtIndex: i];
|
|
|
|
|
if (![port isValid])
|
|
|
|
|
[ports removeObjectAtIndex: i];
|
|
|
|
|
}
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
|
|
|
|
/* Ask our ports for the list of file descriptors they
|
1996-10-31 17:54:57 +00:00
|
|
|
|
want us to listen to; add these to FD_LISTEN_SET. */
|
1996-03-18 19:32:45 +00:00
|
|
|
|
for (i = [ports count]-1; i >= 0; i--)
|
|
|
|
|
{
|
1996-10-31 17:54:57 +00:00
|
|
|
|
int port_fd_count = 128; // xxx #define this constant
|
|
|
|
|
int port_fd_array[port_fd_count];
|
1996-03-18 19:32:45 +00:00
|
|
|
|
port = [ports objectAtIndex: i];
|
|
|
|
|
if ([port respondsTo: @selector(getFds:count:)])
|
1996-10-31 17:54:57 +00:00
|
|
|
|
[port getFds: port_fd_array count: &port_fd_count];
|
1996-03-19 00:59:05 +00:00
|
|
|
|
if (debug_run_loop)
|
1996-10-31 17:54:57 +00:00
|
|
|
|
printf("\tRunLoop listening to %d sockets\n", port_fd_count);
|
|
|
|
|
while (port_fd_count--)
|
1996-03-18 19:32:45 +00:00
|
|
|
|
{
|
1996-10-31 17:54:57 +00:00
|
|
|
|
FD_SET (port_fd_array[port_fd_count], &fds);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSMapInsert (rfd_2_object,
|
1996-10-31 17:54:57 +00:00
|
|
|
|
(void*)port_fd_array[port_fd_count], port);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
num_inputs++;
|
1996-03-18 19:32:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wait for incoming data, listening to the file descriptors in _FDS. */
|
|
|
|
|
read_fds = fds;
|
|
|
|
|
exception_fds = fds;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
/* Detect if the RunLoop is idle, and if necessary - dispatch the
|
|
|
|
|
notifications from NSNotificationQueue's idle queue? */
|
|
|
|
|
if (num_inputs == 0 && [NSNotificationQueue runLoopMore])
|
|
|
|
|
{
|
|
|
|
|
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,
|
1996-03-18 19:32:45 +00:00
|
|
|
|
select_timeout);
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
|
|
|
|
if (debug_run_loop)
|
1996-03-19 00:59:05 +00:00
|
|
|
|
printf ("\tRunLoop select returned %d\n", select_return);
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
|
|
|
|
if (select_return < 0)
|
|
|
|
|
{
|
1996-03-18 19:32:45 +00:00
|
|
|
|
/* Some exceptional condition happened. */
|
|
|
|
|
/* xxx We can do something with exception_fds, instead of
|
|
|
|
|
aborting here. */
|
1996-03-12 15:39:13 +00:00
|
|
|
|
perror ("[TcpInPort receivePacketWithTimeout:] select()");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
else if (select_return == 0)
|
1996-07-15 18:41:44 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSFreeMapTable (rfd_2_object);
|
|
|
|
|
NSFreeMapTable (wfd_2_object);
|
|
|
|
|
[NSNotificationQueue runLoopIdle];
|
|
|
|
|
[NSNotificationQueue runLoopASAP];
|
1997-01-06 22:21:02 +00:00
|
|
|
|
_current_mode = saved_mode;
|
1996-07-15 18:41:44 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
/* Look at all the file descriptors select() says are ready for reading;
|
1996-03-18 19:32:45 +00:00
|
|
|
|
notify the corresponding object for each of the ready fd's. */
|
1996-10-31 17:54:57 +00:00
|
|
|
|
for (fd_index = 0; fd_index < FD_SETSIZE; fd_index++)
|
|
|
|
|
{
|
|
|
|
|
if (FD_ISSET (fd_index, &write_fds))
|
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
id fd_object = (id) NSMapGet (wfd_2_object, (void*)fd_index);
|
1996-10-31 17:54:57 +00:00
|
|
|
|
assert (fd_object);
|
|
|
|
|
[fd_object readyForWritingOnFileDescriptor: fd_index];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[NSNotificationQueue runLoopASAP];
|
1996-10-31 17:54:57 +00:00
|
|
|
|
}
|
|
|
|
|
if (FD_ISSET (fd_index, &read_fds))
|
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
id fd_object = (id) NSMapGet (rfd_2_object, (void*)fd_index);
|
1996-10-31 17:54:57 +00:00
|
|
|
|
assert (fd_object);
|
|
|
|
|
[fd_object readyForReadingOnFileDescriptor: fd_index];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[NSNotificationQueue runLoopASAP];
|
1996-10-31 17:54:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1996-03-18 19:32:45 +00:00
|
|
|
|
/* Clean up before returning. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSFreeMapTable (rfd_2_object);
|
|
|
|
|
NSFreeMapTable (wfd_2_object);
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
_current_mode = saved_mode;
|
1996-03-12 15:39:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-13 17:52:31 +00:00
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
{
|
|
|
|
|
#if defined(__WIN32__) || defined(_WIN32)
|
|
|
|
|
[self acceptWIN32InputForMode: mode beforeDate: limit_date];
|
|
|
|
|
#else
|
|
|
|
|
[self acceptUNIXInputForMode: mode beforeDate: limit_date];
|
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
|
|
|
|
/* Running the run loop once through for timers and input listening. */
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- (BOOL) runOnceBeforeDate: date forMode: (NSString*)mode
|
1996-03-12 15:39:13 +00:00
|
|
|
|
{
|
|
|
|
|
id d;
|
|
|
|
|
|
|
|
|
|
/* If DATE is already later than now, just return. */
|
|
|
|
|
if ([date timeIntervalSinceNow] < 0)
|
|
|
|
|
{
|
|
|
|
|
if (debug_run_loop)
|
1996-03-19 00:59:05 +00:00
|
|
|
|
printf ("\tRunLoop run mode before date already past\n");
|
1996-03-12 15:39:13 +00:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find out how long we can wait; and fire timers that are ready. */
|
1996-03-18 19:32:45 +00:00
|
|
|
|
d = [self limitDateForMode: mode];
|
1996-03-12 15:39:13 +00:00
|
|
|
|
if (!d)
|
|
|
|
|
d = date;
|
|
|
|
|
|
|
|
|
|
/* Wait, listening to our input sources. */
|
|
|
|
|
[self acceptInputForMode: mode
|
|
|
|
|
beforeDate: d];
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:42:45 +00:00
|
|
|
|
- (BOOL) runOnceBeforeDate: date
|
|
|
|
|
{
|
1996-03-18 19:32:45 +00:00
|
|
|
|
return [self runOnceBeforeDate: date forMode: _current_mode];
|
1996-03-12 19:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
|
|
|
|
/* Running the run loop multiple times through. */
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- (void) runUntilDate: date forMode: (NSString*)mode
|
1996-03-12 15:39:13 +00:00
|
|
|
|
{
|
|
|
|
|
volatile double ti;
|
|
|
|
|
|
|
|
|
|
ti = [date timeIntervalSinceNow];
|
|
|
|
|
/* Positive values are in the future. */
|
|
|
|
|
while (ti > 0)
|
|
|
|
|
{
|
|
|
|
|
id arp = [NSAutoreleasePool new];
|
|
|
|
|
if (debug_run_loop)
|
1996-03-19 00:59:05 +00:00
|
|
|
|
printf ("\tRunLoop run until date %f seconds from now\n", ti);
|
1996-03-18 19:32:45 +00:00
|
|
|
|
[self runOnceBeforeDate: date forMode: mode];
|
1996-03-12 15:39:13 +00:00
|
|
|
|
[arp release];
|
|
|
|
|
ti = [date timeIntervalSinceNow];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
- (void) runUntilDate: date
|
|
|
|
|
{
|
|
|
|
|
[self runUntilDate: date forMode: _current_mode];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
- (void) run
|
|
|
|
|
{
|
|
|
|
|
[self runUntilDate: [NSDate distantFuture]];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
/* Class methods that send messages to the current instance. */
|
|
|
|
|
|
|
|
|
|
+ (void) run
|
|
|
|
|
{
|
|
|
|
|
assert (current_run_loop);
|
|
|
|
|
[current_run_loop run];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) runUntilDate: date
|
|
|
|
|
{
|
|
|
|
|
assert (current_run_loop);
|
|
|
|
|
[current_run_loop runUntilDate: date];
|
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
+ (void) runUntilDate: date forMode: (NSString*)mode
|
1996-03-18 19:32:45 +00:00
|
|
|
|
{
|
|
|
|
|
assert (current_run_loop);
|
|
|
|
|
[current_run_loop runUntilDate: date forMode: mode];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) runOnceBeforeDate: date
|
|
|
|
|
{
|
|
|
|
|
return [current_run_loop runOnceBeforeDate: date];
|
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
+ (BOOL) runOnceBeforeDate: date forMode: (NSString*)mode
|
1996-03-18 19:32:45 +00:00
|
|
|
|
{
|
|
|
|
|
return [current_run_loop runOnceBeforeDate: date forMode: mode];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
+ currentInstance
|
|
|
|
|
{
|
|
|
|
|
assert (current_run_loop);
|
|
|
|
|
return current_run_loop;
|
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
+ (NSString*) currentMode
|
1996-03-18 19:32:45 +00:00
|
|
|
|
{
|
|
|
|
|
return [current_run_loop currentMode];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
|
@end
|
|
|
|
|
|
1996-03-18 19:32:45 +00:00
|
|
|
|
|
|
|
|
|
/* NSObject method additions. */
|
1996-03-12 15:39:13 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSObject (PerformingAfterDelay)
|
|
|
|
|
|
|
|
|
|
- (void) performSelector: (SEL)sel afterDelay: (NSTimeInterval)delay
|
|
|
|
|
{
|
1996-03-18 19:32:45 +00:00
|
|
|
|
[self notImplemented: _cmd];
|
1996-03-12 15:39:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- getNotificationWithName: (NSString*)name
|
1996-03-12 15:39:13 +00:00
|
|
|
|
object: object
|
1996-11-24 17:30:39 +00:00
|
|
|
|
inMode: (NSString*)mode
|
1996-03-12 15:39:13 +00:00
|
|
|
|
beforeDate: date
|
|
|
|
|
{
|
|
|
|
|
/* See if any timers should fire, and fire them. */
|
|
|
|
|
|
|
|
|
|
/* Figure out how long we can listen to file descriptors before, either,
|
|
|
|
|
we need to fire another timer, or we need to return before DATE. */
|
|
|
|
|
|
|
|
|
|
/* Wait, listening to the file descriptors. */
|
|
|
|
|
|
|
|
|
|
/* Process active file descriptors. */
|
|
|
|
|
|
|
|
|
|
/* Is it time to return? If not, go back and check timers,
|
|
|
|
|
otherwise return. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Some alternate names */
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- waitForNotificationWithName: (NSString*)name
|
1996-03-12 15:39:13 +00:00
|
|
|
|
object: object
|
1996-11-24 17:30:39 +00:00
|
|
|
|
inMode: (NSString*)mode
|
1996-03-12 15:39:13 +00:00
|
|
|
|
untilDate: date
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The old alternate names */
|
|
|
|
|
- (void) makeNotificationsForFileDescriptor: (int)fd
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
name: (NSString*)name
|
1996-03-12 15:39:13 +00:00
|
|
|
|
object: object
|
|
|
|
|
postingTo: (id <NotificationPosting>)poster
|
|
|
|
|
postingStyle: style
|
|
|
|
|
- (void) addFileDescriptor: (int)fd
|
1996-11-24 17:30:39 +00:00
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
postingWithName: (NSString*)name
|
1996-03-12 15:39:13 +00:00
|
|
|
|
object: object;
|
|
|
|
|
- (void) addFileDescriptor: (int)fd
|
|
|
|
|
withAttender: (id <FileDescriptorAttending>)object
|
|
|
|
|
- (void) addObserver: observer
|
|
|
|
|
selector: (SEL)
|
|
|
|
|
ofName: fileDescriptorString
|
|
|
|
|
withAttender: (id <FileDescriptorAttending>)object
|
|
|
|
|
|
|
|
|
|
#endif
|
1996-10-31 17:54:57 +00:00
|
|
|
|
|