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:
Richard Frith-Macdonald 2005-02-23 16:05:09 +00:00
parent 0e7313bb94
commit 2a9f4ec7c0
24 changed files with 2735 additions and 1640 deletions

View file

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

View file

@ -58,6 +58,9 @@
#if USE_ZLIB
gzFile gzDescriptor;
#endif
#ifdef __MINGW32__
WSAEVENT event;
#endif
}
- (id) initAsClientAtAddress: (NSString*)address

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

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

View 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

View 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

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

View 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

View file

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

View file

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