mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Apply modified patch to support windows native event handling
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@20785 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
0e7313bb94
commit
2a9f4ec7c0
24 changed files with 2735 additions and 1640 deletions
29
ChangeLog
29
ChangeLog
|
@ -1,3 +1,32 @@
|
|||
2005-02-23 14:00 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Headers/Additions/GNUstepBase/GSFileHandle.h: Add windows event
|
||||
* Headers/Foundation/NSPort.h:
|
||||
* Headers/Foundation/NSRunLoop.h:
|
||||
* Source/GNUmakefile:
|
||||
* Source/GSFileHandle.m:
|
||||
* Source/GSLocale.m:
|
||||
* Source/NSMessagePort.m:
|
||||
* Source/NSPipe.m:
|
||||
* Source/NSRunLoop.m:
|
||||
* Source/NSSocketPort.m:
|
||||
* Source/NSThread.m:
|
||||
* Source/NSUser.m:
|
||||
* Source/unix/GNUmakefile:
|
||||
* Source/unix/GSRunLoopCtxt.m:
|
||||
* Source/unix/GSRunLoopWatcher.m:
|
||||
* Source/unix/Makefile.preamble:
|
||||
* Source/win32/GNUmakefile:
|
||||
* Source/win32/GSRunLoopCtxt.m:
|
||||
* Source/win32/GSRunLoopWatcher.m:
|
||||
* Source/win32/Makefile.preamble:
|
||||
* Source/win32/NSRunLoopWin32.m:
|
||||
Applied patch by Luis Cabellos to use native win32 event handling
|
||||
rather than unix style select/poll on a win32 system.
|
||||
Rewrote various chunks to simplify, conform to coding standards,
|
||||
work for me etc. In particular, replaced code for thread
|
||||
synchronisation to use win32 Event rather than pipe.
|
||||
|
||||
2005-02-22 14:00 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Documentation/Base.gsdoc:
|
||||
|
|
|
@ -58,6 +58,9 @@
|
|||
#if USE_ZLIB
|
||||
gzFile gzDescriptor;
|
||||
#endif
|
||||
#ifdef __MINGW32__
|
||||
WSAEVENT event;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id) initAsClientAtAddress: (NSString*)address
|
||||
|
|
|
@ -160,18 +160,6 @@ GS_EXPORT NSString * const NSPortTimeoutException; /* OPENSTEP */
|
|||
#endif
|
||||
@end
|
||||
|
||||
#ifndef NO_GNUSTEP
|
||||
/**
|
||||
* Stubs for backward compatibility. Do not use.
|
||||
*/
|
||||
@interface NSPort (GNUstep)
|
||||
//PENDING: none of this is implemented.. should it be removed?
|
||||
- (void) close;
|
||||
+ (Class) outPacketClass;
|
||||
- (Class) outPacketClass;
|
||||
@end
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Notification posted when an instance of [NSPort] or a subclass becomes
|
||||
* invalid.
|
||||
|
@ -204,7 +192,15 @@ typedef SOCKET NSSocketNativeHandle;
|
|||
NSString *address; /* Forced internet address. */
|
||||
gsu16 portNum; /* TCP port in host byte order. */
|
||||
SOCKET listener;
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
WSAEVENT listenerWin;
|
||||
NSMapTable *handlesWin;
|
||||
#endif
|
||||
NSMapTable *handles; /* Handles indexed by socket. */
|
||||
#ifdef __MINGW32__
|
||||
WSAEVENT eventListener;
|
||||
NSMapTable *events;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -325,6 +321,10 @@ typedef SOCKET NSSocketNativeHandle;
|
|||
NSRecursiveLock *myLock;
|
||||
NSMapTable *handles; /* Handles indexed by socket. */
|
||||
int listener; /* Descriptor to listen on. */
|
||||
#ifdef __MINGW32__
|
||||
WSAEVENT eventListener;
|
||||
NSMapTable *events;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (int) _listener;
|
||||
|
|
|
@ -108,10 +108,14 @@ GS_EXPORT NSString * const NSDefaultRunLoopMode;
|
|||
</example>
|
||||
*/
|
||||
typedef enum {
|
||||
#ifdef __MINGW__
|
||||
ET_HANDLE,
|
||||
#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_EDESC, /* Watch for descriptor with out-of-band data. */
|
||||
#endif
|
||||
ET_RPORT /* Watch for message arriving on port. */
|
||||
} RunLoopEventType;
|
||||
|
||||
/**
|
||||
|
@ -194,4 +198,25 @@ typedef enum {
|
|||
- (void) getFds: (int*)fds count: (int*)count;
|
||||
@end
|
||||
|
||||
#ifdef __MINGW32__
|
||||
/**
|
||||
* Interface that add method to set target for win32 messages.<br />
|
||||
*/
|
||||
@interface NSRunLoop(mingw32)
|
||||
/**
|
||||
* Adds a target to the loop in the specified mode for the
|
||||
* win32 messages.<br />
|
||||
* Only a target+selector is added in one mode. Successive
|
||||
* calls overwrite the previous.<br />
|
||||
*/
|
||||
- (void) addMsgTarget: (id)target
|
||||
withMethod: (SEL)selector
|
||||
forMode: (NSString*)mode;
|
||||
/**
|
||||
* Delete the target of the loop in the specified mode for the
|
||||
* win32 messages.<br />
|
||||
*/
|
||||
- (void) removeMsgForMode: (NSString*)mode;
|
||||
@end
|
||||
#endif
|
||||
#endif /*__NSRunLoop_h_GNUSTEP_BASE_INCLUDE */
|
||||
|
|
|
@ -40,8 +40,10 @@
|
|||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "GNUstepBase/GSCategories.h"
|
||||
|
||||
|
||||
#ifdef HAVE_LIBXML
|
||||
|
||||
// #undef HAVE_LIBXML_SAX2_H
|
||||
|
@ -86,8 +88,6 @@
|
|||
#include <libxslt/xsltutils.h>
|
||||
#endif /* HAVE_LIBXSLT */
|
||||
|
||||
extern int xmlGetWarningsDefaultValue;
|
||||
|
||||
/*
|
||||
* optimization
|
||||
*
|
||||
|
|
|
@ -50,6 +50,14 @@ endif
|
|||
libgnustep-base_SUBPROJECTS=Additions
|
||||
libgnustep-baseadd_SUBPROJECTS=Additions
|
||||
|
||||
ifeq ($(GNUSTEP_TARGET_OS), mingw32)
|
||||
libgnustep-base_SUBPROJECTS+=win32
|
||||
libgnustep-baseadd_SUBPROJECTS+=win32
|
||||
else
|
||||
libgnustep-base_SUBPROJECTS+=unix
|
||||
libgnustep-baseadd_SUBPROJECTS+=unix
|
||||
endif
|
||||
|
||||
# GNUSTEP_INSTALL_PREFIX must be defined here and not in config.h because
|
||||
# the installing person may set it on the `make' command line.
|
||||
|
||||
|
@ -125,7 +133,9 @@ Unicode.h \
|
|||
GNUstep.h \
|
||||
behavior.h \
|
||||
preface.h \
|
||||
objc-gnu2next.h
|
||||
objc-gnu2next.h \
|
||||
GSRunLoopCtxt.h \
|
||||
GSRunLoopWatcher.h
|
||||
|
||||
GNU_HEADERS = $(ADD_HEADERS)
|
||||
|
||||
|
@ -226,7 +236,7 @@ NSValue.m \
|
|||
NSXMLParser.m \
|
||||
NSZone.m \
|
||||
externs.m \
|
||||
objc-load.m
|
||||
objc-load.m
|
||||
|
||||
ifneq ($(GNUSTEP_TARGET_OS), mingw32)
|
||||
BASE_MFILES += \
|
||||
|
|
|
@ -109,6 +109,11 @@ static GSFileHandle* fh_stderr = nil;
|
|||
// Key to info dictionary for operation mode.
|
||||
static NSString* NotificationKey = @"NSFileHandleNotificationKey";
|
||||
|
||||
@interface GSFileHandle(private)
|
||||
- (void) receivedEventRead;
|
||||
- (void) receivedEventWrite;
|
||||
@end
|
||||
|
||||
@implementation GSFileHandle
|
||||
|
||||
/**
|
||||
|
@ -299,6 +304,8 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
if (isSocket)
|
||||
{
|
||||
closesocket((SOCKET)_get_osfhandle(descriptor));
|
||||
WSACloseEvent(event);
|
||||
event = WSA_INVALID_EVENT;
|
||||
}
|
||||
#endif
|
||||
close(descriptor);
|
||||
|
@ -1221,6 +1228,22 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
writeOK = YES;
|
||||
acceptOK = YES;
|
||||
connectOK = YES;
|
||||
#ifdef __MINGW32__
|
||||
if (isSocket)
|
||||
{
|
||||
event = CreateEvent(NULL, NO, NO, NULL);
|
||||
if (event == WSA_INVALID_EVENT)
|
||||
{
|
||||
NSLog(@"Invalid Event - '%d'", WSAGetLastError());
|
||||
return nil;
|
||||
}
|
||||
WSAEventSelect(_get_osfhandle(descriptor), event, FD_ALL_EVENTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
event = WSA_INVALID_EVENT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -1492,7 +1515,12 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
rval = [self write: (char*)ptr+pos length: toWrite];
|
||||
if (rval < 0)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
if (WSAGetLastError()== WSAEINTR ||
|
||||
WSAGetLastError()== WSAEWOULDBLOCK)
|
||||
#else
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
#endif
|
||||
{
|
||||
rval = 0;
|
||||
}
|
||||
|
@ -1702,6 +1730,8 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
if (isSocket)
|
||||
{
|
||||
(void)closesocket((SOCKET)_get_osfhandle(descriptor));
|
||||
WSACloseEvent(event);
|
||||
event = WSA_INVALID_EVENT;
|
||||
}
|
||||
#endif
|
||||
(void)close(descriptor);
|
||||
|
@ -1796,6 +1826,10 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
modes = (NSArray*)[info objectForKey: NSFileHandleNotificationMonitorModes];
|
||||
name = (NSString*)[info objectForKey: NotificationKey];
|
||||
|
||||
if (name == nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
n = [NSNotification notificationWithName: name object: self userInfo: info];
|
||||
|
||||
RELEASE(info); /* Retained by the notification. */
|
||||
|
@ -1877,9 +1911,9 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
|
||||
for (i = 0; i < [modes count]; i++)
|
||||
{
|
||||
#if defined(__MINGW__)
|
||||
[l removeEvent: (void*)(gsaddr)(SOCKET)_get_osfhandle(descriptor)
|
||||
type: ET_RDESC
|
||||
#ifdef __MINGW32__
|
||||
[l removeEvent: (void*)(gsaddr)event
|
||||
type: ET_HANDLE
|
||||
forMode: [modes objectAtIndex: i]
|
||||
all: YES];
|
||||
#else
|
||||
|
@ -1892,11 +1926,11 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined(__MINGW__)
|
||||
[l removeEvent: (void*)(gsaddr)(SOCKET)_get_osfhandle(descriptor)
|
||||
type: ET_RDESC
|
||||
#ifdef __MINGW32__
|
||||
[l removeEvent: (void*)(gsaddr)event
|
||||
type: ET_HANDLE
|
||||
forMode: NSDefaultRunLoopMode
|
||||
all: YES];
|
||||
all: YES];
|
||||
#else
|
||||
[l removeEvent: (void*)(gsaddr)descriptor
|
||||
type: ET_RDESC
|
||||
|
@ -1931,11 +1965,11 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
|
||||
for (i = 0; i < [modes count]; i++)
|
||||
{
|
||||
#if defined(__MINGW__)
|
||||
[l removeEvent: (void*)(gsaddr)(SOCKET)_get_osfhandle(descriptor)
|
||||
type: ET_WDESC
|
||||
forMode: [modes objectAtIndex: i]
|
||||
all: YES];
|
||||
#ifdef __MINGW32__
|
||||
[l removeEvent: (void*)(gsaddr)event
|
||||
type: ET_HANDLE
|
||||
forMode: [modes objectAtIndex: i]
|
||||
all: YES];
|
||||
#else
|
||||
[l removeEvent: (void*)(gsaddr)descriptor
|
||||
type: ET_WDESC
|
||||
|
@ -1946,11 +1980,11 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined(__MINGW__)
|
||||
[l removeEvent: (void*)(gsaddr)(SOCKET)_get_osfhandle(descriptor)
|
||||
type: ET_WDESC
|
||||
#ifdef __MINGW32__
|
||||
[l removeEvent: (void*)(gsaddr)event
|
||||
type: ET_HANDLE
|
||||
forMode: NSDefaultRunLoopMode
|
||||
all: YES];
|
||||
all: YES];
|
||||
#else
|
||||
[l removeEvent: (void*)(gsaddr)descriptor
|
||||
type: ET_WDESC
|
||||
|
@ -1968,6 +2002,7 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
l = [NSRunLoop currentRunLoop];
|
||||
[self setNonBlocking: YES];
|
||||
if (modes && [modes count])
|
||||
|
@ -1976,9 +2011,9 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
|
||||
for (i = 0; i < [modes count]; i++)
|
||||
{
|
||||
#if defined(__MINGW__)
|
||||
[l addEvent: (void*)(gsaddr)(SOCKET)_get_osfhandle(descriptor)
|
||||
type: ET_RDESC
|
||||
#ifdef __MINGW32__
|
||||
[l addEvent: (void*)(gsaddr)event
|
||||
type: ET_HANDLE
|
||||
watcher: self
|
||||
forMode: [modes objectAtIndex: i]];
|
||||
#else
|
||||
|
@ -1992,9 +2027,9 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined(__MINGW__)
|
||||
[l addEvent: (void*)(gsaddr)(SOCKET)_get_osfhandle(descriptor)
|
||||
type: ET_RDESC
|
||||
#ifdef __MINGW32__
|
||||
[l addEvent: (void*)(gsaddr)event
|
||||
type: ET_HANDLE
|
||||
watcher: self
|
||||
forMode: NSDefaultRunLoopMode];
|
||||
#else
|
||||
|
@ -2027,9 +2062,9 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
|
||||
for (i = 0; i < [modes count]; i++)
|
||||
{
|
||||
#if defined(__MINGW__)
|
||||
[l addEvent: (void*)(gsaddr)(SOCKET)_get_osfhandle(descriptor)
|
||||
type: ET_WDESC
|
||||
#ifdef __MINGW32__
|
||||
[l addEvent: (void*)(gsaddr)event
|
||||
type: ET_HANDLE
|
||||
watcher: self
|
||||
forMode: [modes objectAtIndex: i]];
|
||||
#else
|
||||
|
@ -2042,9 +2077,9 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined(__MINGW__)
|
||||
[l addEvent: (void*)(gsaddr)(SOCKET)_get_osfhandle(descriptor)
|
||||
type: ET_WDESC
|
||||
#ifdef __MINGW32__
|
||||
[l addEvent: (void*)(gsaddr)event
|
||||
type: ET_HANDLE
|
||||
watcher: self
|
||||
forMode: NSDefaultRunLoopMode];
|
||||
#else
|
||||
|
@ -2057,12 +2092,205 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
}
|
||||
}
|
||||
|
||||
- (void) receivedEventRead
|
||||
{
|
||||
NSString *operation;
|
||||
|
||||
operation = [readInfo objectForKey: NotificationKey];
|
||||
if (operation == NSFileHandleConnectionAcceptedNotification)
|
||||
{
|
||||
struct sockaddr_in buf;
|
||||
#if defined(__MINGW__)
|
||||
SOCKET desc;
|
||||
#else
|
||||
int desc;
|
||||
#endif
|
||||
int blen = sizeof(buf);
|
||||
|
||||
#if defined(__MINGW__)
|
||||
desc = accept((SOCKET)_get_osfhandle(descriptor), (struct sockaddr*)&buf, &blen);
|
||||
#else
|
||||
desc = accept(descriptor, (struct sockaddr*)&buf, &blen);
|
||||
#endif
|
||||
if (desc == INVALID_SOCKET)
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat: @"Accept attempt failed - %s",
|
||||
GSLastErrorStr(errno)];
|
||||
[readInfo setObject: s forKey: GSFileHandleNotificationError];
|
||||
}
|
||||
else
|
||||
{ // Accept attempt completed.
|
||||
GSFileHandle *h;
|
||||
struct sockaddr_in sin;
|
||||
int size = sizeof(sin);
|
||||
|
||||
#if defined(__MINGW__)
|
||||
h = [[[self class] alloc] initWithNativeHandle: (void*)desc
|
||||
closeOnDealloc: YES];
|
||||
#else
|
||||
h = [[[self class] alloc] initWithFileDescriptor: desc
|
||||
closeOnDealloc: YES];
|
||||
#endif
|
||||
h->isSocket = YES;
|
||||
getpeername(desc, (struct sockaddr*)&sin, &size);
|
||||
[h setAddr: &sin];
|
||||
[readInfo setObject: h
|
||||
forKey: NSFileHandleNotificationFileHandleItem];
|
||||
RELEASE(h);
|
||||
}
|
||||
[self postReadNotification];
|
||||
}
|
||||
else if (operation == NSFileHandleDataAvailableNotification)
|
||||
{
|
||||
[self postReadNotification];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableData *item;
|
||||
int length;
|
||||
int received = 0;
|
||||
char buf[NETBUF_SIZE];
|
||||
|
||||
item = [readInfo objectForKey: NSFileHandleNotificationDataItem];
|
||||
/*
|
||||
* We may have a maximum data size set...
|
||||
*/
|
||||
if (readMax > 0)
|
||||
{
|
||||
length = (unsigned int)readMax - [item length];
|
||||
if (length > (int)sizeof(buf))
|
||||
{
|
||||
length = sizeof(buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
length = sizeof(buf);
|
||||
}
|
||||
|
||||
received = [self read: buf length: length];
|
||||
if (received == 0)
|
||||
{ // Read up to end of file.
|
||||
[self postReadNotification];
|
||||
}
|
||||
else if (received < 0)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
if (WSAGetLastError() != WSAEINTR
|
||||
&& WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
#else
|
||||
if (errno != EAGAIN && errno != EINTR)
|
||||
#endif
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat: @"Read attempt failed - %s",
|
||||
GSLastErrorStr(errno)];
|
||||
[readInfo setObject: s forKey: GSFileHandleNotificationError];
|
||||
[self postReadNotification];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[item appendBytes: buf length: received];
|
||||
if (readMax < 0 || (readMax > 0 && (int)[item length] == readMax))
|
||||
{
|
||||
// Read a single chunk of data
|
||||
[self postReadNotification];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) receivedEventWrite
|
||||
{
|
||||
NSString *operation;
|
||||
NSMutableDictionary *info;
|
||||
|
||||
info = [writeInfo objectAtIndex: 0];
|
||||
operation = [info objectForKey: NotificationKey];
|
||||
if (operation == GSFileHandleConnectCompletionNotification
|
||||
|| operation == GSSOCKSConnect)
|
||||
{ // Connection attempt completed.
|
||||
int result;
|
||||
int len = sizeof(result);
|
||||
|
||||
#if defined(__MINGW__)
|
||||
if (getsockopt((SOCKET)_get_osfhandle(descriptor), SOL_SOCKET, SO_ERROR,
|
||||
(char*)&result, &len) == 0 && result != 0)
|
||||
#else
|
||||
if (getsockopt(descriptor, SOL_SOCKET, SO_ERROR,
|
||||
(char*)&result, &len) == 0 && result != 0)
|
||||
#endif
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat: @"Connect attempt failed - %s",
|
||||
GSLastErrorStr(result)];
|
||||
[info setObject: s forKey: GSFileHandleNotificationError];
|
||||
}
|
||||
else
|
||||
{
|
||||
readOK = YES;
|
||||
writeOK = YES;
|
||||
}
|
||||
connectOK = NO;
|
||||
[self postWriteNotification];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSData *item;
|
||||
int length;
|
||||
const void *ptr;
|
||||
|
||||
item = [info objectForKey: NSFileHandleNotificationDataItem];
|
||||
length = [item length];
|
||||
ptr = [item bytes];
|
||||
if (writePos < length)
|
||||
{
|
||||
int written;
|
||||
|
||||
written = [self write: (char*)ptr+writePos
|
||||
length: length-writePos];
|
||||
if (written <= 0)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
if (written < 0 && WSAGetLastError()!= WSAEINTR
|
||||
&& WSAGetLastError()!= WSAEWOULDBLOCK)
|
||||
#else
|
||||
if (written < 0 && errno != EAGAIN && errno != EINTR)
|
||||
#endif
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat:
|
||||
@"Write attempt failed - %s", GSLastErrorStr(errno)];
|
||||
[info setObject: s forKey: GSFileHandleNotificationError];
|
||||
[self postWriteNotification];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writePos += written;
|
||||
}
|
||||
}
|
||||
if (writePos >= length)
|
||||
{ // Write operation completed.
|
||||
[self postWriteNotification];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) receivedEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
extra: (void*)extra
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
NSString *operation;
|
||||
#ifdef __MINGW32__
|
||||
WSANETWORKEVENTS ocurredEvents;
|
||||
#endif
|
||||
|
||||
NSDebugMLLog(@"NSFileHandle", @"%@ event: %d", self, type);
|
||||
|
||||
|
@ -2070,183 +2298,77 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
{
|
||||
[self setNonBlocking: YES];
|
||||
}
|
||||
|
||||
if (type == ET_RDESC)
|
||||
#ifdef __MINGW32__
|
||||
if (WSAEnumNetworkEvents((SOCKET)_get_osfhandle(descriptor),
|
||||
event, &ocurredEvents) == SOCKET_ERROR)
|
||||
{
|
||||
operation = [readInfo objectForKey: NotificationKey];
|
||||
if (operation == NSFileHandleConnectionAcceptedNotification)
|
||||
NSLog(@"Error getting event type %d", WSAGetLastError());
|
||||
abort();
|
||||
}
|
||||
if (ocurredEvents.lNetworkEvents & FD_CONNECT)
|
||||
{
|
||||
NSDebugMLLog(@"NSFileHandle", @"Connect on %x", extra);
|
||||
ocurredEvents.lNetworkEvents ^= FD_CONNECT;
|
||||
[self receivedEventWrite];
|
||||
GSNotifyASAP();
|
||||
}
|
||||
if (ocurredEvents.lNetworkEvents & FD_ACCEPT)
|
||||
{
|
||||
NSDebugMLLog(@"NSFileHandle", @"Accept on %x", extra);
|
||||
ocurredEvents.lNetworkEvents ^= FD_ACCEPT;
|
||||
[self receivedEventRead];
|
||||
GSNotifyASAP();
|
||||
}
|
||||
if (ocurredEvents.lNetworkEvents & FD_WRITE)
|
||||
{
|
||||
NSDebugMLLog(@"NSFileHandle", @"Write on %x", extra);
|
||||
ocurredEvents.lNetworkEvents ^= FD_WRITE;
|
||||
[self receivedEventWrite];
|
||||
GSNotifyASAP();
|
||||
}
|
||||
if (ocurredEvents.lNetworkEvents & FD_READ)
|
||||
{
|
||||
NSDebugMLLog(@"NSFileHandle", @"Read on %x", extra);
|
||||
ocurredEvents.lNetworkEvents ^= FD_READ;
|
||||
[self receivedEventRead];
|
||||
GSNotifyASAP();
|
||||
}
|
||||
if (ocurredEvents.lNetworkEvents & FD_OOB)
|
||||
{
|
||||
NSDebugMLLog(@"NSFileHandle", @"OOB on %x", extra);
|
||||
ocurredEvents.lNetworkEvents ^= FD_OOB;
|
||||
[self receivedEventRead];
|
||||
GSNotifyASAP();
|
||||
}
|
||||
if (ocurredEvents.lNetworkEvents & FD_CLOSE)
|
||||
{
|
||||
NSDebugMLLog(@"NSFileHandle", @"Close on %x", extra);
|
||||
ocurredEvents.lNetworkEvents ^= FD_CLOSE;
|
||||
if ([writeInfo count] > 0)
|
||||
{
|
||||
struct sockaddr_in buf;
|
||||
#if defined(__MINGW__)
|
||||
SOCKET desc;
|
||||
#else
|
||||
int desc;
|
||||
#endif
|
||||
int blen = sizeof(buf);
|
||||
|
||||
#if defined(__MINGW__)
|
||||
desc = accept((SOCKET)_get_osfhandle(descriptor), (struct sockaddr*)&buf, &blen);
|
||||
#else
|
||||
desc = accept(descriptor, (struct sockaddr*)&buf, &blen);
|
||||
#endif
|
||||
if (desc == INVALID_SOCKET)
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat: @"Accept attempt failed - %s",
|
||||
GSLastErrorStr(errno)];
|
||||
[readInfo setObject: s forKey: GSFileHandleNotificationError];
|
||||
}
|
||||
else
|
||||
{ // Accept attempt completed.
|
||||
GSFileHandle *h;
|
||||
struct sockaddr_in sin;
|
||||
int size = sizeof(sin);
|
||||
|
||||
#if defined(__MINGW__)
|
||||
h = [[[self class] alloc] initWithNativeHandle: (void*)desc
|
||||
closeOnDealloc: YES];
|
||||
#else
|
||||
h = [[[self class] alloc] initWithFileDescriptor: desc
|
||||
closeOnDealloc: YES];
|
||||
#endif
|
||||
h->isSocket = YES;
|
||||
getpeername(desc, (struct sockaddr*)&sin, &size);
|
||||
[h setAddr: &sin];
|
||||
[readInfo setObject: h
|
||||
forKey: NSFileHandleNotificationFileHandleItem];
|
||||
RELEASE(h);
|
||||
}
|
||||
[self postReadNotification];
|
||||
}
|
||||
else if (operation == NSFileHandleDataAvailableNotification)
|
||||
{
|
||||
[self postReadNotification];
|
||||
[self receivedEventWrite];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableData *item;
|
||||
int length;
|
||||
int received = 0;
|
||||
char buf[NETBUF_SIZE];
|
||||
|
||||
item = [readInfo objectForKey: NSFileHandleNotificationDataItem];
|
||||
/*
|
||||
* We may have a maximum data size set...
|
||||
*/
|
||||
if (readMax > 0)
|
||||
{
|
||||
length = (unsigned int)readMax - [item length];
|
||||
if (length > (int)sizeof(buf))
|
||||
{
|
||||
length = sizeof(buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
length = sizeof(buf);
|
||||
}
|
||||
|
||||
received = [self read: buf length: length];
|
||||
if (received == 0)
|
||||
{ // Read up to end of file.
|
||||
[self postReadNotification];
|
||||
}
|
||||
else if (received < 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EINTR)
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat: @"Read attempt failed - %s",
|
||||
GSLastErrorStr(errno)];
|
||||
[readInfo setObject: s forKey: GSFileHandleNotificationError];
|
||||
[self postReadNotification];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[item appendBytes: buf length: received];
|
||||
if (readMax < 0 || (readMax > 0 && (int)[item length] == readMax))
|
||||
{
|
||||
// Read a single chunk of data
|
||||
[self postReadNotification];
|
||||
}
|
||||
}
|
||||
[self receivedEventRead];
|
||||
}
|
||||
GSNotifyASAP();
|
||||
}
|
||||
if (ocurredEvents.lNetworkEvents)
|
||||
{
|
||||
NSLog(@"Event not get %d", ocurredEvents.lNetworkEvents);
|
||||
abort();
|
||||
}
|
||||
#else
|
||||
if (type == ET_RDESC)
|
||||
{
|
||||
[self receivedEventRead];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableDictionary *info;
|
||||
|
||||
info = [writeInfo objectAtIndex: 0];
|
||||
operation = [info objectForKey: NotificationKey];
|
||||
if (operation == GSFileHandleConnectCompletionNotification
|
||||
|| operation == GSSOCKSConnect)
|
||||
{ // Connection attempt completed.
|
||||
int result;
|
||||
int len = sizeof(result);
|
||||
|
||||
#if defined(__MINGW__)
|
||||
if (getsockopt((SOCKET)_get_osfhandle(descriptor), SOL_SOCKET, SO_ERROR,
|
||||
(char*)&result, &len) == 0 && result != 0)
|
||||
#else
|
||||
if (getsockopt(descriptor, SOL_SOCKET, SO_ERROR,
|
||||
(char*)&result, &len) == 0 && result != 0)
|
||||
#endif
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat: @"Connect attempt failed - %s",
|
||||
GSLastErrorStr(result)];
|
||||
[info setObject: s forKey: GSFileHandleNotificationError];
|
||||
}
|
||||
else
|
||||
{
|
||||
readOK = YES;
|
||||
writeOK = YES;
|
||||
}
|
||||
connectOK = NO;
|
||||
[self postWriteNotification];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSData *item;
|
||||
int length;
|
||||
const void *ptr;
|
||||
|
||||
item = [info objectForKey: NSFileHandleNotificationDataItem];
|
||||
length = [item length];
|
||||
ptr = [item bytes];
|
||||
if (writePos < length)
|
||||
{
|
||||
int written;
|
||||
|
||||
written = [self write: (char*)ptr+writePos
|
||||
length: length-writePos];
|
||||
if (written <= 0)
|
||||
{
|
||||
if (written < 0 && errno != EAGAIN && errno != EINTR)
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithFormat:
|
||||
@"Write attempt failed - %s", GSLastErrorStr(errno)];
|
||||
[info setObject: s forKey: GSFileHandleNotificationError];
|
||||
[self postWriteNotification];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writePos += written;
|
||||
}
|
||||
}
|
||||
if (writePos >= length)
|
||||
{ // Write operation completed.
|
||||
[self postWriteNotification];
|
||||
}
|
||||
}
|
||||
[self receivedEventWrite];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (NSDate*) timedOutEvent: (void*)data
|
||||
|
|
|
@ -89,12 +89,14 @@ NSDictionary *
|
|||
GSDomainFromDefaultLocale(void)
|
||||
{
|
||||
static NSDictionary *saved = nil;
|
||||
int i;
|
||||
struct lconv *lconv;
|
||||
NSMutableDictionary *dict;
|
||||
NSMutableArray *arr;
|
||||
NSString *str1;
|
||||
NSString *str2;
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
int i;
|
||||
NSMutableArray *arr;
|
||||
#endif
|
||||
|
||||
if (saved != nil)
|
||||
return saved;
|
||||
|
|
|
@ -81,9 +81,14 @@
|
|||
DESTROY(self);
|
||||
}
|
||||
#else
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
HANDLE readh, writeh;
|
||||
|
||||
if (CreatePipe(&readh, &writeh, NULL, 0) != 0)
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
if (CreatePipe(&readh, &writeh, &saAttr, 0) != 0)
|
||||
{
|
||||
readHandle = [[NSFileHandle alloc] initWithNativeHandle: readh
|
||||
closeOnDealloc: YES];
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -42,6 +42,8 @@
|
|||
#include "thr-mach.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "Foundation/NSException.h"
|
||||
#include "Foundation/NSThread.h"
|
||||
#include "Foundation/NSLock.h"
|
||||
|
@ -792,8 +794,12 @@ gnustep_base_thread_callback(void)
|
|||
@implementation GSPerformHolder
|
||||
|
||||
static NSLock *subthreadsLock = nil;
|
||||
#ifdef __MINGW__
|
||||
static HANDLE event;
|
||||
#else
|
||||
static int inputFd = -1;
|
||||
static int outputFd = -1;
|
||||
#endif
|
||||
static NSMutableArray *perfArray = nil;
|
||||
static NSDate *theFuture;
|
||||
|
||||
|
@ -803,9 +809,10 @@ static NSDate *theFuture;
|
|||
NSArray *m = commonModes();
|
||||
unsigned count = [m count];
|
||||
unsigned i;
|
||||
BOOL pipeOK = NO;
|
||||
|
||||
theFuture = RETAIN([NSDate distantFuture]);
|
||||
subthreadsLock = [[NSLock alloc] init];
|
||||
perfArray = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||
|
||||
#ifndef __MINGW__
|
||||
{
|
||||
|
@ -815,47 +822,36 @@ static NSDate *theFuture;
|
|||
{
|
||||
inputFd = fd[0];
|
||||
outputFd = fd[1];
|
||||
pipeOK = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Failed to create pipe to handle perform in main thread"];
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
[loop addEvent: (void*)inputFd
|
||||
type: ET_RDESC
|
||||
watcher: (id<RunLoopEvents>)self
|
||||
forMode: [m objectAtIndex: i]];
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
HANDLE readh, writeh;
|
||||
|
||||
if (CreatePipe(&readh, &writeh, NULL, 0) != 0)
|
||||
if ((event = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
|
||||
{
|
||||
inputFd = _open_osfhandle((int)readh, 0);
|
||||
outputFd = _open_osfhandle((int)writeh, 0);
|
||||
pipeOK = YES;
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Failed to create event to handle perform in main thread"];
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
[loop addEvent: (void*)event
|
||||
type: ET_HANDLE
|
||||
watcher: (id<RunLoopEvents>)self
|
||||
forMode: [m objectAtIndex: i]];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (pipeOK == NO)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Failed to create pipe to handle perform in main thread"];
|
||||
}
|
||||
|
||||
subthreadsLock = [[NSLock alloc] init];
|
||||
|
||||
perfArray = [[NSMutableArray alloc] initWithCapacity: 10];
|
||||
|
||||
/*
|
||||
* FIXME: The runloop under MINGW only accepts sockets and
|
||||
* unfortunately pipes under windows can not be
|
||||
* treated as sockets so this will not WORK.
|
||||
* Consequence, performSelectorOnMainThread methods will not
|
||||
* work.
|
||||
*/
|
||||
#ifndef __MINGW__
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
[loop addEvent: (void*)inputFd
|
||||
type: ET_RDESC
|
||||
watcher: (id<RunLoopEvents>)self
|
||||
forMode: [m objectAtIndex: i]];
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (BOOL) isValid
|
||||
|
@ -879,8 +875,21 @@ static NSDate *theFuture;
|
|||
h->lock = l;
|
||||
|
||||
[subthreadsLock lock];
|
||||
|
||||
[perfArray addObject: h];
|
||||
write(outputFd, "0", 1);
|
||||
|
||||
#if defined(__MINGW__)
|
||||
if (SetEvent(event) == 0)
|
||||
{
|
||||
NSLog(@"Set event failed - %@", GSLastErrorStr(errno));
|
||||
}
|
||||
#else
|
||||
if (write(outputFd, "0", 1) != 1)
|
||||
{
|
||||
NSLog(@"Write to pipe failed - %@", GSLastErrorStr(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
[subthreadsLock unlock];
|
||||
|
||||
return h;
|
||||
|
@ -892,18 +901,32 @@ static NSDate *theFuture;
|
|||
forMode: (NSString*)mode
|
||||
{
|
||||
NSRunLoop *loop = [NSRunLoop currentRunLoop];
|
||||
NSArray *toDo;
|
||||
unsigned int i;
|
||||
unsigned int c;
|
||||
char dummy;
|
||||
|
||||
read(inputFd, &dummy, 1);
|
||||
|
||||
[subthreadsLock lock];
|
||||
|
||||
c = [perfArray count];
|
||||
#if defined(__MINGW__)
|
||||
if (ResetEvent(event) == 0)
|
||||
{
|
||||
NSLog(@"Reset event failed - %@", GSLastErrorStr(errno));
|
||||
}
|
||||
#else
|
||||
if (read(inputFd, &c, 1) != 1)
|
||||
{
|
||||
NSLog(@"Read pipe failed - %@", GSLastErrorStr(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
toDo = [[NSArray alloc] initWithArray: perfArray];
|
||||
[perfArray removeAllObjects];
|
||||
[subthreadsLock unlock];
|
||||
|
||||
c = [toDo count];
|
||||
for (i = 0; i < c; i++)
|
||||
{
|
||||
GSPerformHolder *h = [perfArray objectAtIndex: i];
|
||||
GSPerformHolder *h = [toDo objectAtIndex: i];
|
||||
|
||||
[loop performSelector: @selector(fire)
|
||||
target: h
|
||||
|
@ -911,9 +934,7 @@ static NSDate *theFuture;
|
|||
order: 0
|
||||
modes: h->modes];
|
||||
}
|
||||
[perfArray removeAllObjects];
|
||||
|
||||
[subthreadsLock unlock];
|
||||
RELEASE(toDo);
|
||||
}
|
||||
|
||||
+ (NSDate*) timedOutEvent: (void*)data
|
||||
|
|
|
@ -787,9 +787,10 @@ NSTemporaryDirectory(void)
|
|||
NSDictionary *attr;
|
||||
int perm;
|
||||
int owner;
|
||||
int uid;
|
||||
BOOL flag;
|
||||
#if defined(__WIN32__)
|
||||
#if !defined(__WIN32__)
|
||||
int uid;
|
||||
#else
|
||||
char buffer[1024];
|
||||
|
||||
if (GetTempPath(1024, buffer))
|
||||
|
|
40
Source/unix/GNUmakefile
Normal file
40
Source/unix/GNUmakefile
Normal file
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
# src makefile for the GNUstep Base Library
|
||||
#
|
||||
# Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
#
|
||||
# Written by: Scott Christley <scottc@net-community.com>
|
||||
#
|
||||
# This file is part of the GNUstep Base Library.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this library; if not, write to the Free
|
||||
# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
#
|
||||
|
||||
GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../../base.make
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
include ../../config.mak
|
||||
|
||||
SUBPROJECT_NAME = unix
|
||||
|
||||
unix_OBJC_FILES = \
|
||||
GSRunLoopCtxt.m \
|
||||
GSRunLoopWatcher.m
|
||||
|
||||
-include Makefile.preamble
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/subproject.make
|
||||
|
||||
-include Makefile.postamble
|
831
Source/unix/GSRunLoopCtxt.m
Normal file
831
Source/unix/GSRunLoopCtxt.m
Normal file
|
@ -0,0 +1,831 @@
|
|||
/**
|
||||
* The GSRunLoopCtxt stores context information to handle polling for
|
||||
* events. This information is associated with a particular runloop
|
||||
* mode, and persists throughout the life of the runloop instance.
|
||||
*
|
||||
* NB. This class is private to NSRunLoop and must not be subclassed.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "GNUstepBase/GSRunLoopCtxt.h"
|
||||
#include "GNUstepBase/GSRunLoopWatcher.h"
|
||||
#include <Foundation/NSDebug.h>
|
||||
#include <Foundation/NSNotificationQueue.h>
|
||||
#include <Foundation/NSPort.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
extern BOOL GSCheckTasks();
|
||||
|
||||
#if GS_WITH_GC == 0
|
||||
SEL wRelSel;
|
||||
SEL wRetSel;
|
||||
IMP wRelImp;
|
||||
IMP wRetImp;
|
||||
|
||||
static void
|
||||
wRelease(NSMapTable* t, void* w)
|
||||
{
|
||||
(*wRelImp)((id)w, wRelSel);
|
||||
}
|
||||
|
||||
static void
|
||||
wRetain(NSMapTable* t, const void* w)
|
||||
{
|
||||
(*wRetImp)((id)w, wRetSel);
|
||||
}
|
||||
|
||||
static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
||||
{
|
||||
wRetain,
|
||||
wRelease,
|
||||
0
|
||||
};
|
||||
#else
|
||||
#define WatcherMapValueCallBacks NSOwnedPointerMapValueCallBacks
|
||||
#endif
|
||||
|
||||
@implementation GSRunLoopCtxt
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(mode);
|
||||
GSIArrayEmpty(performers);
|
||||
NSZoneFree(performers->zone, (void*)performers);
|
||||
GSIArrayEmpty(timers);
|
||||
NSZoneFree(timers->zone, (void*)timers);
|
||||
GSIArrayEmpty(watchers);
|
||||
NSZoneFree(watchers->zone, (void*)watchers);
|
||||
if (_efdMap != 0)
|
||||
{
|
||||
NSFreeMapTable(_efdMap);
|
||||
}
|
||||
if (_rfdMap != 0)
|
||||
{
|
||||
NSFreeMapTable(_rfdMap);
|
||||
}
|
||||
if (_wfdMap != 0)
|
||||
{
|
||||
NSFreeMapTable(_wfdMap);
|
||||
}
|
||||
#ifdef HAVE_POLL
|
||||
if (pollfds != 0)
|
||||
{
|
||||
objc_free(pollfds);
|
||||
}
|
||||
#endif
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any callback for the specified event which is set for an
|
||||
* uncompleted poll operation.<br />
|
||||
* This is called by nested event loops on contexts in outer loops
|
||||
* when they handle an event ... removing the event from the outer
|
||||
* loop ensures that it won't get handled twice, once by the inner
|
||||
* loop and once by the outer one.
|
||||
*/
|
||||
- (void) endEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
{
|
||||
if (completed == NO)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ET_RDESC:
|
||||
NSMapRemove(_rfdMap, data);
|
||||
break;
|
||||
case ET_WDESC:
|
||||
NSMapRemove(_wfdMap, data);
|
||||
break;
|
||||
case ET_EDESC:
|
||||
NSMapRemove(_efdMap, data);
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Ending an event of unkown type (%d)", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this poll context as having completed, so that if we are
|
||||
* executing a re-entrant poll, the enclosing poll operations
|
||||
* know they can stop what they are doing because an inner
|
||||
* operation has done the job.
|
||||
*/
|
||||
- (void) endPoll
|
||||
{
|
||||
completed = YES;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"-init may not be called for GSRunLoopCtxt"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id) initWithMode: (NSString*)theMode extra: (void*)e
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
NSZone *z = [self zone];
|
||||
|
||||
mode = [theMode copy];
|
||||
extra = e;
|
||||
performers = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity(performers, z, 8);
|
||||
timers = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity(timers, z, 8);
|
||||
watchers = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity(watchers, z, 8);
|
||||
|
||||
_efdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
|
||||
WatcherMapValueCallBacks, 0);
|
||||
_rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
|
||||
WatcherMapValueCallBacks, 0);
|
||||
_wfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
|
||||
WatcherMapValueCallBacks, 0);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
|
||||
static void setPollfd(int fd, int event, GSRunLoopCtxt *ctxt)
|
||||
{
|
||||
int index;
|
||||
struct pollfd *pollfds = ctxt->pollfds;
|
||||
pollextra *pe = (pollextra*)ctxt->extra;
|
||||
|
||||
if (fd >= pe->limit)
|
||||
{
|
||||
int oldfd_limit = pe->limit;
|
||||
|
||||
pe->limit = fd + 1;
|
||||
if (pe->index == 0)
|
||||
{
|
||||
pe->index = objc_malloc(pe->limit * sizeof(*(pe->index)));
|
||||
}
|
||||
else
|
||||
{
|
||||
pe->index = objc_realloc(pe->index, pe->limit * sizeof(*(pe->index)));
|
||||
}
|
||||
do
|
||||
{
|
||||
pe->index[oldfd_limit++] = -1;
|
||||
}
|
||||
while (oldfd_limit < pe->limit);
|
||||
}
|
||||
index = pe->index[fd];
|
||||
if (index == -1)
|
||||
{
|
||||
if (ctxt->pollfds_count >= ctxt->pollfds_capacity)
|
||||
{
|
||||
ctxt->pollfds_capacity += 8;
|
||||
pollfds =
|
||||
objc_realloc(pollfds, ctxt->pollfds_capacity * sizeof (*pollfds));
|
||||
ctxt->pollfds = pollfds;
|
||||
}
|
||||
index = ctxt->pollfds_count++;
|
||||
pe->index[fd] = index;
|
||||
pollfds[index].fd = fd;
|
||||
pollfds[index].events = 0;
|
||||
pollfds[index].revents = 0;
|
||||
}
|
||||
pollfds[index].events |= event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a poll for the specified runloop context.
|
||||
* If the method has been called re-entrantly, the contexts stack
|
||||
* will list all the contexts with polls in progress
|
||||
* and this method must tell those outer contexts not to handle events
|
||||
* which are handled by this context.
|
||||
*/
|
||||
- (BOOL) pollUntil: (int)milliseconds within: (NSArray*)contexts
|
||||
{
|
||||
int poll_return;
|
||||
int fdEnd; /* Number of descriptors being monitored. */
|
||||
int fdIndex;
|
||||
int fdFinish;
|
||||
unsigned int i;
|
||||
|
||||
i = GSIArrayCount(watchers);
|
||||
|
||||
/*
|
||||
* Get ready to listen to file descriptors.
|
||||
* The maps will not have been emptied by any previous call.
|
||||
*/
|
||||
NSResetMapTable(_efdMap);
|
||||
NSResetMapTable(_rfdMap);
|
||||
NSResetMapTable(_wfdMap);
|
||||
|
||||
/*
|
||||
* Do the pre-listening set-up for the file descriptors of this mode.
|
||||
*/
|
||||
if (pollfds_capacity < i + 1)
|
||||
{
|
||||
pollfds_capacity = i + 1;
|
||||
if (pollfds == 0)
|
||||
{
|
||||
pollfds = objc_malloc(pollfds_capacity * sizeof(*pollfds));
|
||||
}
|
||||
else
|
||||
{
|
||||
pollfds = objc_realloc(pollfds, pollfds_capacity * sizeof(*pollfds));
|
||||
}
|
||||
}
|
||||
pollfds_count = 0;
|
||||
((pollextra*)extra)->limit = 0;
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *info;
|
||||
int fd;
|
||||
|
||||
info = GSIArrayItemAtIndex(watchers, i).obj;
|
||||
if (info->_invalidated == YES)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (info->type)
|
||||
{
|
||||
case ET_EDESC:
|
||||
fd = (int)info->data;
|
||||
setPollfd(fd, POLLPRI, self);
|
||||
NSMapInsert(_efdMap, (void*)fd, info);
|
||||
break;
|
||||
|
||||
case ET_RDESC:
|
||||
fd = (int)info->data;
|
||||
setPollfd(fd, POLLIN, self);
|
||||
NSMapInsert(_rfdMap, (void*)fd, info);
|
||||
break;
|
||||
|
||||
case ET_WDESC:
|
||||
fd = (int)info->data;
|
||||
setPollfd(fd, POLLOUT, self);
|
||||
NSMapInsert(_wfdMap, (void*)fd, info);
|
||||
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];
|
||||
|
||||
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*)port_fd_array[port_fd_count], info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are notifications in the 'idle' queue, we try an
|
||||
* instantaneous select so that, if there is no input pending,
|
||||
* we can service the queue. Similarly, if a task has completed,
|
||||
* we need to deliver its notifications.
|
||||
*/
|
||||
if (GSCheckTasks() || GSNotifyMore())
|
||||
{
|
||||
milliseconds = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
unsigned int i;
|
||||
fprintf(stderr, "poll %d %d:", milliseconds, pollfds_count);
|
||||
for (i = 0; i < pollfds_count; i++)
|
||||
fprintf(stderr, " %d,%x", pollfds[i].fd, pollfds[i].events);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
poll_return = poll (pollfds, pollfds_count, milliseconds);
|
||||
#if 0
|
||||
{
|
||||
unsigned int i;
|
||||
fprintf(stderr, "ret %d %d:", poll_return, pollfds_count);
|
||||
for (i = 0; i < pollfds_count; i++)
|
||||
fprintf(stderr, " %d,%x", pollfds[i].fd, pollfds[i].revents);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
NSDebugMLLog(@"NSRunLoop", @"poll returned %d\n", poll_return);
|
||||
|
||||
if (poll_return < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
GSCheckTasks();
|
||||
poll_return = 0;
|
||||
}
|
||||
else if (errno == 0)
|
||||
{
|
||||
/* Some systems returns an errno == 0. Not sure why */
|
||||
poll_return = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some exceptional condition happened. */
|
||||
/* xxx We can do something with exception_fds, instead of
|
||||
aborting here. */
|
||||
NSLog (@"poll() error in -acceptInputForMode:beforeDate: '%s'",
|
||||
GSLastErrorStr(errno));
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
if (poll_return == 0)
|
||||
{
|
||||
completed = YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look at all the file descriptors select() says are ready for action;
|
||||
* notify the corresponding object for each of the ready fd's.
|
||||
* NB. It is possible for a watcher to be missing from the map - if
|
||||
* the event handler of a previous watcher has 'run' the loop again
|
||||
* before returning.
|
||||
* NB. Each time this loop is entered, the starting position (fairStart)
|
||||
* is incremented - this is to ensure a fair distribion over all
|
||||
* inputs where multiple inputs are in use. Note - fairStart can be
|
||||
* modified while we are in the loop (by recursive calls).
|
||||
*/
|
||||
fdEnd = pollfds_count;
|
||||
if (++fairStart >= fdEnd)
|
||||
{
|
||||
fairStart = 0;
|
||||
fdIndex = 0;
|
||||
fdFinish = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fdIndex = fairStart;
|
||||
fdFinish = fairStart;
|
||||
}
|
||||
completed = NO;
|
||||
while (completed == NO)
|
||||
{
|
||||
if (pollfds[fdIndex].revents != 0)
|
||||
{
|
||||
int fd = pollfds[fdIndex].fd;
|
||||
GSRunLoopWatcher *watcher;
|
||||
BOOL found = NO;
|
||||
|
||||
/*
|
||||
* The poll() call supports various error conditions - all
|
||||
* errors should be handled by any available handler.
|
||||
* The ET_EDSEC handler is the primary handler for exceptions
|
||||
* though it is more generally used to deal with out-of-band data.
|
||||
*/
|
||||
if (pollfds[fdIndex].revents & (POLLPRI|POLLERR|POLLHUP|POLLNVAL))
|
||||
{
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_efdMap, (void*)fd);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)fd 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*)(gsaddr)fd, mode);
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
{
|
||||
break; // A nested poll has done the job.
|
||||
}
|
||||
found = YES;
|
||||
}
|
||||
if (pollfds[fdIndex].revents & (POLLOUT|POLLERR|POLLHUP|POLLNVAL))
|
||||
{
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_wfdMap, (void*)fd);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)fd 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*)(gsaddr)fd, mode);
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
{
|
||||
break; // A nested poll has done the job.
|
||||
}
|
||||
found = YES;
|
||||
}
|
||||
if (pollfds[fdIndex].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL))
|
||||
{
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_rfdMap, (void*)fd);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)fd 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*)(gsaddr)fd, mode);
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
{
|
||||
break; // A nested poll has done the job.
|
||||
}
|
||||
found = YES;
|
||||
}
|
||||
if (found == YES && --poll_return == 0)
|
||||
{
|
||||
completed = YES;
|
||||
}
|
||||
}
|
||||
if (++fdIndex >= fdEnd)
|
||||
{
|
||||
fdIndex = 0;
|
||||
}
|
||||
if (fdIndex == fdFinish)
|
||||
{
|
||||
completed = YES;
|
||||
}
|
||||
}
|
||||
completed = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
- (BOOL) pollUntil: (int)milliseconds within: (NSArray*)contexts
|
||||
{
|
||||
struct timeval timeout;
|
||||
void *select_timeout;
|
||||
int select_return;
|
||||
int fdIndex;
|
||||
int fdFinish;
|
||||
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 i;
|
||||
|
||||
i = GSIArrayCount(watchers);
|
||||
|
||||
/* Find out how much time we should wait, and set SELECT_TIMEOUT. */
|
||||
if (milliseconds == 0)
|
||||
{
|
||||
/* Don't wait at all. */
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
select_timeout = &timeout;
|
||||
}
|
||||
else if (milliseconds > 0)
|
||||
{
|
||||
timeout.tv_sec = milliseconds/1000;
|
||||
timeout.tv_usec = (milliseconds - 1000 * timeout.tv_sec) * 1000;
|
||||
select_timeout = &timeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout.tv_sec = -1;
|
||||
timeout.tv_usec = -1;
|
||||
select_timeout = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get ready to listen to file descriptors.
|
||||
* Initialize the set of FDS we'll pass to select(), and make sure we
|
||||
* have empty maps for keeping track of which watcher is associated
|
||||
* with which file descriptor.
|
||||
* The maps may not have been emptied if a previous call to this
|
||||
* method was terminated by an exception.
|
||||
*/
|
||||
memset(&exception_fds, '\0', sizeof(exception_fds));
|
||||
memset(&read_fds, '\0', sizeof(read_fds));
|
||||
memset(&write_fds, '\0', sizeof(write_fds));
|
||||
NSResetMapTable(_efdMap);
|
||||
NSResetMapTable(_rfdMap);
|
||||
NSResetMapTable(_wfdMap);
|
||||
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *info;
|
||||
int fd;
|
||||
|
||||
info = GSIArrayItemAtIndex(watchers, i).obj;
|
||||
if (info->_invalidated == YES)
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(watchers, i);
|
||||
continue;
|
||||
}
|
||||
switch (info->type)
|
||||
{
|
||||
case ET_EDESC:
|
||||
fd = (int)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &exception_fds);
|
||||
NSMapInsert(_efdMap, (void*)fd, info);
|
||||
num_inputs++;
|
||||
break;
|
||||
|
||||
case ET_RDESC:
|
||||
fd = (int)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &read_fds);
|
||||
NSMapInsert(_rfdMap, (void*)fd, info);
|
||||
num_inputs++;
|
||||
break;
|
||||
|
||||
case ET_WDESC:
|
||||
fd = (int)info->data;
|
||||
if (fd > fdEnd)
|
||||
fdEnd = fd;
|
||||
FD_SET (fd, &write_fds);
|
||||
NSMapInsert(_wfdMap, (void*)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*)port_fd_array[port_fd_count], info);
|
||||
num_inputs++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fdEnd++;
|
||||
|
||||
/*
|
||||
* If there are notifications in the 'idle' queue, we try an
|
||||
* instantaneous select so that, if there is no input pending,
|
||||
* we can service the queue. Similarly, if a task has completed,
|
||||
* we need to deliver its notifications.
|
||||
*/
|
||||
if (GSCheckTasks() || GSNotifyMore())
|
||||
{
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
select_timeout = &timeout;
|
||||
}
|
||||
|
||||
// NSDebugMLLog(@"NSRunLoop", @"select timeout %d,%d", timeout.tv_sec, timeout.tv_usec);
|
||||
|
||||
select_return = select (fdEnd, &read_fds, &write_fds,
|
||||
&exception_fds, select_timeout);
|
||||
|
||||
NSDebugMLLog(@"NSRunLoop", @"select returned %d", select_return);
|
||||
|
||||
if (select_return < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
GSCheckTasks();
|
||||
select_return = 0;
|
||||
}
|
||||
else if (errno == 0)
|
||||
{
|
||||
/* Some systems return an errno == 0. Not sure why */
|
||||
select_return = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some exceptional condition happened. */
|
||||
/* xxx We can do something with exception_fds, instead of
|
||||
aborting here. */
|
||||
NSLog (@"select() error in -acceptInputForMode:beforeDate: '%s'",
|
||||
GSLastErrorStr(errno));
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
if (select_return == 0)
|
||||
{
|
||||
completed = YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look at all the file descriptors select() says are ready for action;
|
||||
* notify the corresponding object for each of the ready fd's.
|
||||
* NB. Each time this roop is entered, the starting position (fairStart)
|
||||
* is incremented - this is to ensure a fair distribtion over all
|
||||
* inputs where multiple inputs are in use. Note - fairStart can be
|
||||
* modified while we are in the loop (by recursive calls).
|
||||
*/
|
||||
if (++fairStart >= fdEnd)
|
||||
{
|
||||
fairStart = 0;
|
||||
fdIndex = 0;
|
||||
fdFinish = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fdIndex = fairStart;
|
||||
fdFinish = fairStart;
|
||||
}
|
||||
completed = NO;
|
||||
while (completed == NO)
|
||||
{
|
||||
BOOL found = NO;
|
||||
|
||||
if (FD_ISSET (fdIndex, &exception_fds))
|
||||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_efdMap, (void*)fdIndex);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)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*)(gsaddr)fdIndex, mode);
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
{
|
||||
break;
|
||||
}
|
||||
found = YES;
|
||||
}
|
||||
if (FD_ISSET (fdIndex, &write_fds))
|
||||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_wfdMap, (void*)fdIndex);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)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*)(gsaddr)fdIndex, mode);
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
{
|
||||
break;
|
||||
}
|
||||
found = YES;
|
||||
}
|
||||
if (FD_ISSET (fdIndex, &read_fds))
|
||||
{
|
||||
GSRunLoopWatcher *watcher;
|
||||
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(_rfdMap, (void*)fdIndex);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self) [c endEvent: (void*)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*)(gsaddr)fdIndex, mode);
|
||||
}
|
||||
GSNotifyASAP();
|
||||
if (completed == YES)
|
||||
{
|
||||
break;
|
||||
}
|
||||
found = YES;
|
||||
}
|
||||
if (found == YES && --select_return == 0)
|
||||
{
|
||||
completed = YES;
|
||||
}
|
||||
if (++fdIndex >= fdEnd)
|
||||
{
|
||||
fdIndex = 0;
|
||||
}
|
||||
if (fdIndex == fdFinish)
|
||||
{
|
||||
completed = YES;
|
||||
}
|
||||
}
|
||||
completed = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
#endif
|
||||
@end
|
45
Source/unix/GSRunLoopWatcher.m
Normal file
45
Source/unix/GSRunLoopWatcher.m
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "GNUstepBase/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
|
||||
|
66
Source/unix/Makefile.preamble
Normal file
66
Source/unix/Makefile.preamble
Normal file
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
# Makefile.preamble
|
||||
#
|
||||
# Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
#
|
||||
# Author: Scott Christley <scottc@net-community.com>
|
||||
#
|
||||
# This file is part of the GNUstep Base Library.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
#
|
||||
# If you are interested in a warranty or support for this source code,
|
||||
# contact Scott Christley at scottc@net-community.com
|
||||
#
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this library; see the file COPYING.LIB.
|
||||
# If not, write to the Free Software Foundation,
|
||||
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#
|
||||
# Makefile.preamble
|
||||
#
|
||||
# Project specific makefile variables
|
||||
#
|
||||
# Do not put any Makefile rules in this file, instead they should
|
||||
# be put into Makefile.postamble.
|
||||
#
|
||||
|
||||
#
|
||||
# Flags dealing with compiling and linking
|
||||
#
|
||||
|
||||
# Additional flags to pass to the preprocessor
|
||||
ADDITIONAL_CPPFLAGS = $(DEFS) $(CONFIG_SYSTEM_DEFS) -Wall
|
||||
|
||||
# Additional flags to pass to the Objective-C compiler
|
||||
#ADDITIONAL_OBJCFLAGS =
|
||||
|
||||
ifeq ($(GNUSTEP_TARGET_OS),mingw32)
|
||||
ADDITIONAL_OBJCFLAGS += -DBUILD_libgnustep_base_DLL=1
|
||||
endif
|
||||
ifeq ($(GNUSTEP_TARGET_OS),cygwin)
|
||||
ADDITIONAL_OBJCFLAGS += -DBUILD_libgnustep_base_DLL=1
|
||||
endif
|
||||
|
||||
# Additional flags to pass to the C compiler
|
||||
ADDITIONAL_CFLAGS =
|
||||
|
||||
# Additional include directories the compiler should search
|
||||
ADDITIONAL_INCLUDE_DIRS = -I../../Headers/Additions \
|
||||
-I../$(GNUSTEP_TARGET_DIR)
|
||||
|
||||
ifeq ($(FOUNDATION_LIB),gnu)
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../../Headers
|
||||
endif
|
||||
|
||||
# Additional LDFLAGS to pass to the linker
|
||||
ADDITIONAL_LDFLAGS =
|
41
Source/win32/GNUmakefile
Normal file
41
Source/win32/GNUmakefile
Normal file
|
@ -0,0 +1,41 @@
|
|||
#
|
||||
# src makefile for the GNUstep Base Library
|
||||
#
|
||||
# Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
#
|
||||
# Written by: Scott Christley <scottc@net-community.com>
|
||||
#
|
||||
# This file is part of the GNUstep Base Library.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this library; if not, write to the Free
|
||||
# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
#
|
||||
|
||||
GNUSTEP_LOCAL_ADDITIONAL_MAKEFILES=../../base.make
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
include ../../config.mak
|
||||
|
||||
SUBPROJECT_NAME = win32
|
||||
|
||||
win32_OBJC_FILES =\
|
||||
GSRunLoopCtxt.m \
|
||||
GSRunLoopWatcher.m \
|
||||
NSRunLoopWin32.m
|
||||
|
||||
-include Makefile.preamble
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/subproject.make
|
||||
|
||||
-include Makefile.postamble
|
323
Source/win32/GSRunLoopCtxt.m
Normal file
323
Source/win32/GSRunLoopCtxt.m
Normal file
|
@ -0,0 +1,323 @@
|
|||
/**
|
||||
* The GSRunLoopCtxt stores context information to handle polling for
|
||||
* events. This information is associated with a particular runloop
|
||||
* mode, and persists throughout the life of the runloop instance.
|
||||
*
|
||||
* NB. This class is private to NSRunLoop and must not be subclassed.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "GNUstepBase/GSRunLoopCtxt.h"
|
||||
#include "GNUstepBase/GSRunLoopWatcher.h"
|
||||
#include <Foundation/NSDebug.h>
|
||||
#include <Foundation/NSNotificationQueue.h>
|
||||
#include <Foundation/NSPort.h>
|
||||
|
||||
extern BOOL GSCheckTasks();
|
||||
|
||||
#if GS_WITH_GC == 0
|
||||
SEL wRelSel;
|
||||
SEL wRetSel;
|
||||
IMP wRelImp;
|
||||
IMP wRetImp;
|
||||
|
||||
static void
|
||||
wRelease(NSMapTable* t, void* w)
|
||||
{
|
||||
(*wRelImp)((id)w, wRelSel);
|
||||
}
|
||||
|
||||
static void
|
||||
wRetain(NSMapTable* t, const void* w)
|
||||
{
|
||||
(*wRetImp)((id)w, wRetSel);
|
||||
}
|
||||
|
||||
static const NSMapTableValueCallBacks WatcherMapValueCallBacks =
|
||||
{
|
||||
wRetain,
|
||||
wRelease,
|
||||
0
|
||||
};
|
||||
#else
|
||||
#define WatcherMapValueCallBacks NSOwnedPointerMapValueCallBacks
|
||||
#endif
|
||||
|
||||
@implementation GSRunLoopCtxt
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(mode);
|
||||
GSIArrayEmpty(performers);
|
||||
NSZoneFree(performers->zone, (void*)performers);
|
||||
GSIArrayEmpty(timers);
|
||||
NSZoneFree(timers->zone, (void*)timers);
|
||||
GSIArrayEmpty(watchers);
|
||||
NSZoneFree(watchers->zone, (void*)watchers);
|
||||
if (handleMap != 0)
|
||||
{
|
||||
NSFreeMapTable(handleMap);
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any callback for the specified event which is set for an
|
||||
* uncompleted poll operation.<br />
|
||||
* This is called by nested event loops on contexts in outer loops
|
||||
* when they handle an event ... removing the event from the outer
|
||||
* loop ensures that it won't get handled twice, once by the inner
|
||||
* loop and once by the outer one.
|
||||
*/
|
||||
- (void) endEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
{
|
||||
if (completed == NO)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ET_HANDLE:
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Ending an event of unkown type (%d)", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this poll context as having completed, so that if we are
|
||||
* executing a re-entrant poll, the enclosing poll operations
|
||||
* know they can stop what they are doing because an inner
|
||||
* operation has done the job.
|
||||
*/
|
||||
- (void) endPoll
|
||||
{
|
||||
completed = YES;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"-init may not be called for GSRunLoopCtxt"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id) initWithMode: (NSString*)theMode extra: (void*)e
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
NSZone *z = [self zone];
|
||||
|
||||
mode = [theMode copy];
|
||||
extra = e;
|
||||
performers = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity(performers, z, 8);
|
||||
timers = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity(timers, z, 8);
|
||||
watchers = NSZoneMalloc(z, sizeof(GSIArray_t));
|
||||
GSIArrayInitWithZoneAndCapacity(watchers, z, 8);
|
||||
|
||||
handleMap = NSCreateMapTable(NSIntMapKeyCallBacks,
|
||||
WatcherMapValueCallBacks, 0);
|
||||
|
||||
msgTarget = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL) pollUntil: (int)milliseconds within: (NSArray*)contexts
|
||||
{
|
||||
NSMapEnumerator hEnum;
|
||||
GSRunLoopWatcher *watcher;
|
||||
HANDLE *handleArray;
|
||||
int num_handles;
|
||||
unsigned i;
|
||||
HANDLE handle;
|
||||
int wait_timeout;
|
||||
DWORD wait_return;
|
||||
BOOL do_wait;
|
||||
|
||||
// Set timeout how much time should wait
|
||||
if (milliseconds >= 0)
|
||||
{
|
||||
wait_timeout = milliseconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
wait_timeout = INFINITE;
|
||||
}
|
||||
|
||||
NSResetMapTable(handleMap);
|
||||
|
||||
i = GSIArrayCount(watchers);
|
||||
num_handles = 0;
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopWatcher *info;
|
||||
HANDLE handle;
|
||||
|
||||
info = GSIArrayItemAtIndex(watchers, i).obj;
|
||||
if (info->_invalidated == YES)
|
||||
{
|
||||
GSIArrayRemoveItemAtIndex(watchers, i);
|
||||
continue;
|
||||
}
|
||||
switch (info->type)
|
||||
{
|
||||
case ET_HANDLE:
|
||||
handle = (HANDLE)(int)info->data;
|
||||
NSMapInsert(handleMap, (void*)handle, info);
|
||||
num_handles++;
|
||||
break;
|
||||
case ET_RPORT:
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are notifications in the 'idle' queue, we try an
|
||||
* instantaneous select so that, if there is no input pending,
|
||||
* we can service the queue. Similarly, if a task has completed,
|
||||
* we need to deliver its notifications.
|
||||
*/
|
||||
if (GSCheckTasks() || GSNotifyMore())
|
||||
{
|
||||
wait_timeout = 0;
|
||||
}
|
||||
|
||||
handleArray = (HANDLE*)NSZoneMalloc(NSDefaultMallocZone(),
|
||||
sizeof(HANDLE) * num_handles);
|
||||
hEnum = NSEnumerateMapTable(handleMap);
|
||||
|
||||
i = 0;
|
||||
while (NSNextMapEnumeratorPair(&hEnum, (void**)&handle, (void**)&watcher))
|
||||
{
|
||||
handleArray[i++] = handle;
|
||||
}
|
||||
|
||||
do_wait = YES;
|
||||
do
|
||||
{
|
||||
num_handles = i;
|
||||
wait_return = MsgWaitForMultipleObjects(num_handles, handleArray,
|
||||
NO, wait_timeout, QS_ALLEVENTS);
|
||||
NSDebugMLLog(@"NSRunLoop", @"wait returned %d", wait_return);
|
||||
|
||||
// if there are windows message
|
||||
if (wait_return == WAIT_OBJECT_0 + num_handles)
|
||||
{
|
||||
if (msgTarget != nil)
|
||||
{
|
||||
[msgTarget performSelector: msgSelector withObject: nil];
|
||||
NSZoneFree(NSDefaultMallocZone(), handleArray);
|
||||
completed = YES;
|
||||
return NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
MSG msg;
|
||||
INT bRet;
|
||||
|
||||
while ((bRet = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) != 0)
|
||||
{
|
||||
if (bRet == -1)
|
||||
{
|
||||
// handle the error and possibly exit
|
||||
}
|
||||
else
|
||||
{
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
--wait_timeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_wait = NO;
|
||||
}
|
||||
}
|
||||
while (do_wait && (wait_timeout >= 0));
|
||||
|
||||
// check wait errors
|
||||
if (wait_return == WAIT_FAILED)
|
||||
{
|
||||
NSLog(@"WaitForMultipleObjects() error in -acceptInputForMode:beforeDate: '%d'",
|
||||
GetLastError());
|
||||
abort ();
|
||||
}
|
||||
|
||||
// if there arent events
|
||||
if (wait_return == WAIT_TIMEOUT)
|
||||
{
|
||||
NSZoneFree(NSDefaultMallocZone(), handleArray);
|
||||
completed = YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look the event that WaitForMultipleObjects() says is ready;
|
||||
* get the corresponding fd for that handle event and notify
|
||||
* the corresponding object for the ready fd.
|
||||
*/
|
||||
i = wait_return - WAIT_OBJECT_0;
|
||||
|
||||
NSDebugMLLog(@"NSRunLoop", @"Event listen %d", i);
|
||||
|
||||
handle = handleArray[i];
|
||||
|
||||
watcher = (GSRunLoopWatcher*)NSMapGet(handleMap, (void*)handle);
|
||||
if (watcher != nil && watcher->_invalidated == NO)
|
||||
{
|
||||
i = [contexts count];
|
||||
while (i-- > 0)
|
||||
{
|
||||
GSRunLoopCtxt *c = [contexts objectAtIndex: i];
|
||||
|
||||
if (c != self)
|
||||
{
|
||||
[c endEvent: (void*)handle type: ET_HANDLE];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The watcher is still valid - so call its receivers
|
||||
* event handling method.
|
||||
*/
|
||||
(*watcher->handleEvent)(watcher->receiver,
|
||||
eventSel, watcher->data, watcher->type,
|
||||
(void*)(gsaddr)handle, mode);
|
||||
}
|
||||
|
||||
GSNotifyASAP();
|
||||
|
||||
NSZoneFree(NSDefaultMallocZone(), handleArray);
|
||||
completed = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
43
Source/win32/GSRunLoopWatcher.m
Normal file
43
Source/win32/GSRunLoopWatcher.m
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "GNUstepBase/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;
|
||||
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
|
||||
|
66
Source/win32/Makefile.preamble
Normal file
66
Source/win32/Makefile.preamble
Normal file
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
# Makefile.preamble
|
||||
#
|
||||
# Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
#
|
||||
# Author: Scott Christley <scottc@net-community.com>
|
||||
#
|
||||
# This file is part of the GNUstep Base Library.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
#
|
||||
# If you are interested in a warranty or support for this source code,
|
||||
# contact Scott Christley at scottc@net-community.com
|
||||
#
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this library; see the file COPYING.LIB.
|
||||
# If not, write to the Free Software Foundation,
|
||||
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#
|
||||
# Makefile.preamble
|
||||
#
|
||||
# Project specific makefile variables
|
||||
#
|
||||
# Do not put any Makefile rules in this file, instead they should
|
||||
# be put into Makefile.postamble.
|
||||
#
|
||||
|
||||
#
|
||||
# Flags dealing with compiling and linking
|
||||
#
|
||||
|
||||
# Additional flags to pass to the preprocessor
|
||||
ADDITIONAL_CPPFLAGS = $(DEFS) $(CONFIG_SYSTEM_DEFS) -Wall
|
||||
|
||||
# Additional flags to pass to the Objective-C compiler
|
||||
#ADDITIONAL_OBJCFLAGS =
|
||||
|
||||
ifeq ($(GNUSTEP_TARGET_OS),mingw32)
|
||||
ADDITIONAL_OBJCFLAGS += -DBUILD_libgnustep_base_DLL=1
|
||||
endif
|
||||
ifeq ($(GNUSTEP_TARGET_OS),cygwin)
|
||||
ADDITIONAL_OBJCFLAGS += -DBUILD_libgnustep_base_DLL=1
|
||||
endif
|
||||
|
||||
# Additional flags to pass to the C compiler
|
||||
ADDITIONAL_CFLAGS =
|
||||
|
||||
# Additional include directories the compiler should search
|
||||
ADDITIONAL_INCLUDE_DIRS = -I../../Headers/Additions \
|
||||
-I../$(GNUSTEP_TARGET_DIR)
|
||||
|
||||
ifeq ($(FOUNDATION_LIB),gnu)
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../../Headers
|
||||
endif
|
||||
|
||||
# Additional LDFLAGS to pass to the linker
|
||||
ADDITIONAL_LDFLAGS =
|
45
Source/win32/NSRunLoopWin32.m
Normal file
45
Source/win32/NSRunLoopWin32.m
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "config.h"
|
||||
#include "GNUstepBase/preface.h"
|
||||
#include "Foundation/NSRunLoop.h"
|
||||
#include "GNUstepBase/GSRunLoopCtxt.h"
|
||||
|
||||
@implementation NSRunLoop (mingw32)
|
||||
/**
|
||||
* Adds a target to the loop in the specified mode for the
|
||||
* win32 messages.<br />
|
||||
* Only a target+selector is added in one mode. Successive
|
||||
* calls overwrite the previous.<br />
|
||||
*/
|
||||
- (void) addMsgTarget: (id)target
|
||||
withMethod: (SEL)selector
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
GSRunLoopCtxt *context;
|
||||
|
||||
context = NSMapGet(_contextMap, mode);
|
||||
if (context == nil)
|
||||
{
|
||||
context = [[GSRunLoopCtxt alloc] initWithMode: mode extra: _extra];
|
||||
NSMapInsert(_contextMap, context->mode, context);
|
||||
RELEASE(context);
|
||||
}
|
||||
context->msgTarget = target;
|
||||
context->msgSelector = selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the target of the loop in the specified mode for the
|
||||
* win32 messages.<br />
|
||||
*/
|
||||
- (void) removeMsgForMode: (NSString*)mode
|
||||
{
|
||||
GSRunLoopCtxt *context;
|
||||
|
||||
context = NSMapGet(_contextMap, mode);
|
||||
if (context == nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
context->msgTarget = nil;
|
||||
}
|
||||
@end
|
|
@ -10,6 +10,7 @@ id myServer;
|
|||
+ (void) setServer: (id)anObject;
|
||||
+ (void) startup;
|
||||
- (int) doIt;
|
||||
- (void) testPerform: (id)anObject;
|
||||
@end
|
||||
|
||||
@implementation Tester
|
||||
|
@ -26,6 +27,10 @@ id myServer;
|
|||
sendPort: [portArray objectAtIndex: 1]];
|
||||
|
||||
serverObject = [[self alloc] init];
|
||||
[serverObject performSelectorOnMainThread: @selector(testPerform:)
|
||||
withObject: @"84"
|
||||
waitUntilDone: NO];
|
||||
|
||||
[(id)[serverConnection rootProxy] setServer: serverObject];
|
||||
[serverObject release];
|
||||
|
||||
|
@ -70,6 +75,12 @@ id myServer;
|
|||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
- (void) testPerform: (id)anObject
|
||||
{
|
||||
NSLog(@"Test perform: %@", anObject);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int
|
||||
|
@ -82,7 +93,6 @@ main(int argc, char *argv[], char **env)
|
|||
#endif
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
|
||||
[Tester startup];
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
[pool release];
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#include <Foundation/NSFileHandle.h>
|
||||
#include <Foundation/NSManager.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSURL.h>
|
||||
#include <assert.h>
|
||||
|
||||
int
|
||||
|
@ -26,7 +28,7 @@ main ()
|
|||
assert(dst != nil);
|
||||
|
||||
d0 = [[src readDataToEndOfFile] retain];
|
||||
[dst writeData:d0];
|
||||
[(NSFileHandle*)dst writeData: d0];
|
||||
[src release];
|
||||
[dst release];
|
||||
[pool release];
|
||||
|
@ -44,5 +46,11 @@ main ()
|
|||
else
|
||||
printf("Test failed\n");
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
src = [NSURL URLWithString: @"http://www.w3.org/index.html"];
|
||||
d0 = [src resourceDataUsingCache: NO];
|
||||
NSLog(@"Data is %@", d0);
|
||||
[pool release];
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue