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:
Richard Frith-MacDonald 2006-03-21 15:33:05 +00:00
parent 6ec821f364
commit 3d99e46faf
22 changed files with 1561 additions and 1863 deletions

View file

@ -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 \

View file

@ -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)];

View file

@ -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;

View file

@ -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
View 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

View file

@ -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

View file

@ -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

View file

@ -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];

View file

@ -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",

View file

@ -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

View file

@ -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);

View file

@ -31,7 +31,6 @@ SUBPROJECT_NAME = unix
unix_OBJC_FILES = \
GSRunLoopCtxt.m \
GSRunLoopWatcher.m \
NSStream.m
-include Makefile.preamble

View file

@ -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)

View file

@ -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

View file

@ -32,7 +32,6 @@ SUBPROJECT_NAME = win32
win32_OBJC_FILES =\
GSFileHandleWin32.m \
GSRunLoopCtxt.m \
GSRunLoopWatcher.m \
NSMessagePortWin32.m \
NSMessagePortNameServerWin32.m \
NSStreamWin32.m \

View file

@ -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();

View file

@ -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