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

@ -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 '&nbsp;'

View file

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

View file

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

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