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