mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 00:30:53 +00:00
Added implementation of new methods for notification of readiness of
file descriptors for reading and writing. Done by Richard Frith-Macdonald <richard@brainstorm.co.uk>. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1890 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
5a60c7e987
commit
1c3b575999
1 changed files with 222 additions and 103 deletions
325
Source/RunLoop.m
325
Source/RunLoop.m
|
@ -52,6 +52,7 @@
|
||||||
Alternate names for Notification classes: Dispatcher, EventDistributor, */
|
Alternate names for Notification classes: Dispatcher, EventDistributor, */
|
||||||
|
|
||||||
#include <gnustep/base/preface.h>
|
#include <gnustep/base/preface.h>
|
||||||
|
#include <gnustep/base/Bag.h>
|
||||||
#include <gnustep/base/RunLoop.h>
|
#include <gnustep/base/RunLoop.h>
|
||||||
#include <gnustep/base/Heap.h>
|
#include <gnustep/base/Heap.h>
|
||||||
#include <Foundation/NSMapTable.h>
|
#include <Foundation/NSMapTable.h>
|
||||||
|
@ -69,6 +70,161 @@
|
||||||
Just define it to use memset(). */
|
Just define it to use memset(). */
|
||||||
#define bzero(PTR, LEN) memset (PTR, 0, LEN)
|
#define bzero(PTR, LEN) memset (PTR, 0, LEN)
|
||||||
|
|
||||||
|
|
||||||
|
/* Local class to hold information about file descriptors to be watched
|
||||||
|
and the objects to which messages are to be sent when the descriptors
|
||||||
|
are readable or writable. */
|
||||||
|
|
||||||
|
|
||||||
|
@interface FdInfo: NSObject
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
id receiver;
|
||||||
|
}
|
||||||
|
-(int)getFd;
|
||||||
|
-setFd:(int)desc;
|
||||||
|
-getReceiver;
|
||||||
|
-setReceiver:anObj;
|
||||||
|
-initWithFd:(int)desc andReceiver:anObj;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FdInfo
|
||||||
|
-(int)getFd {
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
- setFd: (int)desc {
|
||||||
|
fd = desc;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
-getReceiver {
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
-setReceiver: anObj {
|
||||||
|
if (receiver != nil) {
|
||||||
|
[receiver release];
|
||||||
|
}
|
||||||
|
receiver = [anObj retain];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
-initWithFd:(int)desc andReceiver:anObj { /* Designated initializer */
|
||||||
|
[super init];
|
||||||
|
[self setFd: desc];
|
||||||
|
return [self setReceiver: anObj];
|
||||||
|
}
|
||||||
|
-init {
|
||||||
|
return [self initWithFd:-1 andReceiver:nil];
|
||||||
|
}
|
||||||
|
-(void)dealloc {
|
||||||
|
if (receiver != nil) {
|
||||||
|
[receiver release];
|
||||||
|
}
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
/* Adding and removing file descriptors. */
|
||||||
|
|
||||||
|
@implementation RunLoop(GNUstepExtensions)
|
||||||
|
|
||||||
|
- (void) addReadDescriptor: (int)fd
|
||||||
|
object: (id <FdListening>)listener
|
||||||
|
forMode: (id <String>)mode
|
||||||
|
{
|
||||||
|
Bag *fd_listeners;
|
||||||
|
FdInfo *info;
|
||||||
|
|
||||||
|
/* Remove any existing handler for the specified descriptor. */
|
||||||
|
[self removeReadDescriptor: fd forMode: mode];
|
||||||
|
|
||||||
|
/* Create new object to hold information. */
|
||||||
|
info = [[FdInfo alloc] initWithFd: fd andReceiver: listener];
|
||||||
|
|
||||||
|
/* Ensure we have a bag to put it in. */
|
||||||
|
fd_listeners = NSMapGet (_mode_2_fd_listeners, mode);
|
||||||
|
if (!fd_listeners)
|
||||||
|
{
|
||||||
|
fd_listeners = [Bag new];
|
||||||
|
NSMapInsert (_mode_2_fd_listeners, mode, fd_listeners);
|
||||||
|
[fd_listeners release];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add our new handler information to the bag. */
|
||||||
|
[fd_listeners addObject: info];
|
||||||
|
[info release];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) addWriteDescriptor: (int)fd
|
||||||
|
object: (id <FdSpeaking>)speaker
|
||||||
|
forMode: (id <String>)mode
|
||||||
|
{
|
||||||
|
Bag *fd_speakers;
|
||||||
|
FdInfo *info;
|
||||||
|
|
||||||
|
/* Remove any existing handler for the specified descriptor. */
|
||||||
|
[self removeWriteDescriptor: fd forMode: mode];
|
||||||
|
|
||||||
|
/* Create new object to hold information. */
|
||||||
|
info = [[FdInfo alloc] initWithFd: fd andReceiver: speaker];
|
||||||
|
|
||||||
|
/* Ensure we have a bag to put it in. */
|
||||||
|
fd_speakers = NSMapGet (_mode_2_fd_speakers, mode);
|
||||||
|
if (!fd_speakers)
|
||||||
|
{
|
||||||
|
fd_speakers = [Bag new];
|
||||||
|
NSMapInsert (_mode_2_fd_speakers, mode, fd_speakers);
|
||||||
|
[fd_speakers release];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add our new handler information to the bag. */
|
||||||
|
[fd_speakers addObject: info];
|
||||||
|
[info release];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) removeReadDescriptor: (int)fd
|
||||||
|
forMode: (id <String>)mode
|
||||||
|
{
|
||||||
|
Bag* fd_listeners;
|
||||||
|
|
||||||
|
fd_listeners = NSMapGet (_mode_2_fd_listeners, mode);
|
||||||
|
if (fd_listeners)
|
||||||
|
{
|
||||||
|
void* es = [fd_listeners newEnumState];
|
||||||
|
id info;
|
||||||
|
|
||||||
|
while ((info=[fd_listeners nextObjectWithEnumState: &es])!=NO_OBJECT)
|
||||||
|
{
|
||||||
|
if ([info getFd] == fd)
|
||||||
|
{
|
||||||
|
[fd_listeners removeObject: info];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) removeWriteDescriptor: (int)fd
|
||||||
|
forMode: (id <String>)mode
|
||||||
|
{
|
||||||
|
Bag* fd_speakers;
|
||||||
|
|
||||||
|
fd_speakers = NSMapGet (_mode_2_fd_speakers, mode);
|
||||||
|
if (fd_speakers)
|
||||||
|
{
|
||||||
|
void* es = [fd_speakers newEnumState];
|
||||||
|
id info;
|
||||||
|
|
||||||
|
while ((info=[fd_speakers nextObjectWithEnumState: &es])!=NO_OBJECT)
|
||||||
|
{
|
||||||
|
if ([info getFd] == fd)
|
||||||
|
{
|
||||||
|
[fd_speakers removeObject: info];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
static int debug_run_loop = 0;
|
static int debug_run_loop = 0;
|
||||||
|
|
||||||
@implementation RunLoop
|
@implementation RunLoop
|
||||||
|
@ -92,6 +248,8 @@ static RunLoop *current_run_loop;
|
||||||
NSObjectMapValueCallBacks, 0);
|
NSObjectMapValueCallBacks, 0);
|
||||||
_mode_2_fd_listeners = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
_mode_2_fd_listeners = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
||||||
NSObjectMapValueCallBacks, 0);
|
NSObjectMapValueCallBacks, 0);
|
||||||
|
_mode_2_fd_speakers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
||||||
|
NSObjectMapValueCallBacks, 0);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,48 +258,6 @@ static RunLoop *current_run_loop;
|
||||||
return _current_mode;
|
return _current_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Adding and removing file descriptors. */
|
|
||||||
|
|
||||||
- (void) addFileDescriptor: (int)fd
|
|
||||||
object: listener
|
|
||||||
forMode: (id <String>)mode
|
|
||||||
{
|
|
||||||
/* xxx Perhaps this should be a Bag instead. */
|
|
||||||
Array *fd_listeners;
|
|
||||||
|
|
||||||
/* xxx We need to keep track of the FD too!
|
|
||||||
Perhaps I'll make a FileDescriptor class to hold all this;
|
|
||||||
it will be more analogous the Port object. */
|
|
||||||
[self notImplemented: _cmd];
|
|
||||||
|
|
||||||
fd_listeners = NSMapGet (_mode_2_fd_listeners, mode);
|
|
||||||
if (!fd_listeners)
|
|
||||||
{
|
|
||||||
fd_listeners = [Array new];
|
|
||||||
NSMapInsert (_mode_2_fd_listeners, mode, fd_listeners);
|
|
||||||
[fd_listeners release];
|
|
||||||
}
|
|
||||||
[fd_listeners addObject: listener];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) removeFileDescriptor: (int)fd
|
|
||||||
forMode: (id <String>)mode
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
[self notImplemented: _cmd];
|
|
||||||
#else
|
|
||||||
Array *fd_listeners;
|
|
||||||
|
|
||||||
fd_listeners = NSMapGet (_mode_2_fd_listeners, mode);
|
|
||||||
if (!fd_listeners)
|
|
||||||
/* xxx Careful, this is only suppose to "undo" one -addPort:.
|
|
||||||
If we change the -removeObject implementation later to remove
|
|
||||||
all instances of port, we'll have to change this code here. */
|
|
||||||
[fd_listeners removeObject: port];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Adding and removing port objects. */
|
/* Adding and removing port objects. */
|
||||||
|
|
||||||
|
@ -252,13 +368,11 @@ static RunLoop *current_run_loop;
|
||||||
fd_set fds; /* The file descriptors we will listen to. */
|
fd_set fds; /* The file descriptors we will listen to. */
|
||||||
fd_set read_fds; /* Copy for listening to read-ready fds. */
|
fd_set read_fds; /* Copy for listening to read-ready fds. */
|
||||||
fd_set exception_fds; /* Copy for listening to exception fds. */
|
fd_set exception_fds; /* Copy for listening to exception fds. */
|
||||||
|
fd_set write_fds; /* Copy for listening for write-ready fds. */
|
||||||
int select_return;
|
int select_return;
|
||||||
|
int fd_index;
|
||||||
NSMapTable *fd_2_object;
|
NSMapTable *fd_2_object;
|
||||||
id saved_mode;
|
id saved_mode;
|
||||||
id ports;
|
|
||||||
int num_of_ports;
|
|
||||||
int port_fd_count = 128; // xxx #define this constant
|
|
||||||
int port_fd_array[port_fd_count];
|
|
||||||
|
|
||||||
assert (mode);
|
assert (mode);
|
||||||
saved_mode = _current_mode;
|
saved_mode = _current_mode;
|
||||||
|
@ -316,74 +430,82 @@ static RunLoop *current_run_loop;
|
||||||
an empty map for keeping track of which object is associated
|
an empty map for keeping track of which object is associated
|
||||||
with which file descriptor. */
|
with which file descriptor. */
|
||||||
FD_ZERO (&fds);
|
FD_ZERO (&fds);
|
||||||
|
FD_ZERO (&write_fds);
|
||||||
fd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks,
|
fd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks,
|
||||||
NSObjectMapValueCallBacks, 0);
|
NSObjectMapValueCallBacks, 0);
|
||||||
|
|
||||||
/* If a port is invalid, remove it from this mode. */
|
|
||||||
ports = NSMapGet (_mode_2_in_ports, mode);
|
|
||||||
{
|
|
||||||
id port;
|
|
||||||
int i;
|
|
||||||
for (i = [ports count]-1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
port = [ports objectAtIndex: i];
|
|
||||||
if (![port isValid])
|
|
||||||
[ports removeObjectAtIndex: i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
num_of_ports = 0;
|
|
||||||
|
|
||||||
/* Do the pre-listening set-up for the file descriptors of this mode. */
|
/* Do the pre-listening set-up for the file descriptors of this mode. */
|
||||||
{
|
{
|
||||||
|
Bag* fdInfo;
|
||||||
|
|
||||||
|
fdInfo = NSMapGet (_mode_2_fd_speakers, mode);
|
||||||
|
if (fdInfo) {
|
||||||
|
void* es = [fdInfo newEnumState];
|
||||||
|
id info;
|
||||||
|
|
||||||
|
while ((info=[fdInfo nextObjectWithEnumState: &es])!=NO_OBJECT) {
|
||||||
|
int fd = [info getFd];
|
||||||
|
|
||||||
|
FD_SET (fd, &write_fds);
|
||||||
|
NSMapInsert (fd_2_object, (void*)fd, [info getReceiver]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fdInfo = NSMapGet (_mode_2_fd_listeners, mode);
|
||||||
|
if (fdInfo) {
|
||||||
|
void* es = [fdInfo newEnumState];
|
||||||
|
id info;
|
||||||
|
|
||||||
|
while ((info=[fdInfo nextObjectWithEnumState: &es])!=NO_OBJECT) {
|
||||||
|
int fd = [info getFd];
|
||||||
|
|
||||||
|
FD_SET (fd, &fds);
|
||||||
|
NSMapInsert (fd_2_object, (void*)fd, [info getReceiver]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the pre-listening set-up for the ports of this mode. */
|
/* Do the pre-listening set-up for the ports of this mode. */
|
||||||
{
|
{
|
||||||
|
id ports = NSMapGet (_mode_2_in_ports, mode);
|
||||||
if (ports)
|
if (ports)
|
||||||
{
|
{
|
||||||
id port;
|
id port;
|
||||||
int i;
|
int i;
|
||||||
int fd_count = port_fd_count;
|
|
||||||
int fd_array[port_fd_count];
|
|
||||||
|
|
||||||
/* Ask our ports for the list of file descriptors they
|
/* If a port is invalid, remove it from this mode. */
|
||||||
want us to listen to; add these to FD_LISTEN_SET.
|
|
||||||
Save the list of ports for later use. */
|
|
||||||
for (i = [ports count]-1; i >= 0; i--)
|
for (i = [ports count]-1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
port = [ports objectAtIndex: i];
|
||||||
|
if (![port isValid])
|
||||||
|
[ports removeObjectAtIndex: i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ask our ports for the list of file descriptors they
|
||||||
|
want us to listen to; add these to FD_LISTEN_SET. */
|
||||||
|
for (i = [ports count]-1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
int port_fd_count = 128; // xxx #define this constant
|
||||||
|
int port_fd_array[port_fd_count];
|
||||||
port = [ports objectAtIndex: i];
|
port = [ports objectAtIndex: i];
|
||||||
if ([port respondsTo: @selector(getFds:count:)])
|
if ([port respondsTo: @selector(getFds:count:)])
|
||||||
[port getFds: fd_array count: &fd_count];
|
[port getFds: port_fd_array count: &port_fd_count];
|
||||||
else
|
|
||||||
fd_count = 0;
|
|
||||||
if (debug_run_loop)
|
if (debug_run_loop)
|
||||||
printf("\tRunLoop listening to %d sockets\n", fd_count);
|
printf("\tRunLoop listening to %d sockets\n", port_fd_count);
|
||||||
num_of_ports += fd_count;
|
while (port_fd_count--)
|
||||||
if (num_of_ports > port_fd_count)
|
|
||||||
{
|
{
|
||||||
/* xxx Uh oh our array isn't big enough */
|
FD_SET (port_fd_array[port_fd_count], &fds);
|
||||||
perror ("RunLoop attempt to listen to too many ports\n");
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
while (fd_count--)
|
|
||||||
{
|
|
||||||
int j = num_of_ports - fd_count - 1;
|
|
||||||
port_fd_array[j] = fd_array[fd_count];
|
|
||||||
FD_SET (port_fd_array[j], &fds);
|
|
||||||
NSMapInsert (fd_2_object,
|
NSMapInsert (fd_2_object,
|
||||||
(void*)port_fd_array[j],
|
(void*)port_fd_array[port_fd_count], port);
|
||||||
port);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (debug_run_loop)
|
|
||||||
printf("\tRunLoop listening to %d total ports\n", num_of_ports);
|
|
||||||
|
|
||||||
/* Wait for incoming data, listening to the file descriptors in _FDS. */
|
/* Wait for incoming data, listening to the file descriptors in _FDS. */
|
||||||
read_fds = fds;
|
read_fds = fds;
|
||||||
exception_fds = fds;
|
exception_fds = fds;
|
||||||
select_return = select (FD_SETSIZE, &read_fds, NULL, &exception_fds,
|
select_return = select (FD_SETSIZE, &read_fds, &write_fds, &exception_fds,
|
||||||
select_timeout);
|
select_timeout);
|
||||||
|
|
||||||
if (debug_run_loop)
|
if (debug_run_loop)
|
||||||
|
@ -405,25 +527,21 @@ static RunLoop *current_run_loop;
|
||||||
|
|
||||||
/* Look at all the file descriptors select() says are ready for reading;
|
/* Look at all the file descriptors select() says are ready for reading;
|
||||||
notify the corresponding object for each of the ready fd's. */
|
notify the corresponding object for each of the ready fd's. */
|
||||||
{
|
for (fd_index = 0; fd_index < FD_SETSIZE; fd_index++)
|
||||||
if (ports)
|
{
|
||||||
{
|
if (FD_ISSET (fd_index, &write_fds))
|
||||||
int i;
|
{
|
||||||
|
id fd_object = (id) NSMapGet (fd_2_object, (void*)fd_index);
|
||||||
for (i = num_of_ports - 1; i >= 0; i--)
|
assert (fd_object);
|
||||||
{
|
[fd_object readyForWritingOnFileDescriptor: fd_index];
|
||||||
if (FD_ISSET (port_fd_array[i], &read_fds))
|
}
|
||||||
{
|
if (FD_ISSET (fd_index, &read_fds))
|
||||||
id fd_object = (id) NSMapGet (fd_2_object,
|
{
|
||||||
(void*)port_fd_array[i]);
|
id fd_object = (id) NSMapGet (fd_2_object, (void*)fd_index);
|
||||||
assert (fd_object);
|
assert (fd_object);
|
||||||
[fd_object readyForReadingOnFileDescriptor:
|
[fd_object readyForReadingOnFileDescriptor: fd_index];
|
||||||
port_fd_array[i]];
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clean up before returning. */
|
/* Clean up before returning. */
|
||||||
NSFreeMapTable (fd_2_object);
|
NSFreeMapTable (fd_2_object);
|
||||||
_current_mode = saved_mode;
|
_current_mode = saved_mode;
|
||||||
|
@ -607,3 +725,4 @@ id RunLoopDefaultMode = @"RunLoopDefaultMode";
|
||||||
withAttender: (id <FileDescriptorAttending>)object
|
withAttender: (id <FileDescriptorAttending>)object
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue