mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
Changes for NSStream support, especially in mingw32 ... not yet complete.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@22693 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
6ec821f364
commit
3d99e46faf
22 changed files with 1561 additions and 1863 deletions
38
ChangeLog
38
ChangeLog
|
@ -1,3 +1,41 @@
|
|||
2006-03-21 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/unix/GSRunLoopWatcher.m: deleted
|
||||
* Source/win32/GSRunLoopWatcher.m: deleted
|
||||
* Source/GSRunLoopWatcher.m: combine drom subdirectories.
|
||||
* Source/GNUmakefile:
|
||||
* Source/NSSocketPort.m:
|
||||
* Source/NSRunLoop.m:
|
||||
* Source/GSRunLoopWatcher.h:
|
||||
* Source/GSStream.h:
|
||||
* Source/GSStream.m:
|
||||
* Source/unix/GSRunLoopCtxt.m:
|
||||
* Source/unix/GNUmakefile:
|
||||
* Source/unix/NSStream.m:
|
||||
* Source/GSRunLoopCtxt.h:
|
||||
* Source/NSMessagePort.m:
|
||||
* Source/win32/GSRunLoopCtxt.m:
|
||||
* Source/win32/GNUmakefile:
|
||||
* Source/win32/NSStreamWin32.m:
|
||||
* Source/NSThread.m:
|
||||
* Source/GSFileHandle.m:
|
||||
* Headers/Foundation/NSRunLoop.h:
|
||||
* Headers/Additions/GNUstepBase/GSFileHandle.h:
|
||||
Remove timeout facility for runloop watchers ... can use standard
|
||||
timers instead. This simplifies api/code somewhat.
|
||||
Added new watcher type ET_TRIGGER to count as an input source for
|
||||
the runloop but work by polling rather than waiting for I/O events.
|
||||
This allows NSStream objects to be added to the runloop even if
|
||||
they don't do real I/O (eg memory streams).
|
||||
Added private internal API to allow watchers to adjust how the loop
|
||||
deals with them for each iteration... needed to simulate unix like
|
||||
level-triggered events on windows where events are edge triggered.
|
||||
Rewrote NSStream code to put handling of runloop scheduling in the
|
||||
abstract classes rather than repeat in every subclass.
|
||||
Rewrote NSStream stuff to use new runloop mechanisms to support
|
||||
memory and file streams in runloops.
|
||||
Implemented pipe base NSStream for windows.
|
||||
|
||||
2006-03-18 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Tools/AGSOutput.m: Get rid of bogus ' '
|
||||
|
|
|
@ -97,9 +97,6 @@
|
|||
extra: (void*)extra
|
||||
forMode: (NSString*)mode;
|
||||
- (void) setAddr: (struct sockaddr_in *)sin;
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
- (BOOL) useCompression;
|
||||
- (void) watchReadDescriptorForModes: (NSArray*)modes;
|
||||
- (void) watchWriteDescriptor;
|
||||
|
|
|
@ -118,26 +118,22 @@ typedef enum {
|
|||
ET_HANDLE, /* Watch for an I/O event on a handle. */
|
||||
ET_RPORT, /* Watch for message arriving on port. */
|
||||
ET_WINMSG, /* Watch for a message on a window handle. */
|
||||
ET_INSTREAM, /* Watch for event on input stream. */
|
||||
ET_OUTSTREAM /* Watch for event on output stream. */
|
||||
ET_TRIGGER /* Trigger immediately when the loop runs. */
|
||||
#else
|
||||
ET_RDESC, /* Watch for descriptor becoming readable. */
|
||||
ET_WDESC, /* Watch for descriptor becoming writeable. */
|
||||
ET_RPORT, /* Watch for message arriving on port. */
|
||||
ET_EDESC, /* Watch for descriptor with out-of-band data. */
|
||||
ET_INSTREAM, /* Watch for event on input stream. */
|
||||
ET_OUTSTREAM /* Watch for event on output stream. */
|
||||
ET_TRIGGER /* Trigger immediately when the loop runs. */
|
||||
#endif
|
||||
} RunLoopEventType;
|
||||
@protocol RunLoopEvents
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
- (void) receivedEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
extra: (void*)extra
|
||||
forMode: (NSString*)mode;
|
||||
@end
|
||||
@class NSStream;
|
||||
@interface NSRunLoop(GNUstepExtensions)
|
||||
- (void) addEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
#
|
||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
|
||||
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02111 USA.
|
||||
#
|
||||
|
||||
# Install into the system root by default
|
||||
|
@ -137,6 +138,7 @@ GSDictionary.m \
|
|||
GSFormat.m \
|
||||
GSFTPURLHandle.m \
|
||||
GSHTTPURLHandle.m \
|
||||
GSRunLoopWatcher.m \
|
||||
GSSet.m \
|
||||
GSStream.m \
|
||||
GSString.m \
|
||||
|
|
|
@ -2102,13 +2102,6 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
}
|
||||
}
|
||||
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return nil; /* Don't restart timed out events */
|
||||
}
|
||||
|
||||
- (void) setAddr: (struct sockaddr_in *)sin
|
||||
{
|
||||
address = [[NSString alloc] initWithCString: (char*)inet_ntoa(sin->sin_addr)];
|
||||
|
|
|
@ -48,8 +48,9 @@ typedef struct{
|
|||
NSMapTable *_efdMap;
|
||||
NSMapTable *_rfdMap;
|
||||
NSMapTable *_wfdMap;
|
||||
int fairStart; // For trying to ensure fair handling.
|
||||
#endif
|
||||
GSIArray _trigger; // Watchers to trigger unconditionally.
|
||||
int fairStart; // For trying to ensure fair handling.
|
||||
BOOL completed; // To mark operation as completed.
|
||||
#ifdef HAVE_POLL
|
||||
unsigned int pollfds_capacity;
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
*
|
||||
* The internal variables if the GSRunLoopWatcher are used as follows -
|
||||
*
|
||||
* 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
|
||||
* be removed from the runloop when next encountered.
|
||||
*
|
||||
* If 'checkBlocking' is set, the run loop should ask the watcher
|
||||
* whether it should block and/or trigger each loop iteration.
|
||||
*
|
||||
* The 'data' variable is used to identify the resource/event that the
|
||||
* watcher is interested in.
|
||||
* watcher is interested in. Its meaning is system dependent.
|
||||
*
|
||||
* The 'receiver' is the object which should be told when the event
|
||||
* occurs. This object is retained so that we know it will continue
|
||||
|
@ -27,10 +27,6 @@
|
|||
* NSRunLoops [-acceptInputForMode: beforeDate: ] method MUST contain
|
||||
* code to watch for events of each type.
|
||||
*
|
||||
* To set this variable, the method adding the GSRunLoopWatcher to the
|
||||
* runloop must ask the 'receiver' (or its delegate) to supply a date
|
||||
* using the '[-limitDateForMode: ]' message.
|
||||
*
|
||||
* NB. This class is private to NSRunLoop and must not be subclassed.
|
||||
*/
|
||||
|
||||
|
@ -40,14 +36,11 @@
|
|||
|
||||
@class NSDate;
|
||||
|
||||
extern SEL eventSel; /* Initialized in [NSRunLoop +initialize] */
|
||||
|
||||
@interface GSRunLoopWatcher: NSObject
|
||||
{
|
||||
@public
|
||||
NSDate *_date; /* First to match layout of NSTimer */
|
||||
BOOL _invalidated; /* 2nd to match layout of NSTimer */
|
||||
IMP handleEvent; /* New-style event handling */
|
||||
BOOL _invalidated;
|
||||
BOOL checkBlocking;
|
||||
void *data;
|
||||
id receiver;
|
||||
RunLoopEventType type;
|
||||
|
@ -56,21 +49,13 @@ extern SEL eventSel; /* Initialized in [NSRunLoop +initialize] */
|
|||
- (id) initWithType: (RunLoopEventType)type
|
||||
receiver: (id)anObj
|
||||
data: (void*)data;
|
||||
/**
|
||||
* Returns a boolean indicating whether the receiver needs the loop to
|
||||
* block to wait for input, or whether the loop can run through at once.
|
||||
* It also sets *trigger to say whether the receiver should be triggered
|
||||
* once the input test has been done or not.
|
||||
*/
|
||||
- (BOOL) runLoopShouldBlock: (BOOL*)trigger;
|
||||
@end
|
||||
|
||||
/*
|
||||
* Two optimisation functions that depend on a hack that the layout of
|
||||
* the NSTimer class is known to be the same as GSRunLoopWatcher for the
|
||||
* first two elements.
|
||||
*/
|
||||
static inline NSDate* timerDate(NSTimer* timer)
|
||||
{
|
||||
return ((GSRunLoopWatcher*)timer)->_date;
|
||||
}
|
||||
|
||||
static inline BOOL timerInvalidated(NSTimer* timer)
|
||||
{
|
||||
return ((GSRunLoopWatcher*)timer)->_invalidated;
|
||||
}
|
||||
|
||||
#endif /* __GSRunLoopWatcher_h_GNUSTEP_BASE_INCLUDE */
|
||||
|
|
69
Source/GSRunLoopWatcher.m
Normal file
69
Source/GSRunLoopWatcher.m
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "GSRunLoopWatcher.h"
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSPort.h>
|
||||
|
||||
@implementation GSRunLoopWatcher
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) initWithType: (RunLoopEventType)aType
|
||||
receiver: (id)anObj
|
||||
data: (void*)item
|
||||
{
|
||||
_invalidated = NO;
|
||||
receiver = anObj;
|
||||
data = item;
|
||||
switch (aType)
|
||||
{
|
||||
#if defined(__MINGW32__)
|
||||
case ET_HANDLE: type = aType; break;
|
||||
case ET_WINMSG: type = aType; break;
|
||||
#else
|
||||
case ET_EDESC: type = aType; break;
|
||||
case ET_RDESC: type = aType; break;
|
||||
case ET_WDESC: type = aType; break;
|
||||
#endif
|
||||
case ET_RPORT: type = aType; break;
|
||||
case ET_TRIGGER: type = aType; break;
|
||||
default:
|
||||
RELEASE(self);
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"NSRunLoop - unknown event type"];
|
||||
}
|
||||
|
||||
if ([anObj respondsToSelector: @selector(runLoopShouldBlock:)])
|
||||
{
|
||||
checkBlocking = YES;
|
||||
}
|
||||
|
||||
if (![anObj respondsToSelector: @selector(receivedEvent:type:extra:forMode:)])
|
||||
{
|
||||
RELEASE(self);
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"RunLoop listener has no event handling method"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL) runLoopShouldBlock: (BOOL*)trigger
|
||||
{
|
||||
if (checkBlocking == YES)
|
||||
{
|
||||
return [(id)receiver runLoopShouldBlock: trigger];
|
||||
}
|
||||
else if (type == ET_TRIGGER)
|
||||
{
|
||||
*trigger = YES;
|
||||
return NO; // By default triggers may fire immediately
|
||||
}
|
||||
*trigger = YES;
|
||||
return YES; // By default we must wait for input sources
|
||||
}
|
||||
@end
|
||||
|
|
@ -51,6 +51,17 @@
|
|||
*/
|
||||
|
||||
#include <Foundation/NSStream.h>
|
||||
#include <Foundation/NSRunLoop.h>
|
||||
|
||||
/**
|
||||
* Convenience methods used to add streams to the run loop.
|
||||
*/
|
||||
@interface NSRunLoop (NSStream)
|
||||
- (void) addStream: (NSStream*)aStream mode: (NSString*)mode;
|
||||
- (void) removeStream: (NSStream*)aStream mode: (NSString*)mode;
|
||||
@end
|
||||
|
||||
@class NSMutableData;
|
||||
|
||||
#define IVARS \
|
||||
{ \
|
||||
|
@ -61,7 +72,7 @@
|
|||
NSStreamStatus _currentStatus;/* current status */\
|
||||
NSMutableArray *_modes; /* currently scheduled modes. */\
|
||||
NSRunLoop *_runloop; /* currently scheduled loop. */\
|
||||
void *_fd; /* the file descriptor (if any) */\
|
||||
void *_loopID; /* file descriptor etc */\
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,28 +83,40 @@
|
|||
@interface GSStream : NSStream
|
||||
IVARS
|
||||
@end
|
||||
@interface GSStream(Private)
|
||||
|
||||
@interface NSStream(Private)
|
||||
|
||||
/**
|
||||
* Async notification
|
||||
*/
|
||||
- (void) _dispatch;
|
||||
|
||||
/**
|
||||
* Return YES if the stream is opened, NO otherwise.
|
||||
*/
|
||||
- (BOOL) _isOpened;
|
||||
|
||||
/**
|
||||
* Return previously set reference for IO in run loop.
|
||||
*/
|
||||
- (void*) _loopID;
|
||||
|
||||
/**
|
||||
* send an event to delegate
|
||||
*/
|
||||
- (void) _sendEvent: (NSStreamEvent)event;
|
||||
|
||||
/**
|
||||
* setter for IO event reference (file descriptor, file handle etc )
|
||||
*/
|
||||
- (void) _setLoopID: (void *)ref;
|
||||
|
||||
/**
|
||||
* set the status to newStatus. an exception is error cannot
|
||||
* be overwriten by closed
|
||||
*/
|
||||
- (void) _setStatus: (NSStreamStatus)newStatus;
|
||||
|
||||
/**
|
||||
* setter for fd
|
||||
*/
|
||||
- (void) _setFd: (void *)fd;
|
||||
|
||||
/**
|
||||
* record an error based on errno
|
||||
*/
|
||||
|
@ -103,35 +126,14 @@ IVARS
|
|||
@interface GSInputStream : NSInputStream
|
||||
IVARS
|
||||
@end
|
||||
@interface GSInputStream (Private)
|
||||
- (BOOL) _isOpened;
|
||||
- (void) _sendEvent: (NSStreamEvent)event;
|
||||
- (void) _setStatus: (NSStreamStatus)newStatus;
|
||||
- (void) _setFd: (void*)fd;
|
||||
- (void) _recordError;
|
||||
@end
|
||||
|
||||
@interface GSOutputStream : NSOutputStream
|
||||
IVARS
|
||||
@end
|
||||
@interface GSOutputStream (Private)
|
||||
- (BOOL) _isOpened;
|
||||
- (void) _sendEvent: (NSStreamEvent)event;
|
||||
- (void) _setStatus: (NSStreamStatus)newStatus;
|
||||
- (void) _setFd: (void*)fd;
|
||||
- (void) _recordError;
|
||||
@end
|
||||
|
||||
@interface GSAbstractServerStream : GSServerStream
|
||||
IVARS
|
||||
@end
|
||||
@interface GSAbstractServerStream (private)
|
||||
- (BOOL) _isOpened;
|
||||
- (void) _sendEvent: (NSStreamEvent)event;
|
||||
- (void) _setStatus: (NSStreamStatus)newStatus;
|
||||
- (void) _setFd: (void*)fd;
|
||||
- (void) _recordError;
|
||||
@end
|
||||
|
||||
/**
|
||||
* The concrete subclass of NSInputStream that reads from the memory
|
||||
|
|
|
@ -73,6 +73,61 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
= @"NSStreamSOCKSProxyVersionKey";
|
||||
|
||||
|
||||
/*
|
||||
* Determine the type of event to use when adding a stream to the run loop.
|
||||
* By default add as an 'ET_TRIGGER' so that the stream will be notified
|
||||
* every time the loop runs (the event id/reference must be the address of
|
||||
* the stream itsself to ensure that event/type is unique).
|
||||
*
|
||||
* Streams which actually expect to wait for I/O events must be added with
|
||||
* the appropriate information for the loop to signal them.
|
||||
*/
|
||||
static RunLoopEventType typeForStream(NSStream *aStream)
|
||||
{
|
||||
#if defined(__MINGW32__)
|
||||
if ([aStream _loopID] == (void*)aStream)
|
||||
{
|
||||
return ET_TRIGGER;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ET_HANDLE;
|
||||
}
|
||||
#else
|
||||
if ([aStream _loopID] == (void*)aStream)
|
||||
{
|
||||
return ET_TRIGGER;
|
||||
}
|
||||
else if ([aStream isKindOfClass: [NSOutputStream class]] == NO
|
||||
&& [aStream streamStatus] != NSStreamStatusOpening)
|
||||
{
|
||||
return ET_RDESC;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ET_WDESC;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@implementation NSRunLoop (NSStream)
|
||||
- (void) addStream: (NSStream*)aStream mode: (NSString*)mode
|
||||
{
|
||||
[self addEvent: [aStream _loopID]
|
||||
type: typeForStream(aStream)
|
||||
watcher: (id<RunLoopEvents>)aStream
|
||||
forMode: mode];
|
||||
}
|
||||
|
||||
- (void) removeStream: (NSStream*)aStream mode: (NSString*)mode
|
||||
{
|
||||
[self removeEvent: [aStream _loopID]
|
||||
type: typeForStream(aStream)
|
||||
forMode: mode
|
||||
all: NO];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSStream
|
||||
|
||||
- (void) close
|
||||
|
@ -80,11 +135,25 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
NSAssert(_currentStatus != NSStreamStatusNotOpen
|
||||
&& _currentStatus != NSStreamStatusClosed,
|
||||
@"Attempt to close a stream not yet opened.");
|
||||
if (_runloop)
|
||||
{
|
||||
unsigned i = [_modes count];
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
[_runloop removeStream: self mode: [_modes objectAtIndex: i]];
|
||||
}
|
||||
}
|
||||
[self _setStatus: NSStreamStatusClosed];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (_currentStatus != NSStreamStatusNotOpen
|
||||
&& _currentStatus != NSStreamStatusClosed)
|
||||
{
|
||||
[self close];
|
||||
}
|
||||
DESTROY(_runloop);
|
||||
DESTROY(_modes);
|
||||
DESTROY(_properties);
|
||||
|
@ -97,12 +166,83 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
return _delegate;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
{
|
||||
_delegate = self;
|
||||
_properties = nil;
|
||||
_lastError = nil;
|
||||
_modes = [NSMutableArray new];
|
||||
_currentStatus = NSStreamStatusNotOpen;
|
||||
_loopID = (void*)self;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) open
|
||||
{
|
||||
NSAssert(_currentStatus == NSStreamStatusNotOpen
|
||||
|| _currentStatus == NSStreamStatusOpening,
|
||||
@"Attempt to open a stream already opened.");
|
||||
[self _setStatus: NSStreamStatusOpen];
|
||||
if (_runloop)
|
||||
{
|
||||
unsigned i = [_modes count];
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
[_runloop addStream: self mode: [_modes objectAtIndex: i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (id) propertyForKey: (NSString *)key
|
||||
{
|
||||
return [_properties objectForKey: key];
|
||||
}
|
||||
|
||||
- (void) receivedEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
extra: (void*)extra
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
[self _dispatch];
|
||||
}
|
||||
|
||||
- (void) removeFromRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode
|
||||
{
|
||||
NSAssert(_runloop == aRunLoop,
|
||||
@"Attempt to remove unscheduled runloop");
|
||||
if ([_modes containsObject: mode])
|
||||
{
|
||||
if ([self _isOpened])
|
||||
{
|
||||
[_runloop removeStream: self mode: mode];
|
||||
}
|
||||
[_modes removeObject: mode];
|
||||
if ([_modes count] == 0)
|
||||
{
|
||||
DESTROY(_runloop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode
|
||||
{
|
||||
NSAssert(!_runloop || _runloop == aRunLoop,
|
||||
@"Attempt to schedule in more than one runloop.");
|
||||
ASSIGN(_runloop, aRunLoop);
|
||||
if ([_modes containsObject: mode] == NO)
|
||||
{
|
||||
mode = [mode copy];
|
||||
[_modes addObject: mode];
|
||||
RELEASE(mode);
|
||||
if ([self _isOpened])
|
||||
{
|
||||
[_runloop addStream: self mode: mode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setDelegate: (id)delegate
|
||||
|
@ -119,20 +259,6 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
= [_delegate respondsToSelector: @selector(stream:handleEvent:)];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]) != nil)
|
||||
{
|
||||
_delegate = self;
|
||||
_properties = nil;
|
||||
_lastError = nil;
|
||||
_modes = [NSMutableArray new];
|
||||
_currentStatus = NSStreamStatusNotOpen;
|
||||
_fd = (void*)-1; // any operation will fail
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL) setProperty: (id)property forKey: (NSString *)key
|
||||
{
|
||||
if (_properties == nil)
|
||||
|
@ -143,11 +269,6 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (id) propertyForKey: (NSString *)key
|
||||
{
|
||||
return [_properties objectForKey: key];
|
||||
}
|
||||
|
||||
- (NSError *) streamError
|
||||
{
|
||||
if (_currentStatus == NSStreamStatusError)
|
||||
|
@ -165,6 +286,40 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
@end
|
||||
|
||||
|
||||
@implementation NSStream (Private)
|
||||
|
||||
- (void) _dispatch
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL) _isOpened
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void*) _loopID
|
||||
{
|
||||
return (void*)self; // By default a stream is a TRIGGER event.
|
||||
}
|
||||
|
||||
- (void) _recordError
|
||||
{
|
||||
}
|
||||
|
||||
- (void) _sendEvent: (NSStreamEvent)event
|
||||
{
|
||||
}
|
||||
|
||||
- (void) _setLoopID: (void *)ref
|
||||
{
|
||||
}
|
||||
|
||||
- (void) _setStatus: (NSStreamStatus)newStatus
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSStream (Private)
|
||||
|
||||
- (BOOL) _isOpened
|
||||
|
@ -174,13 +329,22 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
|| _currentStatus == NSStreamStatusClosed);
|
||||
}
|
||||
|
||||
- (void*) _loopID
|
||||
{
|
||||
return _loopID;
|
||||
}
|
||||
|
||||
- (void) _recordError
|
||||
{
|
||||
// make an error
|
||||
NSError *theError = [NSError errorWithDomain: NSPOSIXErrorDomain
|
||||
NSError *theError;
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
errno = GetLastError();
|
||||
#endif
|
||||
theError = [NSError errorWithDomain: NSPOSIXErrorDomain
|
||||
code: errno
|
||||
userInfo: nil];
|
||||
NSLog(@"stream error: - %s", GSLastErrorStr(errno));
|
||||
NSLog(@"%@ error(%d): - %s", self, errno, GSLastErrorStr(errno));
|
||||
ASSIGN(_lastError, theError);
|
||||
_currentStatus = NSStreamStatusError;
|
||||
}
|
||||
|
@ -193,6 +357,11 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
}
|
||||
}
|
||||
|
||||
- (void) _setLoopID: (void *)ref
|
||||
{
|
||||
_loopID = ref;
|
||||
}
|
||||
|
||||
- (void) _setStatus: (NSStreamStatus)newStatus
|
||||
{
|
||||
// last error before closing is preserved
|
||||
|
@ -203,11 +372,6 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
}
|
||||
}
|
||||
|
||||
- (void) _setFd: (void *)fd
|
||||
{
|
||||
_fd = fd;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSInputStream
|
||||
|
@ -306,37 +470,6 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
return (dataSize > _pointer);
|
||||
}
|
||||
|
||||
- (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode
|
||||
{
|
||||
NSAssert(!_runloop || _runloop == aRunLoop,
|
||||
@"Attempt to schedule in more than one runloop.");
|
||||
ASSIGN(_runloop, aRunLoop);
|
||||
if (![_modes containsObject: mode])
|
||||
[_modes addObject: mode];
|
||||
if ([self _isOpened])
|
||||
[_runloop performSelector: @selector(_dispatch)
|
||||
target: self
|
||||
argument: nil
|
||||
order: 0
|
||||
modes: _modes];
|
||||
}
|
||||
|
||||
- (void) removeFromRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode
|
||||
{
|
||||
NSAssert(_runloop == aRunLoop,
|
||||
@"Attempt to remove unscheduled runloop");
|
||||
if ([_modes containsObject: mode])
|
||||
{
|
||||
[_modes removeObject: mode];
|
||||
if ([self _isOpened])
|
||||
[_runloop cancelPerformSelector: @selector(_dispatch)
|
||||
target: self
|
||||
argument: nil];
|
||||
if ([_modes count] == 0)
|
||||
DESTROY(_runloop);
|
||||
}
|
||||
}
|
||||
|
||||
- (id) propertyForKey: (NSString *)key
|
||||
{
|
||||
if ([key isEqualToString: NSStreamFileCurrentOffsetKey])
|
||||
|
@ -344,24 +477,6 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
return [super propertyForKey: key];
|
||||
}
|
||||
|
||||
- (void) open
|
||||
{
|
||||
[super open];
|
||||
if (_runloop)
|
||||
[_runloop performSelector: @selector(_dispatch)
|
||||
target: self
|
||||
argument: nil
|
||||
order: 0
|
||||
modes: _modes];
|
||||
}
|
||||
|
||||
- (void) close
|
||||
{
|
||||
if (_runloop)
|
||||
[_runloop cancelPerformSelectorsWithTarget: self];
|
||||
[super close];
|
||||
}
|
||||
|
||||
- (void) _dispatch
|
||||
{
|
||||
BOOL av = [self hasBytesAvailable];
|
||||
|
@ -372,15 +487,7 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
|
||||
[self _setStatus: myStatus];
|
||||
[self _sendEvent: myEvent];
|
||||
// dispatch again iff still opened, and last event is not eos
|
||||
if (av && [self _isOpened])
|
||||
{
|
||||
[_runloop performSelector: @selector(_dispatch)
|
||||
target: self
|
||||
argument: nil
|
||||
order: 0
|
||||
modes: _modes];
|
||||
}
|
||||
// FIXME should we remain in run loop if NSStreamStatusAtEnd?
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -439,37 +546,6 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode
|
||||
{
|
||||
NSAssert(!_runloop || _runloop == aRunLoop,
|
||||
@"Attempt to schedule in more than one runloop.");
|
||||
ASSIGN(_runloop, aRunLoop);
|
||||
if (![_modes containsObject: mode])
|
||||
[_modes addObject: mode];
|
||||
if ([self _isOpened])
|
||||
[_runloop performSelector: @selector(_dispatch)
|
||||
target: self
|
||||
argument: nil
|
||||
order: 0
|
||||
modes: _modes];
|
||||
}
|
||||
|
||||
- (void) removeFromRunLoop: (NSRunLoop *)aRunLoop forMode: (NSString *)mode
|
||||
{
|
||||
NSAssert(_runloop == aRunLoop,
|
||||
@"Attempt to remove unscheduled runloop");
|
||||
if ([_modes containsObject: mode])
|
||||
{
|
||||
[_modes removeObject: mode];
|
||||
if ([self _isOpened])
|
||||
[_runloop cancelPerformSelector: @selector(_dispatch)
|
||||
target: self
|
||||
argument: nil];
|
||||
if ([_modes count] == 0)
|
||||
DESTROY(_runloop);
|
||||
}
|
||||
}
|
||||
|
||||
- (id) propertyForKey: (NSString *)key
|
||||
{
|
||||
if ([key isEqualToString: NSStreamFileCurrentOffsetKey])
|
||||
|
@ -484,26 +560,6 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
return [super propertyForKey: key];
|
||||
}
|
||||
|
||||
- (void) open
|
||||
{
|
||||
[super open];
|
||||
if (_runloop)
|
||||
{
|
||||
[_runloop performSelector: @selector(_dispatch)
|
||||
target: self
|
||||
argument: nil
|
||||
order: 0
|
||||
modes: _modes];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) close
|
||||
{
|
||||
if (_runloop)
|
||||
[_runloop cancelPerformSelectorsWithTarget: self];
|
||||
[super close];
|
||||
}
|
||||
|
||||
- (void) _dispatch
|
||||
{
|
||||
BOOL av = [self hasSpaceAvailable];
|
||||
|
@ -511,20 +567,8 @@ NSString * const NSStreamSOCKSProxyVersionKey
|
|||
NSStreamEventEndEncountered;
|
||||
|
||||
[self _sendEvent: myEvent];
|
||||
// dispatch again iff still opened, and last event is not eos
|
||||
if (av && [self _isOpened])
|
||||
[_runloop performSelector: @selector(_dispatch)
|
||||
target: self
|
||||
argument: nil
|
||||
order: 0
|
||||
modes: _modes];
|
||||
// FIXME should we remain in run loop if NSStreamEventEndEncountered?
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -268,9 +268,6 @@ typedef enum {
|
|||
- (NSMessagePort*) sendPort;
|
||||
- (void) setState: (GSHandleState)s;
|
||||
- (GSHandleState) state;
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
@end
|
||||
|
||||
|
||||
|
@ -1097,13 +1094,6 @@ static Class runLoopClass;
|
|||
return state;
|
||||
}
|
||||
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
@ -1113,9 +1103,6 @@ static Class runLoopClass;
|
|||
type: (RunLoopEventType)type
|
||||
extra: (void*)extra
|
||||
forMode: (NSString*)mode;
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
@end
|
||||
|
||||
|
||||
|
@ -1930,14 +1917,6 @@ typedef struct {
|
|||
return sent;
|
||||
}
|
||||
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (const unsigned char *) _name
|
||||
{
|
||||
return [name bytes];
|
||||
|
|
|
@ -39,10 +39,12 @@
|
|||
#include "Foundation/NSTimer.h"
|
||||
#include "Foundation/NSNotificationQueue.h"
|
||||
#include "Foundation/NSRunLoop.h"
|
||||
#include "Foundation/NSStream.h"
|
||||
#include "Foundation/NSThread.h"
|
||||
#include "Foundation/NSDebug.h"
|
||||
#include "GSRunLoopCtxt.h"
|
||||
#include "GSRunLoopWatcher.h"
|
||||
#include "GSStream.h"
|
||||
#include "GSPrivate.h"
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
|
@ -231,10 +233,22 @@ extern BOOL GSCheckTasks();
|
|||
#include "GNUstepBase/GSIArray.h"
|
||||
#endif
|
||||
|
||||
static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
|
||||
typedef struct {
|
||||
@defs(NSTimer)
|
||||
} *tvars;
|
||||
|
||||
static inline NSDate *timerDate(NSTimer *t)
|
||||
{
|
||||
return [((GSRunLoopWatcher *)(i0.obj))->_date
|
||||
compare: ((GSRunLoopWatcher *)(i1.obj))->_date];
|
||||
return ((tvars)t)->_date;
|
||||
}
|
||||
static inline BOOL timerInvalidated(NSTimer *t)
|
||||
{
|
||||
return ((tvars)t)->_invalidated;
|
||||
}
|
||||
|
||||
static NSComparisonResult tSort(GSIArrayItem i0, GSIArrayItem i1)
|
||||
{
|
||||
return [timerDate(i0.obj) compare: timerDate(i1.obj)];
|
||||
}
|
||||
|
||||
|
||||
|
@ -377,7 +391,6 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
|
|||
{
|
||||
GSRunLoopCtxt *context;
|
||||
GSIArray watchers;
|
||||
id obj;
|
||||
|
||||
context = NSMapGet(_contextMap, mode);
|
||||
if (context == nil)
|
||||
|
@ -387,38 +400,7 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1)
|
|||
RELEASE(context);
|
||||
}
|
||||
watchers = context->watchers;
|
||||
|
||||
/*
|
||||
* If the receiver or its delegate (if any) respond to
|
||||
* 'limitDateForMode: ' then we ask them for the limit date for
|
||||
* this watcher.
|
||||
*/
|
||||
obj = item->receiver;
|
||||
if ([obj respondsToSelector: @selector(limitDateForMode:)])
|
||||
{
|
||||
NSDate *d = [obj limitDateForMode: mode];
|
||||
|
||||
item->_date = RETAIN(d);
|
||||
}
|
||||
else if ([obj respondsToSelector: @selector(delegate)])
|
||||
{
|
||||
obj = [obj delegate];
|
||||
if (obj != nil && [obj respondsToSelector: @selector(limitDateForMode:)])
|
||||
{
|
||||
NSDate *d = [obj limitDateForMode: mode];
|
||||
|
||||
item->_date = RETAIN(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
item->_date = RETAIN(theFuture);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item->_date = RETAIN(theFuture);
|
||||
}
|
||||
GSIArrayInsertSorted(watchers, (GSIArrayItem)((id)item), aSort);
|
||||
GSIArrayAddItem(watchers, (GSIArrayItem)((id)item));
|
||||
}
|
||||
|
||||
- (void) _checkPerformers: (GSRunLoopCtxt*)context
|
||||
|
@ -677,7 +659,6 @@ extern IMP wRetImp;
|
|||
{
|
||||
[self currentRunLoop];
|
||||
theFuture = RETAIN([NSDate distantFuture]);
|
||||
eventSel = @selector(receivedEvent:type:extra:forMode:);
|
||||
#if GS_WITH_GC == 0
|
||||
wRelSel = @selector(release);
|
||||
wRetSel = @selector(retain);
|
||||
|
@ -769,7 +750,7 @@ extern IMP wRetImp;
|
|||
RELEASE(context);
|
||||
}
|
||||
timers = context->timers;
|
||||
GSIArrayInsertSorted(timers, (GSIArrayItem)((id)timer), aSort);
|
||||
GSIArrayInsertSorted(timers, (GSIArrayItem)((id)timer), tSort);
|
||||
}
|
||||
|
||||
|
||||
|
@ -786,7 +767,6 @@ extern IMP wRetImp;
|
|||
context = NSMapGet(_contextMap, mode);
|
||||
if (context != nil)
|
||||
{
|
||||
GSRunLoopWatcher *min_watcher = nil;
|
||||
NSString *savedMode = _currentMode;
|
||||
CREATE_AUTORELEASE_POOL(arp);
|
||||
|
||||
|
@ -795,7 +775,6 @@ extern IMP wRetImp;
|
|||
{
|
||||
extern NSTimeInterval GSTimeNow(void);
|
||||
GSIArray timers = context->timers;
|
||||
GSIArray watchers = context->watchers;
|
||||
NSTimeInterval now;
|
||||
NSTimer *t;
|
||||
|
||||
|
@ -845,7 +824,7 @@ extern IMP wRetImp;
|
|||
if (timerInvalidated(min_timer) == NO)
|
||||
{
|
||||
GSIArrayInsertSortedNoRetain(timers,
|
||||
(GSIArrayItem)((id)min_timer), aSort);
|
||||
(GSIArrayItem)((id)min_timer), tSort);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -853,76 +832,6 @@ extern IMP wRetImp;
|
|||
}
|
||||
GSNotifyASAP(); /* Post notifications. */
|
||||
}
|
||||
|
||||
while (GSIArrayCount(watchers) != 0)
|
||||
{
|
||||
min_watcher = GSIArrayItemAtIndex(watchers, 0).obj;
|
||||
|
||||
if (min_watcher->_invalidated == YES)
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(watchers, 0);
|
||||
min_watcher = nil;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([min_watcher->_date timeIntervalSinceReferenceDate] > now)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
id obj;
|
||||
NSDate *nxt = nil;
|
||||
|
||||
/*
|
||||
* If the receiver or its delegate wants to know about
|
||||
* timeouts - inform it and give it a chance to set a
|
||||
* revised limit date.
|
||||
*/
|
||||
GSIArrayRemoveItemAtIndexNoRelease(watchers, 0);
|
||||
obj = min_watcher->receiver;
|
||||
if ([obj respondsToSelector:
|
||||
@selector(timedOutEvent:type:forMode:)])
|
||||
{
|
||||
nxt = [obj timedOutEvent: min_watcher->data
|
||||
type: min_watcher->type
|
||||
forMode: mode];
|
||||
now = GSTimeNow();
|
||||
}
|
||||
else if ([obj respondsToSelector: @selector(delegate)])
|
||||
{
|
||||
obj = [obj delegate];
|
||||
if (obj != nil && [obj respondsToSelector:
|
||||
@selector(timedOutEvent:type:forMode:)])
|
||||
{
|
||||
nxt = [obj timedOutEvent: min_watcher->data
|
||||
type: min_watcher->type
|
||||
forMode: mode];
|
||||
now = GSTimeNow();
|
||||
}
|
||||
}
|
||||
if (nxt && [nxt timeIntervalSinceReferenceDate] > now)
|
||||
{
|
||||
/*
|
||||
* If the watcher has been given a revised limit date -
|
||||
* re-insert it into the queue in the correct place.
|
||||
*/
|
||||
ASSIGN(min_watcher->_date, nxt);
|
||||
GSIArrayInsertSortedNoRetain(watchers,
|
||||
(GSIArrayItem)((id)min_watcher), aSort);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If the watcher is now useless - invalidate and
|
||||
* release it.
|
||||
*/
|
||||
min_watcher->_invalidated = YES;
|
||||
RELEASE(min_watcher);
|
||||
}
|
||||
min_watcher = nil;
|
||||
}
|
||||
}
|
||||
_currentMode = savedMode;
|
||||
}
|
||||
NS_HANDLER
|
||||
|
@ -934,33 +843,28 @@ extern IMP wRetImp;
|
|||
|
||||
RELEASE(arp);
|
||||
|
||||
/*
|
||||
* If there are timers, when is already set to the limit date of the
|
||||
* earliest of them (and retained!).
|
||||
* 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).
|
||||
*/
|
||||
if (when != nil)
|
||||
{
|
||||
if (min_watcher != nil
|
||||
&& [min_watcher->_date compare: when] == NSOrderedAscending)
|
||||
{
|
||||
RELEASE(when);
|
||||
when = min_watcher->_date;
|
||||
}
|
||||
else
|
||||
{
|
||||
AUTORELEASE(when);
|
||||
}
|
||||
}
|
||||
else if (min_watcher != nil)
|
||||
{
|
||||
when = min_watcher->_date;
|
||||
AUTORELEASE(when);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil; /* Nothing waiting to be done. */
|
||||
{
|
||||
GSIArray watchers = context->watchers;
|
||||
unsigned i = GSIArrayCount(watchers);
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *w = GSIArrayItemAtIndex(watchers, i).obj;
|
||||
|
||||
if (w->_invalidated == YES)
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(watchers, i);
|
||||
}
|
||||
}
|
||||
if (GSIArrayCount(context->watchers) > 0)
|
||||
{
|
||||
when = theFuture;
|
||||
}
|
||||
}
|
||||
|
||||
NSDebugMLLog(@"NSRunLoop", @"limit date %f",
|
||||
|
|
|
@ -239,9 +239,6 @@ typedef enum {
|
|||
- (NSSocketPort*) sendPort;
|
||||
- (void) setState: (GSHandleState)s;
|
||||
- (GSHandleState) state;
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
@end
|
||||
|
||||
|
||||
|
@ -1462,13 +1459,6 @@ static Class runLoopClass;
|
|||
return state;
|
||||
}
|
||||
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
@ -1478,9 +1468,6 @@ static Class runLoopClass;
|
|||
type: (RunLoopEventType)type
|
||||
extra: (void*)extra
|
||||
forMode: (NSString*)mode;
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
@end
|
||||
|
||||
@implementation NSSocketPort
|
||||
|
@ -2463,11 +2450,4 @@ static Class tcpPortClass;
|
|||
return sent;
|
||||
}
|
||||
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -101,9 +101,6 @@ static NSNotificationCenter *nc = nil;
|
|||
type: (RunLoopEventType)type
|
||||
extra: (void*)extra
|
||||
forMode: (NSString*)mode;
|
||||
+ (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode;
|
||||
- (void) fire;
|
||||
@end
|
||||
|
||||
|
@ -946,13 +943,6 @@ static NSDate *theFuture;
|
|||
RELEASE(toDo);
|
||||
}
|
||||
|
||||
+ (NSDate*) timedOutEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return theFuture;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
DESTROY(receiver);
|
||||
|
|
|
@ -31,7 +31,6 @@ SUBPROJECT_NAME = unix
|
|||
|
||||
unix_OBJC_FILES = \
|
||||
GSRunLoopCtxt.m \
|
||||
GSRunLoopWatcher.m \
|
||||
NSStream.m
|
||||
|
||||
-include Makefile.preamble
|
||||
|
|
|
@ -30,10 +30,6 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
@interface NSStream (RunLoop)
|
||||
- (int) _fileDescriptor;
|
||||
@end
|
||||
|
||||
extern BOOL GSCheckTasks();
|
||||
|
||||
#if GS_WITH_GC == 0
|
||||
|
@ -86,6 +82,8 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
{
|
||||
NSFreeMapTable(_wfdMap);
|
||||
}
|
||||
GSIArrayEmpty(_trigger);
|
||||
NSZoneFree(_trigger->zone, (void*)_trigger);
|
||||
#ifdef HAVE_POLL_F
|
||||
if (pollfds != 0)
|
||||
{
|
||||
|
@ -119,14 +117,23 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
case ET_EDESC:
|
||||
NSMapRemove(_efdMap, data);
|
||||
break;
|
||||
case ET_INSTREAM:
|
||||
NSMapRemove(_rfdMap, data);
|
||||
break;
|
||||
case ET_OUTSTREAM:
|
||||
NSMapRemove(_wfdMap, data);
|
||||
case ET_TRIGGER:
|
||||
{
|
||||
unsigned i = GSIArrayCount(_trigger);
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSIArrayItem item = GSIArrayItemAtIndex(_trigger, i);
|
||||
|
||||
if (item.obj == (id)data)
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(_trigger, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Ending an event of unkown type (%d)", type);
|
||||
NSLog(@"Ending an event of unexpected type (%d)", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +179,8 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
WatcherMapValueCallBacks, 0);
|
||||
_wfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
|
||||
WatcherMapValueCallBacks, 0);
|
||||
_trigger = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity(_trigger, z, 8);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -235,7 +244,9 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
int fdEnd; /* Number of descriptors being monitored. */
|
||||
int fdIndex;
|
||||
int fdFinish;
|
||||
unsigned count;
|
||||
unsigned int i;
|
||||
BOOL immediate = NO;
|
||||
|
||||
i = GSIArrayCount(watchers);
|
||||
|
||||
|
@ -246,6 +257,7 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
NSResetMapTable(_efdMap);
|
||||
NSResetMapTable(_rfdMap);
|
||||
NSResetMapTable(_wfdMap);
|
||||
GSIArrayRemoveAllItems(_trigger);
|
||||
|
||||
/*
|
||||
* Do the pre-listening set-up for the file descriptors of this mode.
|
||||
|
@ -268,84 +280,72 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *info;
|
||||
int fd;
|
||||
BOOL trigger;
|
||||
|
||||
info = GSIArrayItemAtIndex(watchers, i).obj;
|
||||
if (info->_invalidated == YES)
|
||||
{
|
||||
continue;
|
||||
GSIArrayRemoveItemAtIndex(watchers, i);
|
||||
}
|
||||
|
||||
switch (info->type)
|
||||
else if ([info runLoopShouldBlock: &trigger] == NO)
|
||||
{
|
||||
case ET_EDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
setPollfd(fd, POLLPRI, self);
|
||||
NSMapInsert(_efdMap, (void*)(intptr_t)fd, info);
|
||||
break;
|
||||
if (trigger == YES)
|
||||
{
|
||||
immediate = YES;
|
||||
GSIArrayAddItem(_trigger, (GSIArrayItem)(id)info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int fd;
|
||||
|
||||
case ET_RDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
setPollfd(fd, POLLIN, self);
|
||||
NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
|
||||
break;
|
||||
switch (info->type)
|
||||
{
|
||||
case ET_EDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
setPollfd(fd, POLLPRI, self);
|
||||
NSMapInsert(_efdMap, (void*)(intptr_t)fd, info);
|
||||
break;
|
||||
|
||||
case ET_WDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
setPollfd(fd, POLLOUT, self);
|
||||
NSMapInsert(_wfdMap, (void*)(intptr_t)fd, info);
|
||||
break;
|
||||
|
||||
case ET_INSTREAM:
|
||||
fd = [(NSStream*)info->data _fileDescriptor];
|
||||
if (fd >= 0)
|
||||
{
|
||||
setPollfd(fd, POLLOUT, self);
|
||||
case ET_RDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
setPollfd(fd, POLLIN, self);
|
||||
NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case ET_OUTSTREAM:
|
||||
fd = [(NSStream*)info->data _fileDescriptor];
|
||||
if (fd >= 0)
|
||||
{
|
||||
case ET_WDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
setPollfd(fd, POLLOUT, self);
|
||||
NSMapInsert(_wfdMap, (void*)(intptr_t)fd, info);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case ET_RPORT:
|
||||
if ([info->receiver isValid] == NO)
|
||||
{
|
||||
/*
|
||||
* We must remove an invalidated port.
|
||||
*/
|
||||
info->_invalidated = YES;
|
||||
GSIArrayRemoveItemAtIndex(watchers, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
id port = info->receiver;
|
||||
int port_fd_count = 128; // FIXME
|
||||
int port_fd_array[port_fd_count];
|
||||
case ET_TRIGGER:
|
||||
break;
|
||||
|
||||
if ([port respondsToSelector:
|
||||
@selector(getFds:count:)])
|
||||
{
|
||||
[port getFds: port_fd_array
|
||||
count: &port_fd_count];
|
||||
}
|
||||
NSDebugMLLog(@"NSRunLoop",
|
||||
@"listening to %d port handles\n", port_fd_count);
|
||||
while (port_fd_count--)
|
||||
{
|
||||
fd = port_fd_array[port_fd_count];
|
||||
setPollfd(fd, POLLIN, self);
|
||||
NSMapInsert(_rfdMap,
|
||||
(void*)(intptr_t)port_fd_array[port_fd_count], info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ET_RPORT:
|
||||
{
|
||||
id port = info->receiver;
|
||||
int port_fd_count = 128; // FIXME
|
||||
int port_fd_array[port_fd_count];
|
||||
|
||||
if ([port respondsToSelector:
|
||||
@selector(getFds:count:)])
|
||||
{
|
||||
[port getFds: port_fd_array
|
||||
count: &port_fd_count];
|
||||
}
|
||||
NSDebugMLLog(@"NSRunLoop",
|
||||
@"listening to %d port handles\n", port_fd_count);
|
||||
while (port_fd_count--)
|
||||
{
|
||||
fd = port_fd_array[port_fd_count];
|
||||
setPollfd(fd, POLLIN, self);
|
||||
NSMapInsert(_rfdMap,
|
||||
(void*)(intptr_t)port_fd_array[port_fd_count], info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +355,7 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
* we can service the queue. Similarly, if a task has completed,
|
||||
* we need to deliver its notifications.
|
||||
*/
|
||||
if (GSCheckTasks() || GSNotifyMore())
|
||||
if (GSCheckTasks() || GSNotifyMore() || immediate == YES)
|
||||
{
|
||||
milliseconds = 0;
|
||||
}
|
||||
|
@ -369,7 +369,14 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
poll_return = poll (pollfds, pollfds_count, milliseconds);
|
||||
if (pollfds_count > 0)
|
||||
{
|
||||
poll_return = poll (pollfds, pollfds_count, milliseconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
poll_return = 0;
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -405,6 +412,42 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger any watchers which are set up to for every runloop wait.
|
||||
*/
|
||||
count = GSIArrayCount(_trigger);
|
||||
while (completed == NO && count-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)GSIArrayItemAtIndex(_trigger, count).obj;
|
||||
if (watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self)
|
||||
{
|
||||
[c endEvent: (void*)watcher type: ET_TRIGGER];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The watcher is still valid - so call its
|
||||
* receivers event handling method.
|
||||
*/
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: watcher->data
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
}
|
||||
|
||||
/*
|
||||
* If the poll returned no descriptors with events, we have no more to do.
|
||||
*/
|
||||
if (poll_return == 0)
|
||||
{
|
||||
completed = YES;
|
||||
|
@ -469,9 +512,10 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
* The watcher is still valid - so call its
|
||||
* receivers event handling method.
|
||||
*/
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)fd, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: (void*)(uintptr_t)fd
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
|
@ -500,9 +544,10 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
* The watcher is still valid - so call its
|
||||
* receivers event handling method.
|
||||
*/
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)fd, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: (void*)(uintptr_t)fd
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
|
@ -531,9 +576,10 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
* The watcher is still valid - so call its
|
||||
* receivers event handling method.
|
||||
*/
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)fd, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: (void*)(uintptr_t)fd
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
|
@ -572,9 +618,10 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
fd_set read_fds; // Mask for read-ready fds.
|
||||
fd_set exception_fds; // Mask for exception fds.
|
||||
fd_set write_fds; // Mask for write-ready fds.
|
||||
int num_inputs = 0;
|
||||
int fdEnd = -1;
|
||||
unsigned count;
|
||||
unsigned i;
|
||||
BOOL immediate = NO;
|
||||
|
||||
i = GSIArrayCount(watchers);
|
||||
|
||||
|
@ -613,107 +660,85 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
NSResetMapTable(_efdMap);
|
||||
NSResetMapTable(_rfdMap);
|
||||
NSResetMapTable(_wfdMap);
|
||||
GSIArrayRemoveAllItems(_trigger);
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *info;
|
||||
int fd;
|
||||
BOOL trigger;
|
||||
|
||||
info = GSIArrayItemAtIndex(watchers, i).obj;
|
||||
if (info->_invalidated == YES)
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(watchers, i);
|
||||
continue;
|
||||
}
|
||||
switch (info->type)
|
||||
else if ([info runLoopShouldBlock: &trigger] == NO)
|
||||
{
|
||||
case ET_EDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &exception_fds);
|
||||
NSMapInsert(_efdMap, (void*)(intptr_t)fd, info);
|
||||
num_inputs++;
|
||||
break;
|
||||
if (trigger == YES)
|
||||
{
|
||||
immediate = YES;
|
||||
GSIArrayAddItem(_trigger, (GSIArrayItem)(id)info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (info->type)
|
||||
{
|
||||
case ET_EDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &exception_fds);
|
||||
NSMapInsert(_efdMap, (void*)(intptr_t)fd, info);
|
||||
break;
|
||||
|
||||
case ET_RDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &read_fds);
|
||||
NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
|
||||
num_inputs++;
|
||||
break;
|
||||
|
||||
case ET_WDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &write_fds);
|
||||
NSMapInsert(_wfdMap, (void*)(intptr_t)fd, info);
|
||||
num_inputs++;
|
||||
break;
|
||||
|
||||
case ET_RPORT:
|
||||
if ([info->receiver isValid] == NO)
|
||||
{
|
||||
/*
|
||||
* We must remove an invalidated port.
|
||||
*/
|
||||
info->_invalidated = YES;
|
||||
GSIArrayRemoveItemAtIndex(watchers, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
id port = info->receiver;
|
||||
int port_fd_count = 128; // xxx #define this constant
|
||||
int port_fd_array[port_fd_count];
|
||||
|
||||
if ([port respondsToSelector:
|
||||
@selector(getFds:count:)])
|
||||
{
|
||||
[port getFds: port_fd_array
|
||||
count: &port_fd_count];
|
||||
}
|
||||
NSDebugMLLog(@"NSRunLoop", @"listening to %d port sockets",
|
||||
port_fd_count);
|
||||
while (port_fd_count--)
|
||||
{
|
||||
fd = port_fd_array[port_fd_count];
|
||||
FD_SET (port_fd_array[port_fd_count], &read_fds);
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
NSMapInsert(_rfdMap,
|
||||
(void*)(intptr_t)port_fd_array[port_fd_count], info);
|
||||
num_inputs++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ET_INSTREAM:
|
||||
fd = [(NSStream*)info->data _fileDescriptor];
|
||||
if (fd >= 0)
|
||||
{
|
||||
case ET_RDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &read_fds);
|
||||
NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
|
||||
}
|
||||
num_inputs++;
|
||||
break;
|
||||
break;
|
||||
|
||||
case ET_OUTSTREAM:
|
||||
fd = [(NSStream*)info->data _fileDescriptor];
|
||||
if (fd >= 0)
|
||||
{
|
||||
case ET_WDESC:
|
||||
fd = (int)(intptr_t)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &read_fds);
|
||||
FD_SET (fd, &write_fds);
|
||||
NSMapInsert(_wfdMap, (void*)(intptr_t)fd, info);
|
||||
}
|
||||
num_inputs++;
|
||||
break;
|
||||
break;
|
||||
|
||||
case ET_RPORT:
|
||||
{
|
||||
id port = info->receiver;
|
||||
int port_fd_count = 128; // xxx #define this constant
|
||||
int port_fd_array[port_fd_count];
|
||||
|
||||
if ([port respondsToSelector:
|
||||
@selector(getFds:count:)])
|
||||
{
|
||||
[port getFds: port_fd_array
|
||||
count: &port_fd_count];
|
||||
}
|
||||
NSDebugMLLog(@"NSRunLoop", @"listening to %d port sockets",
|
||||
port_fd_count);
|
||||
while (port_fd_count--)
|
||||
{
|
||||
fd = port_fd_array[port_fd_count];
|
||||
FD_SET (port_fd_array[port_fd_count], &read_fds);
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
NSMapInsert(_rfdMap,
|
||||
(void*)(intptr_t)port_fd_array[port_fd_count], info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ET_TRIGGER:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
fdEnd++;
|
||||
|
@ -724,7 +749,7 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
* we can service the queue. Similarly, if a task has completed,
|
||||
* we need to deliver its notifications.
|
||||
*/
|
||||
if (GSCheckTasks() || GSNotifyMore())
|
||||
if (GSCheckTasks() || GSNotifyMore() || immediate == YES)
|
||||
{
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
|
@ -733,8 +758,15 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
|
||||
// NSDebugMLLog(@"NSRunLoop", @"select timeout %d,%d", timeout.tv_sec, timeout.tv_usec);
|
||||
|
||||
select_return = select (fdEnd, &read_fds, &write_fds,
|
||||
&exception_fds, select_timeout);
|
||||
if (fdEnd >= 0)
|
||||
{
|
||||
select_return = select (fdEnd, &read_fds, &write_fds,
|
||||
&exception_fds, select_timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
select_return = 0;
|
||||
}
|
||||
|
||||
NSDebugMLLog(@"NSRunLoop", @"select returned %d", select_return);
|
||||
|
||||
|
@ -760,6 +792,43 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger any watchers which are set up to for every runloop wait.
|
||||
*/
|
||||
count = GSIArrayCount(_trigger);
|
||||
while (completed == NO && count-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)GSIArrayItemAtIndex(_trigger, count).obj;
|
||||
if (watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self)
|
||||
{
|
||||
[c endEvent: (void*)watcher type: ET_TRIGGER];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The watcher is still valid - so call its
|
||||
* receivers event handling method.
|
||||
*/
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: watcher->data
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
}
|
||||
|
||||
/*
|
||||
* If the select returned no descriptors with events, we have no more to do.
|
||||
*/
|
||||
if (select_return == 0)
|
||||
{
|
||||
completed = YES;
|
||||
|
@ -794,7 +863,8 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_efdMap, (void*)fdIndex);
|
||||
watcher
|
||||
= (GSRunLoopWatcher*)NSMapGet(_efdMap, (void*)(intptr_t)fdIndex);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
|
@ -802,15 +872,17 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)fdIndex type: ET_EDESC];
|
||||
if (c != self)
|
||||
[c endEvent: (void*)(intptr_t)fdIndex type: ET_EDESC];
|
||||
}
|
||||
/*
|
||||
* The watcher is still valid - so call its receivers
|
||||
* event handling method.
|
||||
*/
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)fdIndex, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: watcher->data
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
|
@ -823,7 +895,8 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_wfdMap, (void*)fdIndex);
|
||||
watcher
|
||||
= (GSRunLoopWatcher*)NSMapGet(_wfdMap, (void*)(intptr_t)fdIndex);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
|
@ -831,15 +904,17 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)fdIndex type: ET_WDESC];
|
||||
if (c != self)
|
||||
[c endEvent: (void*)(intptr_t)fdIndex type: ET_WDESC];
|
||||
}
|
||||
/*
|
||||
* The watcher is still valid - so call its receivers
|
||||
* event handling method.
|
||||
*/
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)fdIndex, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: watcher->data
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
|
@ -852,7 +927,8 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_rfdMap, (void*)fdIndex);
|
||||
watcher
|
||||
= (GSRunLoopWatcher*)NSMapGet(_rfdMap, (void*)(intptr_t)fdIndex);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
|
@ -860,15 +936,17 @@ static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
|||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)fdIndex type: ET_RDESC];
|
||||
if (c != self)
|
||||
[c endEvent: (void*)(intptr_t)fdIndex type: ET_RDESC];
|
||||
}
|
||||
/*
|
||||
* The watcher is still valid - so call its receivers
|
||||
* event handling method.
|
||||
*/
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)fdIndex, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: watcher->data
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "../GSRunLoopWatcher.h"
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSPort.h>
|
||||
|
||||
SEL eventSel; /* Initialized in [NSRunLoop +initialize] */
|
||||
|
||||
@implementation GSRunLoopWatcher
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_date);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) initWithType: (RunLoopEventType)aType
|
||||
receiver: (id)anObj
|
||||
data: (void*)item
|
||||
{
|
||||
_invalidated = NO;
|
||||
|
||||
switch (aType)
|
||||
{
|
||||
case ET_EDESC: type = aType; break;
|
||||
case ET_RDESC: type = aType; break;
|
||||
case ET_WDESC: type = aType; break;
|
||||
case ET_RPORT: type = aType; break;
|
||||
default:
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"NSRunLoop - unknown event type"];
|
||||
}
|
||||
receiver = anObj;
|
||||
if ([receiver respondsToSelector: eventSel] == YES)
|
||||
handleEvent = [receiver methodForSelector: eventSel];
|
||||
else
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"RunLoop listener has no event handling method"];
|
||||
data = item;
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -32,7 +32,6 @@ SUBPROJECT_NAME = win32
|
|||
win32_OBJC_FILES =\
|
||||
GSFileHandleWin32.m \
|
||||
GSRunLoopCtxt.m \
|
||||
GSRunLoopWatcher.m \
|
||||
NSMessagePortWin32.m \
|
||||
NSMessagePortNameServerWin32.m \
|
||||
NSStreamWin32.m \
|
||||
|
|
|
@ -19,10 +19,6 @@
|
|||
|
||||
extern BOOL GSCheckTasks();
|
||||
|
||||
@interface NSStream (RunLoop)
|
||||
- (HANDLE) _handle;
|
||||
@end
|
||||
|
||||
#if GS_WITH_GC == 0
|
||||
SEL wRelSel;
|
||||
SEL wRetSel;
|
||||
|
@ -69,6 +65,8 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
{
|
||||
NSFreeMapTable(winMsgMap);
|
||||
}
|
||||
GSIArrayEmpty(_trigger);
|
||||
NSZoneFree(_trigger->zone, (void*)_trigger);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -88,15 +86,28 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
switch (type)
|
||||
{
|
||||
case ET_HANDLE:
|
||||
NSMapRemove(handleMap, data);
|
||||
break;
|
||||
case ET_WINMSG:
|
||||
NSMapRemove(winMsgMap, data);
|
||||
break;
|
||||
case ET_INSTREAM:
|
||||
break;
|
||||
case ET_OUTSTREAM:
|
||||
case ET_TRIGGER:
|
||||
{
|
||||
unsigned i = GSIArrayCount(_trigger);
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSIArrayItem item = GSIArrayItemAtIndex(_trigger, i);
|
||||
|
||||
if (item.obj == (id)data)
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(_trigger, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Ending an event of unkown type (%d)", type);
|
||||
NSLog(@"Ending an event of unexpected type (%d)", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -140,6 +151,8 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
WatcherMapValueCallBacks, 0);
|
||||
winMsgMap = NSCreateMapTable(NSIntMapKeyCallBacks,
|
||||
WatcherMapValueCallBacks, 0);
|
||||
_trigger = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity(_trigger, z, 8);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -192,15 +205,15 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
[c endEvent: (void*)handle type: ET_WINMSG];
|
||||
}
|
||||
}
|
||||
completed = YES;
|
||||
handled = YES;
|
||||
/*
|
||||
* The watcher is still valid - so call the
|
||||
* receiver's event handling method.
|
||||
*/
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)&msg, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: (void*)&msg
|
||||
forMode: mode];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -234,18 +247,17 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
[c endEvent: (void*)handle type: ET_WINMSG];
|
||||
}
|
||||
}
|
||||
completed = YES;
|
||||
handled = YES;
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)&msg, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: (void*)&msg
|
||||
forMode: mode];
|
||||
}
|
||||
}
|
||||
num--;
|
||||
}
|
||||
NSEndMapTableEnumeration(&hEnum);
|
||||
}
|
||||
completed = YES;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
@ -257,10 +269,12 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
HANDLE handleArray[MAXIMUM_WAIT_OBJECTS-1];
|
||||
int num_handles;
|
||||
int num_winMsgs;
|
||||
unsigned count;
|
||||
unsigned i;
|
||||
void *handle;
|
||||
int wait_timeout;
|
||||
DWORD wait_return;
|
||||
BOOL immediate = NO;
|
||||
|
||||
// Set timeout how much time should wait
|
||||
if (milliseconds >= 0)
|
||||
|
@ -274,6 +288,7 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
|
||||
NSResetMapTable(handleMap);
|
||||
NSResetMapTable(winMsgMap);
|
||||
GSIArrayRemoveAllItems(_trigger);
|
||||
|
||||
i = GSIArrayCount(watchers);
|
||||
num_handles = 0;
|
||||
|
@ -281,66 +296,65 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *info;
|
||||
HANDLE handle;
|
||||
BOOL trigger;
|
||||
|
||||
info = GSIArrayItemAtIndex(watchers, i).obj;
|
||||
if (info->_invalidated == YES)
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(watchers, i);
|
||||
continue;
|
||||
}
|
||||
switch (info->type)
|
||||
else if ([info runLoopShouldBlock: &trigger] == NO)
|
||||
{
|
||||
case ET_HANDLE:
|
||||
handle = (HANDLE)(int)info->data;
|
||||
NSMapInsert(handleMap, (void*)handle, info);
|
||||
num_handles++;
|
||||
break;
|
||||
case ET_RPORT:
|
||||
if (trigger == YES)
|
||||
{
|
||||
id port = info->receiver;
|
||||
int port_handle_count = 128; // #define this constant
|
||||
int port_handle_array[port_handle_count];
|
||||
if ([port respondsToSelector: @selector(getFds:count:)])
|
||||
{
|
||||
[port getFds: port_handle_array count: &port_handle_count];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"pollUntil - Impossible get win32 Handles");
|
||||
abort();
|
||||
}
|
||||
NSDebugMLLog(@"NSRunLoop", @"listening to %d port handles",
|
||||
port_handle_count);
|
||||
while (port_handle_count--)
|
||||
immediate = YES;
|
||||
GSIArrayAddItem(_trigger, (GSIArrayItem)(id)info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE handle;
|
||||
|
||||
switch (info->type)
|
||||
{
|
||||
case ET_HANDLE:
|
||||
handle = (HANDLE)(int)info->data;
|
||||
NSMapInsert(handleMap, (void*)handle, info);
|
||||
num_handles++;
|
||||
break;
|
||||
case ET_RPORT:
|
||||
{
|
||||
NSMapInsert(handleMap,
|
||||
(void*)port_handle_array[port_handle_count], info);
|
||||
num_handles++;
|
||||
id port = info->receiver;
|
||||
int port_handle_count = 128; // #define this constant
|
||||
int port_handle_array[port_handle_count];
|
||||
if ([port respondsToSelector: @selector(getFds:count:)])
|
||||
{
|
||||
[port getFds: port_handle_array
|
||||
count: &port_handle_count];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"pollUntil - Impossible get win32 Handles");
|
||||
abort();
|
||||
}
|
||||
NSDebugMLLog(@"NSRunLoop", @"listening to %d port handles",
|
||||
port_handle_count);
|
||||
while (port_handle_count--)
|
||||
{
|
||||
NSMapInsert(handleMap,
|
||||
(void*)port_handle_array[port_handle_count], info);
|
||||
num_handles++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ET_WINMSG:
|
||||
handle = (HANDLE)(int)info->data;
|
||||
NSMapInsert(winMsgMap, (void*)handle, info);
|
||||
num_winMsgs++;
|
||||
break;
|
||||
case ET_INSTREAM:
|
||||
handle = [(NSStream*)info->data _handle];
|
||||
if (handle != 0)
|
||||
{
|
||||
NSMapInsert(handleMap, (void*)handle, info);
|
||||
num_handles++;
|
||||
}
|
||||
break;
|
||||
case ET_OUTSTREAM:
|
||||
handle = [(NSStream*)info->data _handle];
|
||||
if (handle != 0)
|
||||
{
|
||||
NSMapInsert(handleMap, (void*)handle, info);
|
||||
num_handles++;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case ET_WINMSG:
|
||||
handle = (HANDLE)(int)info->data;
|
||||
NSMapInsert(winMsgMap, (void*)handle, info);
|
||||
num_winMsgs++;
|
||||
break;
|
||||
case ET_TRIGGER:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,7 +364,7 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
* we can service the queue. Similarly, if a task has completed,
|
||||
* we need to deliver its notifications.
|
||||
*/
|
||||
if (GSCheckTasks() || GSNotifyMore())
|
||||
if (GSCheckTasks() || GSNotifyMore() || immediate == YES)
|
||||
{
|
||||
wait_timeout = 0;
|
||||
}
|
||||
|
@ -388,7 +402,7 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
wait_return = MsgWaitForMultipleObjects(num_handles, handleArray,
|
||||
NO, wait_timeout, QS_ALLINPUT);
|
||||
}
|
||||
else
|
||||
else if (num_handles > 0)
|
||||
{
|
||||
/*
|
||||
* We are not interested in windows messages ... just wait for
|
||||
|
@ -397,14 +411,11 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
wait_return = WaitForMultipleObjects(num_handles, handleArray,
|
||||
NO, wait_timeout);
|
||||
}
|
||||
NSDebugMLLog(@"NSRunLoop", @"wait returned %d", wait_return);
|
||||
|
||||
// if there are windows message
|
||||
if (wait_return == WAIT_OBJECT_0 + num_handles)
|
||||
else
|
||||
{
|
||||
[self processAllWindowsMessages: num_winMsgs within: contexts];
|
||||
return NO;
|
||||
wait_return = WAIT_OBJECT_0;
|
||||
}
|
||||
NSDebugMLLog(@"NSRunLoop", @"wait returned %d", wait_return);
|
||||
|
||||
// check wait errors
|
||||
if (wait_return == WAIT_FAILED)
|
||||
|
@ -441,6 +452,47 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger any watchers which are set up to for every runloop wait.
|
||||
*/
|
||||
count = GSIArrayCount(_trigger);
|
||||
completed = NO;
|
||||
while (completed == NO && count-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)GSIArrayItemAtIndex(_trigger, count).obj;
|
||||
if (watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self)
|
||||
{
|
||||
[c endEvent: (void*)watcher type: ET_TRIGGER];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The watcher is still valid - so call its
|
||||
* receivers event handling method.
|
||||
*/
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: watcher->data
|
||||
forMode: mode];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
}
|
||||
|
||||
// if there are windows message
|
||||
if (wait_return == WAIT_OBJECT_0 + num_handles)
|
||||
{
|
||||
[self processAllWindowsMessages: num_winMsgs within: contexts];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// if there arent events
|
||||
if (wait_return == WAIT_TIMEOUT)
|
||||
{
|
||||
|
@ -477,9 +529,10 @@ static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
|||
* event handling method.
|
||||
*/
|
||||
NSDebugMLLog(@"NSRunLoop", @"Event callback found");
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(uintptr_t)handle, mode);
|
||||
[watcher->receiver receivedEvent: watcher->data
|
||||
type: watcher->type
|
||||
extra: watcher->data
|
||||
forMode: mode];
|
||||
}
|
||||
|
||||
GSNotifyASAP();
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "../GSRunLoopWatcher.h"
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSPort.h>
|
||||
|
||||
SEL eventSel; /* Initialized in [NSRunLoop +initialize] */
|
||||
|
||||
@implementation GSRunLoopWatcher
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_date);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) initWithType: (RunLoopEventType)aType
|
||||
receiver: (id)anObj
|
||||
data: (void*)item
|
||||
{
|
||||
_invalidated = NO;
|
||||
|
||||
switch (aType)
|
||||
{
|
||||
case ET_RPORT: type = aType; break;
|
||||
case ET_HANDLE: type = aType; break;
|
||||
case ET_WINMSG: type = aType; break;
|
||||
case ET_INSTREAM: type = aType; break;
|
||||
case ET_OUTSTREAM: type = aType; break;
|
||||
default:
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"NSRunLoop - unknown event type"];
|
||||
}
|
||||
receiver = anObj;
|
||||
if ([receiver respondsToSelector: eventSel] == YES)
|
||||
handleEvent = [receiver methodForSelector: eventSel];
|
||||
else
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"RunLoop listener has no event handling method"];
|
||||
data = item;
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue