diff --git a/Headers/gnustep/base/RunLoop.h b/Headers/gnustep/base/RunLoop.h new file mode 100644 index 000000000..4fdc96573 --- /dev/null +++ b/Headers/gnustep/base/RunLoop.h @@ -0,0 +1,46 @@ +#ifndef __RunLoop_h_OBJECTS_INCLUDE +#define __RunLoop_h_OBJECTS_INCLUDE + +#include +#include +#include +#include +#include +#include + +@interface RunLoop : NSObject +{ + fd_set _fds; + NSMapTable *_fd_2_object; + Bag *_fd_objects; + Heap *_timers; + NotificationDispatcher *_dispatcher; + Array *_queues; +} + +- (void) addFileDescriptor: (int)fd + invocation: invocation + forMode: (id )mode; +- (void) removeFileDescriptor: (int)fd + forMode: (id )mode; + +- (void) addTimer: timer forMode: (id )mode; + +- limitDateForMode: (id )mode; +- (void) acceptInputForMode: (id )mode + beforeDate: date; + +- (void) run; +- (void) runUntilDate: limit_date; +- (BOOL) runMode: (id )mode + beforeDate: limit_date; + ++ (void) run; ++ (void) runUntilDate: date; + ++ currentInstance; + +@end + + +#endif /* __RunLoop_h_OBJECTS_INCLUDE */ diff --git a/Source/NSTimer.m b/Source/NSTimer.m new file mode 100644 index 000000000..88ca04b50 --- /dev/null +++ b/Source/NSTimer.m @@ -0,0 +1,154 @@ +/* Implementation of NSTimer for GNUstep + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Created: March 1996 + + This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +@implementation NSTimer + +/* This is the designated initializer. */ +- initWithTimeInterval: (NSTimeInterval)seconds + targetOrInvocation: t + selector: (SEL)sel + userInfo: info + repeats: (BOOL)f +{ + [super init]; + _interval = seconds; + _fire_date = [[NSDate alloc] initWithTimeIntervalSinceNow: seconds]; + _retain_count = 0; + _is_valid = YES; + _target = t; + _selector = sel; + _info = info; + _repeats = f; + return self; +} + +- (void) dealloc +{ + [_fire_date release]; + [super dealloc]; +} + ++ timerWithTimeInterval: (NSTimeInterval)ti + invocation: invocation + repeats: (BOOL)f +{ + return [[[self alloc] initWithTimeInterval: ti + targetOrInvocation: invocation + selector: NULL + userInfo: nil + repeats: f] + autorelease]; +} + ++ timerWithTimeInterval: (NSTimeInterval)ti + target: object + selector: (SEL)selector + userInfo: info + repeats: (BOOL)f +{ + return [[[self alloc] initWithTimeInterval: ti + targetOrInvocation: object + selector: selector + userInfo: info + repeats: f] + autorelease]; +} + ++ scheduledTimerWithTimeInterval: (NSTimeInterval)ti + invocation: invocation + repeats: (BOOL)f +{ + id t = [self timerWithTimeInterval: ti + invocation: invocation + repeats: f]; + [[RunLoop currentInstance] addTimer: t forMode: nil]; + return t; +} + ++ scheduledTimerWithTimeInterval: (NSTimeInterval)ti + target: object + selector: (SEL)selector + userInfo: info + repeats: (BOOL)f +{ + id t = [self timerWithTimeInterval: ti + target: object + selector: selector + userInfo: info + repeats: f]; + [[RunLoop currentInstance] addTimer: t forMode: nil]; + return t; +} + + +- (void) fire +{ + if (_selector) + [_target perform: _selector withObject: self]; + else + [_target invoke]; + + if (!_repeats) + [self invalidate]; + else if (_is_valid) + { + NSTimeInterval ti = [_fire_date timeIntervalSinceReferenceDate]; + NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; + assert (now < 0.0); + while (ti < now) // xxx remove this + ti += _interval; + [_fire_date release]; + assert (ti != NAN); + _fire_date = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate: ti]; + } +} + +- (void) invalidate +{ + assert (_is_valid); + _is_valid = NO; +} + +- (BOOL) isValid +{ + return _is_valid; +} + +- fireDate +{ + return _fire_date; +} + +- userInfo +{ + return _info; +} + +@end diff --git a/Source/RunLoop.m b/Source/RunLoop.m new file mode 100644 index 000000000..7ff88b7b3 --- /dev/null +++ b/Source/RunLoop.m @@ -0,0 +1,333 @@ +/* Implementation of object for waiting on several input sources + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Created: March 1996 + + This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Alternate names: InputDemuxer, InputListener + Alternate names for Notification classes: Dispatcher, EventDistributor, */ + +static int debug_run_loop = 1; + +@implementation RunLoop + +static RunLoop *current_run_loop; + ++ (void) initialize +{ + if (self == [RunLoop class]) + current_run_loop = [self new]; +} + +/* This is the designated initializer. */ +- init +{ + FD_ZERO (&_fds); + _fd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + _fd_objects = [Bag new]; + _timers = [Heap new]; + _dispatcher = [NotificationDispatcher defaultInstance]; + return self; +} + +- notificationDispatcher +{ + return _dispatcher; +} + +- (void) setNotificationDispatcher: d +{ + _dispatcher = d; +} + + +/* xxx This is similar to [NotificationDispatcher addObserver...] + Perhaps NotificationDispatcher and InputDemuxer will be merged. */ + +- (void) addFileDescriptor: (int)fd + invocation: invocation + forMode: (id )mode +{ + /* xxx But actually we should let it be added multiple times, + and keep count. (?) */ + assert (!NSMapGet (_fd_2_object, (void*)fd)); + NSMapInsert (_fd_2_object, (void*)fd, invocation); + FD_SET (fd, &_fds); +} + +- (void) removeFileDescriptor: (int)fd + forMode: (id )mode +{ + assert (NSMapGet (_fd_2_object, (void*)fd)); + NSMapRemove (_fd_2_object, (void*)fd); + FD_CLR (fd, &_fds); +} + +- (void) addTimer: timer + forMode: (id )mode +{ + assert (_timers); + [_timers addObjectIfAbsent: timer]; +} + + +/* Running the loop. */ + +- limitDateForMode: (id )mode +{ +#if 1 + return nil; +#else + NSTimer *min_timer = nil; + + /* Does this properly handle timers that have been sent -invalidate? */ + while ((min_timer = [_timers minObject]) + && ([[min_timer fireDate] timeIntervalSinceNow] > 0)) + { + [_timers removeFirstObject]; + /* Firing will also increment its fireDate, if it is repeating. */ + if ([min_timer isValid]) + { + [min_timer fire]; + if ([[min_timer fireDate] timeIntervalSinceNow] < 0) + [_timers addObject: min_timer]; + } + } + if (debug_run_loop) + printf ("limit date %f\n", + [[min_timer fireDate] timeIntervalSinceReferenceDate]); + return [min_timer fireDate]; +#endif +} + +- (void) acceptInputForMode: (id )mode beforeDate: limit_date +{ + NSTimeInterval ti; + struct timeval timeout; + void *select_timeout; + fd_set fds_copy; + int select_return; + int fd_index; + +#if 0 + /* If there are no input sources to listen to, just return. */ + if (NSCountMapTable (_fd_2_object) == 0) + return; +#endif + + /* Find out how much time we should wait, and set SELECT_TIMEOUT. */ + if (limit_date + && ((ti = [limit_date timeIntervalSinceNow]) < LONG_MAX)) + { + if (debug_run_loop) + printf ("accept input before %f (seconds from now %f)\n", + [limit_date timeIntervalSinceReferenceDate], ti); + /* If LIMIT_DATE has already past, return immediately. */ + if (ti < 0) + { + if (debug_run_loop) + printf ("limit date past, returning\n"); + return; + } + + timeout.tv_sec = ti; + timeout.tv_usec = ti * 1000000.0; + select_timeout = &timeout; + } + else + { + if (debug_run_loop) + printf ("accept input waiting forever\n"); + select_timeout = NULL; + } + + fds_copy = _fds; + + /* Wait for incoming data, listening to the file descriptors in FDS. */ + select_return = select (FD_SETSIZE, &fds_copy, NULL, NULL, select_timeout); + + if (debug_run_loop) + printf ("select returned %d\n", select_return); + + if (select_return < 0) + { + perror ("[TcpInPort receivePacketWithTimeout:] select()"); + abort (); + } + else if (select_return == 0) + return; + + /* Look at all the file descriptors select() says are ready for reading; + invoke the corresponding invocation for each of the ready ones. */ + for (fd_index = 0; fd_index < FD_SETSIZE; fd_index++) + if (FD_ISSET (fd_index, &fds_copy)) + { + id fd_invocation = (id) NSMapGet (_fd_2_object, (void*)fd_index); + assert (fd_invocation); + [fd_invocation + invokeWithObject: [NSNumber numberWithInt: fd_index]]; + /* xxx We can get rid of this NSNumber autorelease later. */ + } +} + +- (BOOL) runMode: (id )mode + beforeDate: date +{ + id d; + + /* If DATE is already later than now, just return. */ + if ([date timeIntervalSinceNow] < 0) + { + if (debug_run_loop) + printf ("run mode before date already past\n"); + return NO; + } + + /* Find out how long we can wait; and fire timers that are ready. */ + d = [self limitDateForMode: nil]; + if (!d) + d = date; + + /* Wait, listening to our input sources. */ + [self acceptInputForMode: mode + beforeDate: d]; + return YES; +} + +- (void) runUntilDate: date +{ + volatile double ti; + + ti = [date timeIntervalSinceNow]; + assert (ti != NAN); + /* Positive values are in the future. */ + while (ti > 0) + { + id arp = [NSAutoreleasePool new]; + if (debug_run_loop) + printf ("run until date %f seconds from now\n", ti); + [self runMode: nil beforeDate: date]; + [arp release]; + ti = [date timeIntervalSinceNow]; + } +} + +- (void) run +{ + [self runUntilDate: [NSDate distantFuture]]; +} + +/* Class methods that send messages to the current instance. */ + ++ (void) run +{ + assert (current_run_loop); + [current_run_loop run]; +} + ++ (void) runUntilDate: date +{ + assert (current_run_loop); + [current_run_loop runUntilDate: date]; +} + ++ currentInstance +{ + assert (current_run_loop); + return current_run_loop; +} + +@end + + + +@implementation NSObject (PerformingAfterDelay) + +- (void) performSelector: (SEL)sel afterDelay: (NSTimeInterval)delay +{ + +} + +@end + + + +#if 0 +- getNotificationWithName: (id )name + object: object + inMode: (id )mode + beforeDate: date +{ + /* See if any timers should fire, and fire them. */ + + /* Figure out how long we can listen to file descriptors before, either, + we need to fire another timer, or we need to return before DATE. */ + + /* Wait, listening to the file descriptors. */ + + /* Process active file descriptors. */ + + /* Is it time to return? If not, go back and check timers, + otherwise return. */ +} + +/* Some alternate names */ +- waitForNotificationWithName: (id )name + object: object + inMode: (id )mode + untilDate: date +{ +} + +@end + + +/* The old alternate names */ +- (void) makeNotificationsForFileDescriptor: (int)fd + forMode: (id )mode + name: (id )name + object: object + postingTo: (id )poster + postingStyle: style +- (void) addFileDescriptor: (int)fd + forMode: (id )mode + postingWithName: (id )name + object: object; +- (void) addFileDescriptor: (int)fd + withAttender: (id )object +- (void) addObserver: observer + selector: (SEL) + ofName: fileDescriptorString + withAttender: (id )object + +#endif diff --git a/Source/objects/RunLoop.h b/Source/objects/RunLoop.h new file mode 100644 index 000000000..4fdc96573 --- /dev/null +++ b/Source/objects/RunLoop.h @@ -0,0 +1,46 @@ +#ifndef __RunLoop_h_OBJECTS_INCLUDE +#define __RunLoop_h_OBJECTS_INCLUDE + +#include +#include +#include +#include +#include +#include + +@interface RunLoop : NSObject +{ + fd_set _fds; + NSMapTable *_fd_2_object; + Bag *_fd_objects; + Heap *_timers; + NotificationDispatcher *_dispatcher; + Array *_queues; +} + +- (void) addFileDescriptor: (int)fd + invocation: invocation + forMode: (id )mode; +- (void) removeFileDescriptor: (int)fd + forMode: (id )mode; + +- (void) addTimer: timer forMode: (id )mode; + +- limitDateForMode: (id )mode; +- (void) acceptInputForMode: (id )mode + beforeDate: date; + +- (void) run; +- (void) runUntilDate: limit_date; +- (BOOL) runMode: (id )mode + beforeDate: limit_date; + ++ (void) run; ++ (void) runUntilDate: date; + ++ currentInstance; + +@end + + +#endif /* __RunLoop_h_OBJECTS_INCLUDE */