diff --git a/Headers/gnustep/base/FastArray.x b/Headers/gnustep/base/FastArray.x index fc619afe8..4f7ab4fac 100644 --- a/Headers/gnustep/base/FastArray.x +++ b/Headers/gnustep/base/FastArray.x @@ -58,7 +58,7 @@ * Defined if no release operation is needed for an item * FAST_ARRAY_NO_RETAIN * Defined if no retain operation is needed for a an item - + */ #ifndef FAST_ARRAY_RETAIN #define FAST_ARRAY_RETAIN(X) [(X).obj retain] #endif @@ -103,7 +103,6 @@ */ #include - struct _FastArray { FastArrayItem *ptr; unsigned count; @@ -114,6 +113,67 @@ struct _FastArray { typedef struct _FastArray FastArray_t; typedef struct _FastArray *FastArray; +static INLINE void +FastArrayGrow(FastArray array) +{ + unsigned next; + unsigned size; + FastArrayItem *tmp; + + next = array->cap + array->old; + size = next*sizeof(FastArrayItem); +#if GS_WITH_GC + tmp = (FastArrayItem*)GC_REALLOC(size); +#else + tmp = NSZoneRealloc(array->zone, array->ptr, size); +#endif + + if (tmp == 0) + { + [NSException raise: NSMallocException + format: @"failed to grow FastArray"]; + } + array->ptr = tmp; + array->old = array->cap; + array->cap = next; +} + +static INLINE void +FastArrayInsertItem(FastArray array, FastArrayItem item, unsigned index) +{ + unsigned i; + + FAST_ARRAY_RETAIN(item); + FAST_ARRAY_CHECK; + if (array->count == array->cap) + { + FastArrayGrow(array); + } + for (i = ++array->count; i > index; i--) + { + array->ptr[i] = array->ptr[i-1]; + } + array->ptr[i] = item; + FAST_ARRAY_CHECK; +} + +static INLINE void +FastArrayInsertItemNoRetain(FastArray array, FastArrayItem item, unsigned index) +{ + unsigned i; + + FAST_ARRAY_CHECK; + if (array->count == array->cap) + { + FastArrayGrow(array); + } + for (i = ++array->count; i > index; i--) + { + array->ptr[i] = array->ptr[i-1]; + } + array->ptr[i] = item; + FAST_ARRAY_CHECK; +} static INLINE void FastArrayAddItem(FastArray array, FastArrayItem item) @@ -122,31 +182,78 @@ FastArrayAddItem(FastArray array, FastArrayItem item) FAST_ARRAY_CHECK; if (array->count == array->cap) { - unsigned next; - unsigned size; - FastArrayItem *tmp; - - next = array->cap + array->old; - size = next*sizeof(FastArrayItem); -#if GS_WITH_GC - tmp = (FastArrayItem*)GC_REALLOC(size); -#else - tmp = NSZoneRealloc(array->zone, array->ptr, size); -#endif - - if (tmp == 0) - { - [NSException raise: NSMallocException - format: @"failed to grow FastArray"]; - } - array->ptr = tmp; - array->old = array->cap; - array->cap = next; + FastArrayGrow(array); } array->ptr[array->count++] = item; FAST_ARRAY_CHECK; } +static INLINE void +FastArrayAddItemNoRetain(FastArray array, FastArrayItem item) +{ + FAST_ARRAY_CHECK; + if (array->count == array->cap) + { + FastArrayGrow(array); + } + array->ptr[array->count++] = item; + FAST_ARRAY_CHECK; +} + +/* + * The comparator function takes two items as arguments, the first is the + * item to be added, the second is the item already in the array. + * The function should return <0 if the item to be added is 'less than' + * the item in the array, >0 if it is greater, and 0 if it is equal. + */ +static INLINE unsigned +FastArrayInsertionPosition(FastArray array, FastArrayItem item, int (*sorter)()) +{ + unsigned upper = array->count; + unsigned index = upper/2; + unsigned lower = 0; + + /* + * Binary search for an item equal to the one to be inserted. + * + while (upper != lower) + { + int comparison = (*sorter)(item, array->ptr[index]); + + if (comparison < 0) + { + upper = index; + } + else if (comparison > 0) + { + lower = index + 1; + } + else + { + break; + } + index = lower+(upper-lower)/2; + } + /* + * Now skip past any equal items so the insertion point is AFTER any + * items that are equal to the new one. + */ + while (index < array->count && (*sorter)(item, array->ptr[index]) >= 0) + { + index++; + } + return index; +} + +static INLINE void +FastArrayInsertSorted(FastArray array, FastArrayItem item, int (*sorter)()) +{ + unsigned index; + + index = FastArrayInsertionPosition(array, item, sorter); + FastArrayInsertItem(array, item, index); +} + static INLINE void FastArrayRemoveItemAtIndex(FastArray array, unsigned index) { @@ -159,6 +266,17 @@ FastArrayRemoveItemAtIndex(FastArray array, unsigned index) FAST_ARRAY_RELEASE(tmp); } +static INLINE void +FastArrayRemoveItemAtIndexNoRelease(FastArray array, unsigned index) +{ + FastArrayItem tmp; + NSCAssert(index < array->count, NSInvalidArgumentException); + tmp = array->ptr[index]; + while (++index < array->count) + array->ptr[index-1] = array->ptr[index]; + array->count--; +} + static INLINE void FastArraySetItemAtIndex(FastArray array, FastArrayItem item, unsigned index) { diff --git a/Headers/gnustep/base/NSDate.h b/Headers/gnustep/base/NSDate.h index c953b3cbf..6794a65e3 100644 --- a/Headers/gnustep/base/NSDate.h +++ b/Headers/gnustep/base/NSDate.h @@ -105,6 +105,8 @@ typedef double NSTimeInterval; NSTimeInterval seconds_since_ref; } @end + +NSTimeInterval GSTimeNow(); /* Get time since reference date */ #endif diff --git a/Headers/gnustep/base/NSNotificationQueue.h b/Headers/gnustep/base/NSNotificationQueue.h index 4e0b426fb..3c5dec710 100644 --- a/Headers/gnustep/base/NSNotificationQueue.h +++ b/Headers/gnustep/base/NSNotificationQueue.h @@ -24,7 +24,7 @@ /* Interface for NSNotificationQueue for GNUStep Copyright (C) 1996 Free Software Foundation, Inc. - Modified by: Richard Frith-Macdonald + Modified by: Richard Frith-Macdonald This file is part of the GNUstep Base Library. @@ -55,15 +55,15 @@ */ typedef enum { - NSPostWhenIdle, - NSPostASAP, - NSPostNow + NSPostWhenIdle, + NSPostASAP, + NSPostNow } NSPostingStyle; typedef enum { - NSNotificationNoCoalescing = 0, - NSNotificationCoalescingOnName = 1, - NSNotificationCoalescingOnSender = 2, + NSNotificationNoCoalescing = 0, + NSNotificationCoalescingOnName = 1, + NSNotificationCoalescingOnSender = 2, } NSNotificationCoalescing; /* @@ -74,40 +74,39 @@ struct _NSNotificationQueueList; @interface NSNotificationQueue : NSObject { - NSNotificationCenter* center; - struct _NSNotificationQueueList* asapQueue; - struct _NSNotificationQueueList* idleQueue; - NSZone* zone; + NSNotificationCenter *center; + struct _NSNotificationQueueList *asapQueue; + struct _NSNotificationQueueList *idleQueue; + NSZone *zone; } /* Creating Notification Queues */ -+ (NSNotificationQueue*)defaultQueue; -- (id)init; -- (id)initWithNotificationCenter:(NSNotificationCenter*)notificationCenter; ++ (NSNotificationQueue*) defaultQueue; +- (id) initWithNotificationCenter: (NSNotificationCenter*)notificationCenter; /* Inserting and Removing Notifications From a Queue */ -- (void)dequeueNotificationsMatching:(NSNotification*)notification - coalesceMask:(unsigned int)coalesceMask; +- (void) dequeueNotificationsMatching:(NSNotification*)notification + coalesceMask:(unsigned int)coalesceMask; -- (void)enqueueNotification:(NSNotification*)notification - postingStyle:(NSPostingStyle)postingStyle; +- (void) enqueueNotification:(NSNotification*)notification + postingStyle:(NSPostingStyle)postingStyle; -- (void)enqueueNotification:(NSNotification*)notification - postingStyle:(NSPostingStyle)postingStyle - coalesceMask:(unsigned int)coalesceMask - forModes:(NSArray*)modes; - -/* Implementation used by the the NSRunLoop */ - -+ (void)runLoopIdle; -+ (void)runLoopASAP; -+ (BOOL)runLoopMore; -- (void)notifyIdle; -- (void)notifyASAP; -- (BOOL)notifyMore; +- (void) enqueueNotification:(NSNotification*)notification + postingStyle:(NSPostingStyle)postingStyle + coalesceMask:(unsigned int)coalesceMask + forModes:(NSArray*)modes; @end +#ifndef NO_GNUSTEP +/* + * Functions used by the the NSRunLoop + */ +extern void GSNotifyASAP(); +extern void GSNotifyIdle(); +extern BOOL GSNotifyMore(); +#endif + #endif /* __NSNotificationQueue_h__ */ diff --git a/Headers/gnustep/base/NSTimer.h b/Headers/gnustep/base/NSTimer.h index c099395d3..4ff25c32b 100644 --- a/Headers/gnustep/base/NSTimer.h +++ b/Headers/gnustep/base/NSTimer.h @@ -30,17 +30,20 @@ #include #include +/* + * NB. NSRunLoop is optimised using a hack that knows about the + * class layout for the fire date and invialidation flag in NSTimer. + * These MUST remain the first two items in the class. + */ @interface NSTimer : NSObject { - unsigned _repeats:1; - unsigned _is_valid:1; - unsigned _timer_filler:6; - unsigned _retain_count:24; - NSDate *_fire_date; + NSDate *_date; /* Must be first - for NSRunLoop optimisation */ + BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */ + BOOL _repeats; NSTimeInterval _interval; - id _target; - SEL _selector; - id _info; + id _target; + SEL _selector; + id _info; } /* Creating timer objects. */ diff --git a/Source/Makefile.postamble b/Source/Makefile.postamble index 54e71413a..395fa4417 100644 --- a/Source/Makefile.postamble +++ b/Source/Makefile.postamble @@ -214,6 +214,7 @@ $(GNUSTEP_OBJ_DIR)/NSUnarchiver.o \ # # Files that include FastArray.x will need a rebuild if it is changed. # +$(GNUSTEP_OBJ_DIR)/NSRunLoop.o \ $(GNUSTEP_OBJ_DIR)/NSSerializer.o \ $(GNUSTEP_OBJ_DIR)/NSUnarchiver.o \ : include/FastArray.x include/GSUnion.h diff --git a/Source/NSConnection.m b/Source/NSConnection.m index 2b85103e8..d46805628 100644 --- a/Source/NSConnection.m +++ b/Source/NSConnection.m @@ -293,23 +293,23 @@ static int messages_received_count; */ + (NSConnection*) defaultConnection { - static NSString* tkey = @"NSConnectionThreadKey"; - NSConnection* c; - NSThread* t; + static NSString *tkey = @"NSConnectionThreadKey"; + NSConnection *c; + NSMutableDictionary *d; - t = GSCurrentThread(); - c = (NSConnection*)[[t threadDictionary] objectForKey:tkey]; + d = GSCurrentThreadDictionary(); + c = (NSConnection*)[d objectForKey:tkey]; if (c != nil && [c isValid] == NO) { /* * If the default connection for this thread has been invalidated - * release it and create a new one. */ - [[t threadDictionary] removeObjectForKey:tkey]; + [d removeObjectForKey:tkey]; c = nil; } if (c == nil) { c = [NSConnection new]; - [[t threadDictionary] setObject:c forKey:tkey]; + [d setObject:c forKey:tkey]; [c release]; /* retained in dictionary. */ } return c; diff --git a/Source/NSDate.m b/Source/NSDate.m index 71d0e6d5b..5ecfe89c2 100644 --- a/Source/NSDate.m +++ b/Source/NSDate.m @@ -91,8 +91,8 @@ otherTime(NSDate* other) return [other timeIntervalSinceReferenceDate]; } -static NSTimeInterval -timeNow() +NSTimeInterval +GSTimeNow() { #if !defined(__WIN32__) && !defined(_WIN32) volatile NSTimeInterval interval; @@ -163,7 +163,7 @@ timeNow() + (NSTimeInterval) timeIntervalSinceReferenceDate { - return timeNow(); + return GSTimeNow(); } // Allocation and initializing @@ -171,7 +171,7 @@ timeNow() + (id) date { return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] - initWithTimeIntervalSinceReferenceDate: timeNow()]); + initWithTimeIntervalSinceReferenceDate: GSTimeNow()]); } + (id) dateWithNaturalLanguageString: (NSString*)string @@ -892,7 +892,7 @@ timeNow() - (id) init { - return [self initWithTimeIntervalSinceReferenceDate: timeNow()]; + return [self initWithTimeIntervalSinceReferenceDate: GSTimeNow()]; } - (id) initWithString: (NSString*)description @@ -919,7 +919,7 @@ timeNow() { // Get the current time, add the secs and init thyself return [self initWithTimeIntervalSinceReferenceDate: - timeNow() + secsToBeAdded]; + GSTimeNow() + secsToBeAdded]; } - (id)initWithTimeIntervalSince1970: (NSTimeInterval)seconds @@ -1013,7 +1013,7 @@ timeNow() - (NSTimeInterval) timeIntervalSinceNow { - return otherTime(self) - timeNow(); + return otherTime(self) - GSTimeNow(); } - (NSTimeInterval) timeIntervalSinceReferenceDate @@ -1126,7 +1126,7 @@ timeNow() - (NSTimeInterval) timeIntervalSinceNow { - return seconds_since_ref - timeNow(); + return seconds_since_ref - GSTimeNow(); } - (NSTimeInterval) timeIntervalSinceReferenceDate diff --git a/Source/NSGDictionary.m b/Source/NSGDictionary.m index d00b2f10a..e485e4f33 100644 --- a/Source/NSGDictionary.m +++ b/Source/NSGDictionary.m @@ -37,11 +37,7 @@ * instances of the string classes we know about! */ typedef struct { - Class *isa; - char *_contents_chars; - int _count; - NSZone *_zone; - unsigned _hash; + @defs(NSGCString) } *dictAccessToStringHack; static inline unsigned diff --git a/Source/NSNotificationQueue.m b/Source/NSNotificationQueue.m index 5039a4d55..817d0b7a3 100644 --- a/Source/NSNotificationQueue.m +++ b/Source/NSNotificationQueue.m @@ -63,36 +63,41 @@ static NSString* tkey = @"NotificationQueueListThreadKey"; +typedef struct { + @defs(NSNotificationQueue) +} *accessQueue; + + @interface NotificationQueueList : NSObject { - NotificationQueueList* next; - NSNotificationQueue* queue; +@public + NotificationQueueList *next; + NSNotificationQueue *queue; } -+ (NotificationQueueList*) currentList; -+ (void)registerQueue:(NSNotificationQueue*)q; -+ (void)unregisterQueue:(NSNotificationQueue*)q; -- (NotificationQueueList*) next; -- (NSNotificationQueue*) queue; ++ (void) registerQueue: (NSNotificationQueue*)q; ++ (void) unregisterQueue: (NSNotificationQueue*)q; @end -@implementation NotificationQueueList -+ (NotificationQueueList*) currentList +static NotificationQueueList* +currentList() { - NotificationQueueList* list; - NSThread* t; + NotificationQueueList *list; + NSMutableDictionary *d; - t = GSCurrentThread(); - list = (NotificationQueueList*)[[t threadDictionary] objectForKey:tkey]; + d = GSCurrentThreadDictionary(); + list = (NotificationQueueList*)[d objectForKey: tkey]; if (list == nil) { list = [NotificationQueueList new]; - [[t threadDictionary] setObject:list forKey:tkey]; - [list release]; /* retained in dictionary. */ + [d setObject: list forKey: tkey]; + RELEASE(list); /* retained in dictionary. */ } return list; } -+ (void)registerQueue:(NSNotificationQueue*)q +@implementation NotificationQueueList + ++ (void)registerQueue: (NSNotificationQueue*)q { NotificationQueueList* list; NotificationQueueList* elem; @@ -100,7 +105,7 @@ static NSString* tkey = @"NotificationQueueListThreadKey"; if (q == nil) return; /* Can't register nil object. */ - list = [self currentList]; /* List of queues for thread. */ + list = currentList(); /* List of queues for thread. */ if (list->queue == nil) list->queue = q; /* Make this the default. */ @@ -111,100 +116,73 @@ static NSString* tkey = @"NotificationQueueListThreadKey"; if (list->queue == q) return; /* Queue already registered. */ - elem = [NotificationQueueList new]; + elem = NSAllocateObject(self, 0, NSDefaultMallocZone()); elem->queue = q; list->next = elem; } -+ (void)unregisterQueue:(NSNotificationQueue*)q ++ (void)unregisterQueue: (NSNotificationQueue*)q { NotificationQueueList* list; if (q == nil) return; - list = [self currentList]; + list = currentList(); if (list->queue == q) { - NSThread* t; + NSMutableDictionary *d; - t = GSCurrentThread(); + d = GSCurrentThreadDictionary(); if (list->next) { NotificationQueueList* tmp = list->next; - [[t threadDictionary] setObject:tmp forKey:tkey]; - [tmp release]; /* retained in dictionary. */ + [d setObject: tmp forKey: tkey]; + RELEASE(tmp); /* retained in dictionary. */ } else - [[t threadDictionary] removeObjectForKey:tkey]; + [d removeObjectForKey: tkey]; } - else - while (list->next != nil) - { - if (list->next->queue == q) - { - NotificationQueueList* tmp = list->next; - - list->next = tmp->next; - [tmp release]; - break; - } - } -} - -- (NotificationQueueList*) next -{ - return next; -} - -- (NSNotificationQueue*) queue -{ - return queue; -} -@end - -static BOOL validMode(NSArray* modes) -{ - BOOL ok = NO; - NSString* mode = [[NSRunLoop currentRunLoop] currentMode]; - - // check to see if run loop is in a valid mode - if (!mode || !modes) - ok = YES; else { - int i; - - for (i = [modes count]; i > 0; i--) - if ([mode isEqual:[modes objectAtIndex:i-1]]) - { - ok = YES; - break; - } + while (list->next != nil) + { + if (list->next->queue == q) + { + NotificationQueueList* tmp = list->next; + + list->next = tmp->next; + RELEASE(tmp); + break; + } + } } - return ok; } +@end + /* * NSNotificationQueue queue */ -typedef struct _NSNotificationQueueRegistration { - struct _NSNotificationQueueRegistration* next; - struct _NSNotificationQueueRegistration* prev; - NSNotification* notification; - id name; - id object; - NSArray* modes; +typedef struct _NSNotificationQueueRegistration +{ + struct _NSNotificationQueueRegistration* next; + struct _NSNotificationQueueRegistration* prev; + NSNotification* notification; + id name; + id object; + NSArray* modes; } NSNotificationQueueRegistration; struct _NSNotificationQueueList; -typedef struct _NSNotificationQueueList { - struct _NSNotificationQueueRegistration* head; - struct _NSNotificationQueueRegistration* tail; +typedef struct _NSNotificationQueueList +{ + struct _NSNotificationQueueRegistration* head; + struct _NSNotificationQueueRegistration* tail; } NSNotificationQueueList; /* @@ -216,30 +194,48 @@ typedef struct _NSNotificationQueueList { * tail ---------------------------------------------> */ +static inline void +remove_from_queue_no_release( + NSNotificationQueueList* queue, + NSNotificationQueueRegistration* item) +{ + if (item->prev) + { + item->prev->next = item->next; + } + else + { + queue->tail = item->next; + if (item->next) + { + item->next->prev = NULL; + } + } + + if (item->next) + { + item->next->prev = item->prev; + } + else + { + queue->head = item->prev; + if (item->prev) + { + item->prev->next = NULL; + } + } +} + static void remove_from_queue( NSNotificationQueueList* queue, NSNotificationQueueRegistration* item, NSZone* zone) { - if (item->prev) - item->prev->next = item->next; - else { - queue->tail = item->next; - if (item->next) - item->next->prev = NULL; - } - - if (item->next) - item->next->prev = item->prev; - else { - queue->head = item->prev; - if (item->prev) - item->prev->next = NULL; - } - [item->notification release]; - [item->modes release]; - NSZoneFree(zone, item); + remove_from_queue_no_release(queue, item); + RELEASE(item->notification); + RELEASE(item->modes); + NSZoneFree(zone, item); } static void @@ -252,10 +248,10 @@ add_to_queue( NSNotificationQueueRegistration* item = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueRegistration)); - item->notification = [notification retain]; + item->notification = RETAIN(notification); item->name = [notification name]; item->object = [notification object]; - item->modes = [modes copyWithZone:[modes zone]]; + item->modes = [modes copyWithZone: [modes zone]]; item->prev = NULL; item->next = queue->tail; @@ -266,6 +262,8 @@ add_to_queue( queue->head = item; } + + /* * NSNotificationQueue class implementation */ @@ -274,36 +272,40 @@ add_to_queue( + (NSNotificationQueue*)defaultQueue { - NotificationQueueList* list; - NSNotificationQueue* item; + NotificationQueueList *list; + NSNotificationQueue *item; - list = [NotificationQueueList currentList]; - item = [list queue]; + list = currentList(); + item = list->queue; if (item == nil) - item = [self new]; - + { + item = (NSNotificationQueue*)NSAllocateObject(self, + 0, NSDefaultMallocZone()); + item = [item initWithNotificationCenter: + [NSNotificationCenter defaultCenter]]; + } return item; } - (id)init { - return [self initWithNotificationCenter: - [NSNotificationCenter defaultCenter]]; + return [self initWithNotificationCenter: + [NSNotificationCenter defaultCenter]]; } -- (id)initWithNotificationCenter:(NSNotificationCenter*)notificationCenter +- (id)initWithNotificationCenter: (NSNotificationCenter*)notificationCenter { - zone = [self zone]; + zone = [self zone]; - // init queue - center = [notificationCenter retain]; - asapQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList)); - idleQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList)); + // init queue + center = RETAIN(notificationCenter); + asapQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList)); + idleQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList)); - // insert in global queue list - [NotificationQueueList registerQueue:self]; + // insert in global queue list + [NotificationQueueList registerQueue: self]; - return self; + return self; } - (void)dealloc @@ -311,7 +313,7 @@ add_to_queue( NSNotificationQueueRegistration* item; // remove from classs instances list - [NotificationQueueList unregisterQueue:self]; + [NotificationQueueList unregisterQueue: self]; // release self for (item = asapQueue->head; item; item=item->prev) @@ -322,14 +324,14 @@ add_to_queue( remove_from_queue(idleQueue, item, zone); NSZoneFree(zone, idleQueue); - [center release]; + RELEASE(center); [super dealloc]; } /* Inserting and Removing Notifications From a Queue */ -- (void)dequeueNotificationsMatching:(NSNotification*)notification - coalesceMask:(NSNotificationCoalescing)coalesceMask +- (void)dequeueNotificationsMatching: (NSNotification*)notification + coalesceMask: (NSNotificationCoalescing)coalesceMask { NSNotificationQueueRegistration* item; NSNotificationQueueRegistration* next; @@ -340,7 +342,7 @@ add_to_queue( for (item = asapQueue->tail; item; item=next) { next = item->next; if ((coalesceMask & NSNotificationCoalescingOnName) - && [name isEqual:item->name]) + && [name isEqual: item->name]) { remove_from_queue(asapQueue, item, zone); continue; @@ -357,7 +359,7 @@ add_to_queue( for (item = idleQueue->tail; item; item=next) { next = item->next; if ((coalesceMask & NSNotificationCoalescingOnName) - && [name isEqual:item->name]) + && [name isEqual: item->name]) { remove_from_queue(asapQueue, item, zone); continue; @@ -371,110 +373,132 @@ add_to_queue( } } -- (void)postNotification:(NSNotification*)notification forModes:(NSArray*)modes +- (void) postNotification: (NSNotification*)notification + forModes: (NSArray*)modes { - if (validMode(modes)) - [center postNotification:notification]; + NSString *mode = [NSRunLoop currentMode]; + + // check to see if run loop is in a valid mode + if (mode == nil || modes == nil + || [modes indexOfObject: mode] != NSNotFound) + { + [center postNotification: notification]; + } } -- (void)enqueueNotification:(NSNotification*)notification - postingStyle:(NSPostingStyle)postingStyle +- (void)enqueueNotification: (NSNotification*)notification + postingStyle: (NSPostingStyle)postingStyle { - [self enqueueNotification:notification - postingStyle:postingStyle - coalesceMask:NSNotificationCoalescingOnName + + [self enqueueNotification: notification + postingStyle: postingStyle + coalesceMask: NSNotificationCoalescingOnName + NSNotificationCoalescingOnSender - forModes:nil]; + forModes: nil]; } -- (void)enqueueNotification:(NSNotification*)notification - postingStyle:(NSPostingStyle)postingStyle - coalesceMask:(NSNotificationCoalescing)coalesceMask - forModes:(NSArray*)modes +- (void)enqueueNotification: (NSNotification*)notification + postingStyle: (NSPostingStyle)postingStyle + coalesceMask: (NSNotificationCoalescing)coalesceMask + forModes: (NSArray*)modes { if (coalesceMask != NSNotificationNoCoalescing) - [self dequeueNotificationsMatching:notification - coalesceMask:coalesceMask]; + [self dequeueNotificationsMatching: notification + coalesceMask: coalesceMask]; switch (postingStyle) { - case NSPostNow: - [self postNotification:notification forModes:modes]; + case NSPostNow: + [self postNotification: notification forModes: modes]; break; - case NSPostASAP: + case NSPostASAP: add_to_queue(asapQueue, notification, modes, zone); break; - case NSPostWhenIdle: + case NSPostWhenIdle: add_to_queue(idleQueue, notification, modes, zone); break; } } +@end + /* - * NotificationQueue internals + * The following code handles sending of queued notifications by + * NSRunLoop. */ -+ (void)runLoopIdle +static inline void notifyASAP(NSNotificationQueue *q) { - NotificationQueueList* item; + NSNotificationQueueList *list = ((accessQueue)q)->asapQueue; - for (item=[NotificationQueueList currentList]; item; item=[item next]) - [[item queue] notifyIdle]; + /* + * post all ASAP notifications in queue + */ + while (list->head) + { + NSNotificationQueueRegistration *item = list->head; + NSNotification *notification = item->notification; + NSArray *modes = item->modes; + + remove_from_queue_no_release(list, item); + [q postNotification: notification forModes: modes]; + RELEASE(notification); + RELEASE(modes); + NSZoneFree(((accessQueue)q)->zone, item); + } } -+ (BOOL)runLoopMore +void +GSNotifyASAP() { - NotificationQueueList* item; + NotificationQueueList *item; - for (item=[NotificationQueueList currentList]; item; item = [item next]) - if ([[item queue] notifyMore] == YES) + for (item = currentList(); item; item = item->next) + if (item->queue) + notifyASAP(item->queue); +} + +static inline void notifyIdle(NSNotificationQueue *q) +{ + NSNotificationQueueList *list = ((accessQueue)q)->idleQueue; + + /* + * post next IDLE notification in queue + */ + if (list->head) + { + NSNotificationQueueRegistration *item = list->head; + NSNotification *notification = item->notification; + NSArray *modes = item->modes; + + remove_from_queue_no_release(list, item); + [q postNotification: notification forModes: modes]; + RELEASE(notification); + RELEASE(modes); + NSZoneFree(((accessQueue)q)->zone, item); + /* + * Post all ASAP notifications. + */ + GSNotifyASAP(); + } +} + +void +GSNotifyIdle() +{ + NotificationQueueList *item; + + for (item = currentList(); item; item = item->next) + if (item->queue) + notifyIdle(item->queue); +} + +BOOL +GSNotifyMore() +{ + NotificationQueueList *item; + + for (item = currentList(); item; item = item->next) + if (item->queue && ((accessQueue)item->queue)->idleQueue->head) return YES; return NO; } -+ (void)runLoopASAP -{ - NotificationQueueList* item; - - for (item=[NotificationQueueList currentList]; item; item=[item next]) - [[item queue] notifyASAP]; -} - -- (BOOL)notifyMore -{ - if (idleQueue->head) - return YES; - return NO; -} - -- (void)notifyIdle -{ - // post next IDLE notification in queue - if (idleQueue->head) { - NSNotification* notification = [idleQueue->head->notification retain]; - NSArray* modes = [idleQueue->head->modes retain]; - - remove_from_queue(idleQueue, idleQueue->head, zone); - [self postNotification:notification forModes:modes]; - [notification release]; - [modes release]; - // Post all ASAP notifications. - [NSNotificationQueue runLoopASAP]; - } -} - -- (void)notifyASAP -{ - // post all ASAP notifications in queue - while (asapQueue->head) { - NSNotification* notification = [asapQueue->head->notification retain]; - NSArray* modes = [asapQueue->head->modes retain]; - - remove_from_queue(asapQueue, asapQueue->head, zone); - [self postNotification:notification forModes:modes]; - [notification release]; - [modes release]; - } -} - -@end - diff --git a/Source/NSRunLoop.m b/Source/NSRunLoop.m index dc9f54595..a6bc4c818 100644 --- a/Source/NSRunLoop.m +++ b/Source/NSRunLoop.m @@ -1,5 +1,5 @@ /* Implementation of object for waiting on several input sources - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996-1999 Free Software Foundation, Inc. Original by: Andrew Kachites McCallum Created: March 1996 @@ -23,36 +23,8 @@ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* October 1996 - extensions to permit file descriptors to be watched - for being readable or writable added by Richard Frith-Macdonald - (richard@brainstorm.co.uk) */ - -/* Andrews original comments - may still be valid even now - - - Does it strike anyone else that NSNotificationCenter, - NSNotificationQueue, NSNotification, NSRunLoop, the "notifications" - a run loop sends the objects on which it is listening, NSEvent, and - the event queue maintained by NSApplication are all much more - intertwined/similar than OpenStep gives them credit for? - - I wonder if these classes could be re-organized a little to make a - more uniform, "grand-unified" mechanism for: events, - event-listening, event-queuing, and event-distributing. It could - be quite pretty. - - (GNUstep would definitely provide classes that were compatible with - all these OpenStep classes, but those classes could be wrappers - around fundamentally cleaner GNU classes. RMS has advised using an - underlying organization/implementation different from NeXT's - whenever that makes sense---it helps legally distinguish our work.) - - Thoughts and insights, anyone? - - */ - #include #include -#include #include #include #include @@ -73,8 +45,8 @@ #include /* for memset() */ static int debug_run_loop = 0; +static NSDate *theFuture = nil; -static SEL isValidSel = @selector(isValid); /* @@ -85,7 +57,11 @@ static SEL isValidSel = @selector(isValid); * extended, and the methods must be modified to handle the new type. * * The internal variables if the RunLoopWatcher are used as follows - - * If 'invalidated' is set, the wather should be disabled and should + * + * The '_date' variable contains a date after which the event is useless + * and the watcher can be removed from the runloop. + * + * If '_invalidated' is set, the watcher should be disabled and should * be removed from the runloop when next encountered. * * The 'data' variable is used to identify the resource/event that the @@ -99,10 +75,6 @@ static SEL isValidSel = @selector(isValid); * NSRunLoops [-acceptInputForMode: beforeDate: ] method MUST contain * code to watch for events of each type. * - * The 'limit' variable contains a date after which the event is useless - * and the watcher can be removed from the runloop. If this is nil - * then the watcher will only be removed if explicitly requested. - * * To set this variable, the method adding the RunLoopWatcher to the * runloop must ask the 'receiver' (or its delegate) to supply a date * using the '[-limitDateForMode: ]' message. @@ -110,75 +82,38 @@ static SEL isValidSel = @selector(isValid); * NB. This class is private to NSRunLoop and must not be subclassed. */ -@interface RunLoopWatcher: NSObject +static SEL eventSel = @selector(receivedEvent:type:extra:forMode:); + +@interface RunLoopWatcher: NSObject { @public - BOOL invalidated; - BOOL handleEvent; // New-style event handling - BOOL (*handleIsValid)(); + NSDate *_date; /* First to match layout of NSTimer */ + BOOL _invalidated; /* 2nd to match layout of NSTimer */ + IMP handleEvent; /* New-style event handling */ void *data; id receiver; RunLoopEventType type; - NSDate *limit; unsigned count; } -- (void) eventFor: (void*)info - mode: (NSString*)mode; - initWithType: (RunLoopEventType)type receiver: (id)anObj data: (void*)data; -- (void) invalidate; -- (BOOL) isValid; @end @implementation RunLoopWatcher - (void) dealloc { - [self gcFinalize]; - RELEASE(limit); + RELEASE(_date); RELEASE(receiver); [super dealloc]; } -- (void) eventFor: (void*)info - mode: (NSString*)mode -{ - if ([self isValid] == NO) - { - return; - } - - if (handleEvent) - { - [receiver receivedEvent: data type: type extra: info forMode: mode]; - } - else - { - switch (type) - { - case ET_RDESC: - case ET_RPORT: - [receiver readyForReadingOnFileDescriptor: (int)(gsaddr)info]; - break; - - case ET_WDESC: - [receiver readyForWritingOnFileDescriptor: (int)(gsaddr)info]; - break; - } - } -} - -- (void) gcFinalize -{ - [self invalidate]; -} - - (id) initWithType: (RunLoopEventType)aType receiver: (id)anObj data: (void*)item { - invalidated = NO; + _invalidated = NO; switch (aType) { @@ -190,38 +125,54 @@ static SEL isValidSel = @selector(isValid); format: @"NSRunLoop - unknown event type"]; } receiver = RETAIN(anObj); - if ([receiver respondsToSelector: - @selector(receivedEvent:type:extra:forMode:)]) - handleEvent = YES; + if ([receiver respondsToSelector: eventSel] == YES) + handleEvent = [receiver methodForSelector: eventSel]; else - handleEvent = NO; + handleEvent = 0; data = item; - if ([receiver respondsToSelector: isValidSel]) - handleIsValid = (BOOL(*)())[receiver methodForSelector: isValidSel]; return self; } -- (void) invalidate -{ - invalidated = YES; -} - -- (BOOL) isValid -{ - if (invalidated == YES) - { - return NO; - } - if (handleIsValid != 0 && (*handleIsValid)(receiver, isValidSel) == NO) - { - [self invalidate]; - return NO; - } - return YES; -} - @end +/* + * Two optimisation functions that depend on a hack that the layout of + * the NSTimer class is known to be the same as RunLoopWatcher for the + * first two elements. + */ +static inline NSDate* timerDate(NSTimer* timer) +{ + return ((RunLoopWatcher*)timer)->_date; +} + +static inline BOOL timerInvalidated(NSTimer* timer) +{ + return ((RunLoopWatcher*)timer)->_invalidated; +} + +static int aSort(RunLoopWatcher *i0, RunLoopWatcher *i1) +{ + return [i0->_date compare: i1->_date]; +} + + + +/* + * Setup for inline operation of arrays. + */ + +#define FAST_ARRAY_TYPES GSUNION_OBJ + +#if GS_WITH_GC == 0 +#define FAST_ARRAY_RELEASE(X) [(X).obj release] +#define FAST_ARRAY_RETAIN(X) [(X).obj retain] +#else +#define FAST_ARRAY_RELEASE(X) +#define FAST_ARRAY_RETAIN(X) (X).obj +#endif + +#include + @interface NSRunLoop (TimedPerformers) @@ -450,22 +401,17 @@ static SEL isValidSel = @selector(isValid); limit-date order. */ - (void) _addWatcher: (RunLoopWatcher*) item forMode: (NSString*)mode { - NSMutableArray *watchers; - id obj; - NSDate *limit; - int count; + FastArray watchers; + id obj; watchers = NSMapGet(_mode_2_watchers, mode); - if (watchers == nil) + if (watchers == 0) { - watchers = [NSMutableArray new]; + NSZone *z = [self zone]; + + watchers = NSZoneMalloc(z, sizeof(FastArray_t)); + FastArrayInitWithZoneAndCapacity(watchers, z, 8); NSMapInsert(_mode_2_watchers, mode, watchers); - RELEASE(watchers); - count = 0; - } - else - { - count = [watchers count]; } /* @@ -478,7 +424,7 @@ static SEL isValidSel = @selector(isValid); { NSDate *d = [obj limitDateForMode: mode]; - ASSIGN(item->limit, d); + ASSIGN(item->_date, d); } else if ([obj respondsToSelector: @selector(delegate)]) { @@ -487,38 +433,14 @@ static SEL isValidSel = @selector(isValid); { NSDate *d = [obj limitDateForMode: mode]; - ASSIGN(item->limit, d); + ASSIGN(item->_date, d); } - } - limit = item->limit; - - /* - * Make sure that the items in the watchers list are ordered. - */ - if (limit == nil || count == 0) - { - [watchers addObject: item]; + else + ASSIGN(item->_date, theFuture); } else - { - int i; - - for (i = 0; i < count; i++) - { - RunLoopWatcher *watcher = [watchers objectAtIndex: i]; - NSDate *when = watcher->limit; - - if (when == nil || [limit earlierDate: when] == when) - { - [watchers insertObject: item atIndex: i]; - break; - } - } - if (i == count) - { - [watchers addObject: item]; - } - } + ASSIGN(item->_date, theFuture); + FastArrayInsertSorted(watchers, (FastArrayItem)item, aSort); } - (void) _checkPerformers @@ -720,8 +642,6 @@ static SEL isValidSel = @selector(isValid); @implementation NSRunLoop -static NSDate *theFuture; - #if GS_WITH_GC == 0 static SEL wRelSel = @selector(release); static SEL wRetSel = @selector(retain); @@ -750,6 +670,27 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = #define WatcherMapValueCallBacks NSOwnedPointerMapValueCallBacks #endif +static void* +aRetain(void* t, FastArray a) +{ + return t; +} + +static void +aRelease(void* t, FastArray a) +{ + FastArrayEmpty(a); + NSZoneFree(a->zone, (void*)a); +} + +const NSMapTableValueCallBacks ArrayMapValueCallBacks = +{ + (NSMT_retain_func_t) aRetain, + (NSMT_release_func_t) aRelease, + (NSMT_describe_func_t) 0 +}; + + + (void) initialize { if (self == [NSRunLoop class]) @@ -786,9 +727,9 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = [super init]; _current_mode = NSDefaultRunLoopMode; _mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks, - NSObjectMapValueCallBacks, 0); + ArrayMapValueCallBacks, 0); _mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks, - NSObjectMapValueCallBacks, 0); + ArrayMapValueCallBacks, 0); _performers = [[NSMutableArray alloc] initWithCapacity: 8]; _timedPerformers = [[NSMutableArray alloc] initWithCapacity: 8]; _rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks, @@ -825,17 +766,18 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = - (void) addTimer: timer forMode: (NSString*)mode { - Heap *timers; + FastArray timers; timers = NSMapGet(_mode_2_timers, mode); if (!timers) { - timers = [Heap new]; + NSZone *z = [self zone]; + + timers = NSZoneMalloc(z, sizeof(FastArray_t)); + FastArrayInitWithZoneAndCapacity(timers, z, 8); NSMapInsert(_mode_2_timers, mode, timers); - RELEASE(timers); } - /* xxx Should we make sure it isn't already there? */ - [timers addObject: timer]; + FastArrayInsertSorted(timers, (FastArrayItem)timer, aSort); } @@ -845,10 +787,10 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = - limitDateForMode: (NSString*)mode { id saved_mode; - Heap *timers; + FastArray timers; NSTimer *min_timer = nil; RunLoopWatcher *min_watcher = nil; - NSMutableArray *watchers; + FastArray watchers; NSDate *when; saved_mode = _current_mode; @@ -857,31 +799,39 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = timers = NSMapGet(_mode_2_timers, mode); if (timers) { - while ((min_timer = [timers minObject]) != nil) + while (FastArrayCount(timers) != 0) { - if (![min_timer isValid]) + min_timer = FastArrayItemAtIndex(timers, 0).obj; + if (timerInvalidated(min_timer) == YES) { - [timers removeFirstObject]; + FastArrayRemoveItemAtIndex(timers, 0); min_timer = nil; continue; } - if ([[min_timer fireDate] timeIntervalSinceNow] > 0) + if ([timerDate(min_timer) timeIntervalSinceNow] > 0) { break; } - RETAIN(min_timer); - [timers removeFirstObject]; + FastArrayRemoveItemAtIndexNoRelease(timers, 0); /* Firing will also increment its fireDate, if it is repeating. */ [min_timer fire]; - if ([min_timer isValid]) + if (timerInvalidated(min_timer) == NO) { - [timers addObject: min_timer]; + unsigned index; + + index = FastArrayInsertionPosition(timers, + (FastArrayItem)min_timer, aSort); + FastArrayInsertItemNoRetain(timers, + (FastArrayItem)min_timer, index); + } + else + { + RELEASE(min_timer); } - RELEASE(min_timer); min_timer = nil; - [NSNotificationQueue runLoopASAP]; /* Post notifications. */ + GSNotifyASAP(); /* Post notifications. */ } } @@ -890,19 +840,19 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = watchers = NSMapGet(_mode_2_watchers, mode); if (watchers) { - while ([watchers count] > 0) + while (FastArrayCount(watchers) != 0) { - min_watcher = (RunLoopWatcher*)[watchers objectAtIndex: 0]; + min_watcher = FastArrayItemAtIndex(watchers, 0).obj; - if (![min_watcher isValid]) + if (min_watcher->_invalidated == YES) { - [watchers removeObjectAtIndex: 0]; + FastArrayRemoveItemAtIndex(watchers, 0); min_watcher = nil; continue; } - when = min_watcher->limit; - if (when == nil || [when timeIntervalSinceNow] > 0) + when = min_watcher->_date; + if ([when timeIntervalSinceNow] > 0) { break; } @@ -937,15 +887,18 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = } if (nxt && [nxt timeIntervalSinceNow] > 0.0) { + unsigned index; + /* * If the watcher has been given a revised limit date - * re-insert it into the queue in the correct place. */ - RETAIN(min_watcher); - ASSIGN(min_watcher->limit, nxt); - [watchers removeObjectAtIndex: 0]; - [self _addWatcher: min_watcher forMode: mode]; - RELEASE(min_watcher); + FastArrayRemoveItemAtIndexNoRelease(watchers, 0); + ASSIGN(min_watcher->_date, nxt); + index = FastArrayInsertionPosition(watchers, + (FastArrayItem)min_watcher, aSort); + FastArrayInsertItemNoRetain(watchers, + (FastArrayItem)min_watcher, index); } else { @@ -954,8 +907,8 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = * remove it from the queue so that we don't need to * check it again. */ - [min_watcher invalidate]; - [watchers removeObjectAtIndex: 0]; + min_watcher->_invalidated = YES; + FastArrayRemoveItemAtIndex(watchers, 0); } min_watcher = nil; } @@ -978,29 +931,16 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = * If there are watchers, set the limit date to that of the earliest * watcher (or leave it as the date of the earliest timer if that is * before the watchers limit). - * NB. A watcher without a limit date watches forever - so it's limit - * is effectively some time in the distant future. */ if (min_watcher) { - NSDate* lim; - - if (min_watcher->limit == nil) /* No limit for watcher */ - { - lim = theFuture; /* - watches forever. */ - } - else - { - lim = min_watcher->limit; - } - if (when == nil) { - when = lim; + when = min_watcher->_date; } else { - when = [when earlierDate: lim]; + when = [when earlierDate: min_watcher->_date]; } } @@ -1022,9 +962,7 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = type: (RunLoopEventType)type forMode: (NSString*)mode { - NSArray *watchers; - RunLoopWatcher *info; - int count; + FastArray watchers; if (mode == nil) { @@ -1032,17 +970,16 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = } watchers = NSMapGet(_mode_2_watchers, mode); - if (watchers == nil) + if (watchers) { - return nil; - } - for (count = 0; count < [watchers count]; count++) - { - info = [watchers objectAtIndex: count]; + unsigned i = FastArrayCount(watchers); - if (info->type == type) + while (i-- > 0) { - if (info->data == data) + RunLoopWatcher *info; + + info = FastArrayItemAtIndex(watchers, i).obj; + if (info->type == type && info->data == data) { return info; } @@ -1055,7 +992,7 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = type: (RunLoopEventType)type forMode: (NSString*)mode { - NSMutableArray *watchers; + FastArray watchers; if (mode == nil) { @@ -1065,17 +1002,17 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = watchers = NSMapGet(_mode_2_watchers, mode); if (watchers) { - int i; + unsigned i = FastArrayCount(watchers); - for (i = [watchers count]; i > 0; i--) + while (i-- > 0) { - RunLoopWatcher* info; + RunLoopWatcher *info; - info = (RunLoopWatcher*)[watchers objectAtIndex: (i-1)]; + info = FastArrayItemAtIndex(watchers, i).obj; if (info->type == type && info->data == data) { - [info invalidate]; - [watchers removeObject: info]; + info->_invalidated = YES; + FastArrayRemoveItemAtIndex(watchers, i); } } } @@ -1164,18 +1101,19 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = /* Do the pre-listening set-up for the file descriptors of this mode. */ { - NSMutableArray *watchers; + FastArray watchers; watchers = NSMapGet(_mode_2_watchers, mode); if (watchers) { int i; - for (i = [watchers count]; i > 0; i--) { - RunLoopWatcher* info = [watchers objectAtIndex: (i-1)]; - int fd; + for (i = FastArrayCount(watchers); i > 0; i--) { + RunLoopWatcher *info; + int fd; - if ([info isValid] == NO) { - [watchers removeObjectAtIndex: (i-1)]; + info = FastArrayItemAtIndex(watchers, i-1).obj; + if (info->_invalidated == YES) { + FastArrayRemoveItemAtIndex(watchers, i-1); continue; } switch (info->type) { @@ -1226,7 +1164,7 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = /* Detect if the NSRunLoop is idle, and if necessary - dispatch the notifications from NSNotificationQueue's idle queue? */ - if (num_inputs == 0 && [NSNotificationQueue runLoopMore]) + if (num_inputs == 0 && GSNotifyMore()) { timeout.tv_sec = 0; timeout.tv_usec = 0; @@ -1260,7 +1198,7 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = { NSResetMapTable(_rfdMap); NSResetMapTable(_wfdMap); - [NSNotificationQueue runLoopIdle]; + GSNotifyIdle(); [self _checkPerformers]; _current_mode = saved_mode; return; @@ -1280,25 +1218,64 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks = RunLoopWatcher *watcher; watcher = NSMapGet(_wfdMap, (void*)fd_index); - [watcher eventFor: (void*)(gsaddr)fd_index mode: _current_mode]; - [NSNotificationQueue runLoopASAP]; + if (watcher->_invalidated == NO) + { + /* + * The watcher is still valid - so call it's receivers + * event handling method. + */ + if (watcher->handleEvent != 0) + { + (*watcher->handleEvent)(watcher->receiver, + eventSel, watcher->data, watcher->type, + (void*)(gsaddr)fd_index, _current_mode); + } + else if (watcher->type == ET_WDESC) + { + [watcher->receiver readyForWritingOnFileDescriptor: + (int)(gsaddr)fd_index]; + } + } + GSNotifyASAP(); + if (--select_return == 0) + break; } if (FD_ISSET (fd_index, &read_fds)) { RunLoopWatcher *watcher; watcher = (RunLoopWatcher*)NSMapGet(_rfdMap, (void*)fd_index); - [watcher eventFor: (void*)(gsaddr)fd_index mode: _current_mode]; - [NSNotificationQueue runLoopASAP]; + if (watcher->_invalidated == NO) + { + /* + * The watcher is still valid - so call it's receivers + * event handling method. + */ + if (watcher->handleEvent != 0) + { + (*watcher->handleEvent)(watcher->receiver, + eventSel, watcher->data, watcher->type, + (void*)(gsaddr)fd_index, _current_mode); + } + else if (watcher->type == ET_RDESC || watcher->type == ET_RPORT) + { + [watcher->receiver readyForReadingOnFileDescriptor: + (int)(gsaddr)fd_index]; + } + } + GSNotifyASAP(); + if (--select_return == 0) + break; } } + /* Clean up before returning. */ NSResetMapTable(_rfdMap); NSResetMapTable(_wfdMap); [self _checkPerformers]; - [NSNotificationQueue runLoopASAP]; + GSNotifyASAP(); _current_mode = saved_mode; } diff --git a/Source/NSTimer.m b/Source/NSTimer.m index 454cbc108..5acff5206 100644 --- a/Source/NSTimer.m +++ b/Source/NSTimer.m @@ -37,11 +37,8 @@ userInfo: info repeats: (BOOL)f { - [super init]; _interval = seconds; - _fire_date = [[NSDate alloc] initWithTimeIntervalSinceNow: seconds]; - _retain_count = 0; - _is_valid = YES; + _date = [[NSDate alloc] initWithTimeIntervalSinceNow: seconds]; _target = t; _selector = sel; _info = info; @@ -51,7 +48,7 @@ - (void) dealloc { - [_fire_date release]; + RELEASE(_date); [super dealloc]; } @@ -59,12 +56,11 @@ invocation: invocation repeats: (BOOL)f { - return [[[self alloc] initWithTimeInterval: ti + return AUTORELEASE([[self alloc] initWithTimeInterval: ti targetOrInvocation: invocation selector: NULL userInfo: nil - repeats: f] - autorelease]; + repeats: f]); } + timerWithTimeInterval: (NSTimeInterval)ti @@ -73,12 +69,11 @@ userInfo: info repeats: (BOOL)f { - return [[[self alloc] initWithTimeInterval: ti + return AUTORELEASE([[self alloc] initWithTimeInterval: ti targetOrInvocation: object selector: selector userInfo: info - repeats: f] - autorelease]; + repeats: f]); } + scheduledTimerWithTimeInterval: (NSTimeInterval)ti @@ -117,32 +112,44 @@ if (!_repeats) [self invalidate]; - else if (_is_valid) + else if (!_invalidated) { - NSTimeInterval ti = [_fire_date timeIntervalSinceReferenceDate]; - NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; + NSTimeInterval ti = [_date timeIntervalSinceReferenceDate]; + NSTimeInterval now = GSTimeNow(); + int inc = -1; + NSAssert(now < 0.0, NSInternalInconsistencyException); - while (ti < now) // xxx remove this - ti += _interval; - [_fire_date release]; - _fire_date = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate: ti]; + while (ti <= now) // xxx remove this + { + inc++; + ti += _interval; + } +#ifdef LOG_MISSED + if (inc > 0) + NSLog(@"Missed %d timeouts at %f second intervals", inc, _interval); +#endif + /* + * Rely on feature of NSDate implementation that it's possible to + * re-initialize a date! + */ + _date = [_date initWithTimeIntervalSinceReferenceDate: ti]; } } - (void) invalidate { - NSAssert(_is_valid, NSInternalInconsistencyException); - _is_valid = NO; + NSAssert(_invalidated == NO, NSInternalInconsistencyException); + _invalidated = YES; } - (BOOL) isValid { - return _is_valid; + return !_invalidated; } - fireDate { - return _fire_date; + return _date; } - userInfo @@ -152,6 +159,6 @@ - (int)compare:(NSTimer*)anotherTimer { - return [_fire_date compare: anotherTimer->_fire_date]; + return [_date compare: anotherTimer->_date]; } @end diff --git a/Source/NSUnarchiver.m b/Source/NSUnarchiver.m index 6bde7786f..dcfef659b 100644 --- a/Source/NSUnarchiver.m +++ b/Source/NSUnarchiver.m @@ -32,7 +32,7 @@ */ #define FAST_ARRAY_RETAIN(X) X #define FAST_ARRAY_RELEASE(X) -#define FAST_ARRAY__TYPES GSUNION_OBJ +#define FAST_ARRAY_TYPES GSUNION_OBJ|GSUNION_SEL|GSUNION_STR #include