Optimisation changes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@4103 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1999-04-20 16:28:04 +00:00
parent 7fd494e6ec
commit 76c9b88542
12 changed files with 654 additions and 527 deletions

View file

@ -58,7 +58,7 @@
* Defined if no release operation is needed for an item * Defined if no release operation is needed for an item
* FAST_ARRAY_NO_RETAIN * FAST_ARRAY_NO_RETAIN
* Defined if no retain operation is needed for a an item * Defined if no retain operation is needed for a an item
*/
#ifndef FAST_ARRAY_RETAIN #ifndef FAST_ARRAY_RETAIN
#define FAST_ARRAY_RETAIN(X) [(X).obj retain] #define FAST_ARRAY_RETAIN(X) [(X).obj retain]
#endif #endif
@ -103,7 +103,6 @@
*/ */
#include <base/GSUnion.h> #include <base/GSUnion.h>
struct _FastArray { struct _FastArray {
FastArrayItem *ptr; FastArrayItem *ptr;
unsigned count; unsigned count;
@ -114,14 +113,9 @@ struct _FastArray {
typedef struct _FastArray FastArray_t; typedef struct _FastArray FastArray_t;
typedef struct _FastArray *FastArray; typedef struct _FastArray *FastArray;
static INLINE void static INLINE void
FastArrayAddItem(FastArray array, FastArrayItem item) FastArrayGrow(FastArray array)
{ {
FAST_ARRAY_RETAIN(item);
FAST_ARRAY_CHECK;
if (array->count == array->cap)
{
unsigned next; unsigned next;
unsigned size; unsigned size;
FastArrayItem *tmp; FastArrayItem *tmp;
@ -142,11 +136,124 @@ FastArrayAddItem(FastArray array, FastArrayItem item)
array->ptr = tmp; array->ptr = tmp;
array->old = array->cap; array->old = array->cap;
array->cap = next; 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)
{
FAST_ARRAY_RETAIN(item);
FAST_ARRAY_CHECK;
if (array->count == array->cap)
{
FastArrayGrow(array);
} }
array->ptr[array->count++] = item; array->ptr[array->count++] = item;
FAST_ARRAY_CHECK; 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 static INLINE void
FastArrayRemoveItemAtIndex(FastArray array, unsigned index) FastArrayRemoveItemAtIndex(FastArray array, unsigned index)
{ {
@ -159,6 +266,17 @@ FastArrayRemoveItemAtIndex(FastArray array, unsigned index)
FAST_ARRAY_RELEASE(tmp); 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 static INLINE void
FastArraySetItemAtIndex(FastArray array, FastArrayItem item, unsigned index) FastArraySetItemAtIndex(FastArray array, FastArrayItem item, unsigned index)
{ {

View file

@ -105,6 +105,8 @@ typedef double NSTimeInterval;
NSTimeInterval seconds_since_ref; NSTimeInterval seconds_since_ref;
} }
@end @end
NSTimeInterval GSTimeNow(); /* Get time since reference date */
#endif #endif

View file

@ -74,40 +74,39 @@ struct _NSNotificationQueueList;
@interface NSNotificationQueue : NSObject @interface NSNotificationQueue : NSObject
{ {
NSNotificationCenter* center; NSNotificationCenter *center;
struct _NSNotificationQueueList* asapQueue; struct _NSNotificationQueueList *asapQueue;
struct _NSNotificationQueueList* idleQueue; struct _NSNotificationQueueList *idleQueue;
NSZone* zone; NSZone *zone;
} }
/* Creating Notification Queues */ /* Creating Notification Queues */
+ (NSNotificationQueue*)defaultQueue; + (NSNotificationQueue*) defaultQueue;
- (id)init; - (id) initWithNotificationCenter: (NSNotificationCenter*)notificationCenter;
- (id)initWithNotificationCenter:(NSNotificationCenter*)notificationCenter;
/* Inserting and Removing Notifications From a Queue */ /* Inserting and Removing Notifications From a Queue */
- (void)dequeueNotificationsMatching:(NSNotification*)notification - (void) dequeueNotificationsMatching:(NSNotification*)notification
coalesceMask:(unsigned int)coalesceMask; coalesceMask:(unsigned int)coalesceMask;
- (void)enqueueNotification:(NSNotification*)notification - (void) enqueueNotification:(NSNotification*)notification
postingStyle:(NSPostingStyle)postingStyle; postingStyle:(NSPostingStyle)postingStyle;
- (void)enqueueNotification:(NSNotification*)notification - (void) enqueueNotification:(NSNotification*)notification
postingStyle:(NSPostingStyle)postingStyle postingStyle:(NSPostingStyle)postingStyle
coalesceMask:(unsigned int)coalesceMask coalesceMask:(unsigned int)coalesceMask
forModes:(NSArray*)modes; forModes:(NSArray*)modes;
/* Implementation used by the the NSRunLoop */
+ (void)runLoopIdle;
+ (void)runLoopASAP;
+ (BOOL)runLoopMore;
- (void)notifyIdle;
- (void)notifyASAP;
- (BOOL)notifyMore;
@end @end
#ifndef NO_GNUSTEP
/*
* Functions used by the the NSRunLoop
*/
extern void GSNotifyASAP();
extern void GSNotifyIdle();
extern BOOL GSNotifyMore();
#endif
#endif /* __NSNotificationQueue_h__ */ #endif /* __NSNotificationQueue_h__ */

View file

@ -30,13 +30,16 @@
#include <base/preface.h> #include <base/preface.h>
#include <Foundation/NSDate.h> #include <Foundation/NSDate.h>
/*
* 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 @interface NSTimer : NSObject
{ {
unsigned _repeats:1; NSDate *_date; /* Must be first - for NSRunLoop optimisation */
unsigned _is_valid:1; BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */
unsigned _timer_filler:6; BOOL _repeats;
unsigned _retain_count:24;
NSDate *_fire_date;
NSTimeInterval _interval; NSTimeInterval _interval;
id _target; id _target;
SEL _selector; SEL _selector;

View file

@ -214,6 +214,7 @@ $(GNUSTEP_OBJ_DIR)/NSUnarchiver.o \
# #
# Files that include FastArray.x will need a rebuild if it is changed. # 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)/NSSerializer.o \
$(GNUSTEP_OBJ_DIR)/NSUnarchiver.o \ $(GNUSTEP_OBJ_DIR)/NSUnarchiver.o \
: include/FastArray.x include/GSUnion.h : include/FastArray.x include/GSUnion.h

View file

@ -293,23 +293,23 @@ static int messages_received_count;
*/ */
+ (NSConnection*) defaultConnection + (NSConnection*) defaultConnection
{ {
static NSString* tkey = @"NSConnectionThreadKey"; static NSString *tkey = @"NSConnectionThreadKey";
NSConnection* c; NSConnection *c;
NSThread* t; NSMutableDictionary *d;
t = GSCurrentThread(); d = GSCurrentThreadDictionary();
c = (NSConnection*)[[t threadDictionary] objectForKey:tkey]; c = (NSConnection*)[d objectForKey:tkey];
if (c != nil && [c isValid] == NO) { if (c != nil && [c isValid] == NO) {
/* /*
* If the default connection for this thread has been invalidated - * If the default connection for this thread has been invalidated -
* release it and create a new one. * release it and create a new one.
*/ */
[[t threadDictionary] removeObjectForKey:tkey]; [d removeObjectForKey:tkey];
c = nil; c = nil;
} }
if (c == nil) { if (c == nil) {
c = [NSConnection new]; c = [NSConnection new];
[[t threadDictionary] setObject:c forKey:tkey]; [d setObject:c forKey:tkey];
[c release]; /* retained in dictionary. */ [c release]; /* retained in dictionary. */
} }
return c; return c;

View file

@ -91,8 +91,8 @@ otherTime(NSDate* other)
return [other timeIntervalSinceReferenceDate]; return [other timeIntervalSinceReferenceDate];
} }
static NSTimeInterval NSTimeInterval
timeNow() GSTimeNow()
{ {
#if !defined(__WIN32__) && !defined(_WIN32) #if !defined(__WIN32__) && !defined(_WIN32)
volatile NSTimeInterval interval; volatile NSTimeInterval interval;
@ -163,7 +163,7 @@ timeNow()
+ (NSTimeInterval) timeIntervalSinceReferenceDate + (NSTimeInterval) timeIntervalSinceReferenceDate
{ {
return timeNow(); return GSTimeNow();
} }
// Allocation and initializing // Allocation and initializing
@ -171,7 +171,7 @@ timeNow()
+ (id) date + (id) date
{ {
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
initWithTimeIntervalSinceReferenceDate: timeNow()]); initWithTimeIntervalSinceReferenceDate: GSTimeNow()]);
} }
+ (id) dateWithNaturalLanguageString: (NSString*)string + (id) dateWithNaturalLanguageString: (NSString*)string
@ -892,7 +892,7 @@ timeNow()
- (id) init - (id) init
{ {
return [self initWithTimeIntervalSinceReferenceDate: timeNow()]; return [self initWithTimeIntervalSinceReferenceDate: GSTimeNow()];
} }
- (id) initWithString: (NSString*)description - (id) initWithString: (NSString*)description
@ -919,7 +919,7 @@ timeNow()
{ {
// Get the current time, add the secs and init thyself // Get the current time, add the secs and init thyself
return [self initWithTimeIntervalSinceReferenceDate: return [self initWithTimeIntervalSinceReferenceDate:
timeNow() + secsToBeAdded]; GSTimeNow() + secsToBeAdded];
} }
- (id)initWithTimeIntervalSince1970: (NSTimeInterval)seconds - (id)initWithTimeIntervalSince1970: (NSTimeInterval)seconds
@ -1013,7 +1013,7 @@ timeNow()
- (NSTimeInterval) timeIntervalSinceNow - (NSTimeInterval) timeIntervalSinceNow
{ {
return otherTime(self) - timeNow(); return otherTime(self) - GSTimeNow();
} }
- (NSTimeInterval) timeIntervalSinceReferenceDate - (NSTimeInterval) timeIntervalSinceReferenceDate
@ -1126,7 +1126,7 @@ timeNow()
- (NSTimeInterval) timeIntervalSinceNow - (NSTimeInterval) timeIntervalSinceNow
{ {
return seconds_since_ref - timeNow(); return seconds_since_ref - GSTimeNow();
} }
- (NSTimeInterval) timeIntervalSinceReferenceDate - (NSTimeInterval) timeIntervalSinceReferenceDate

View file

@ -37,11 +37,7 @@
* instances of the string classes we know about! * instances of the string classes we know about!
*/ */
typedef struct { typedef struct {
Class *isa; @defs(NSGCString)
char *_contents_chars;
int _count;
NSZone *_zone;
unsigned _hash;
} *dictAccessToStringHack; } *dictAccessToStringHack;
static inline unsigned static inline unsigned

View file

@ -63,36 +63,41 @@
static NSString* tkey = @"NotificationQueueListThreadKey"; static NSString* tkey = @"NotificationQueueListThreadKey";
typedef struct {
@defs(NSNotificationQueue)
} *accessQueue;
@interface NotificationQueueList : NSObject @interface NotificationQueueList : NSObject
{ {
NotificationQueueList* next; @public
NSNotificationQueue* queue; NotificationQueueList *next;
NSNotificationQueue *queue;
} }
+ (NotificationQueueList*) currentList; + (void) registerQueue: (NSNotificationQueue*)q;
+ (void)registerQueue:(NSNotificationQueue*)q; + (void) unregisterQueue: (NSNotificationQueue*)q;
+ (void)unregisterQueue:(NSNotificationQueue*)q;
- (NotificationQueueList*) next;
- (NSNotificationQueue*) queue;
@end @end
@implementation NotificationQueueList static NotificationQueueList*
+ (NotificationQueueList*) currentList currentList()
{ {
NotificationQueueList* list; NotificationQueueList *list;
NSThread* t; NSMutableDictionary *d;
t = GSCurrentThread(); d = GSCurrentThreadDictionary();
list = (NotificationQueueList*)[[t threadDictionary] objectForKey:tkey]; list = (NotificationQueueList*)[d objectForKey: tkey];
if (list == nil) if (list == nil)
{ {
list = [NotificationQueueList new]; list = [NotificationQueueList new];
[[t threadDictionary] setObject:list forKey:tkey]; [d setObject: list forKey: tkey];
[list release]; /* retained in dictionary. */ RELEASE(list); /* retained in dictionary. */
} }
return list; return list;
} }
+ (void)registerQueue:(NSNotificationQueue*)q @implementation NotificationQueueList
+ (void)registerQueue: (NSNotificationQueue*)q
{ {
NotificationQueueList* list; NotificationQueueList* list;
NotificationQueueList* elem; NotificationQueueList* elem;
@ -100,7 +105,7 @@ static NSString* tkey = @"NotificationQueueListThreadKey";
if (q == nil) if (q == nil)
return; /* Can't register nil object. */ 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) if (list->queue == nil)
list->queue = q; /* Make this the default. */ list->queue = q; /* Make this the default. */
@ -111,36 +116,37 @@ static NSString* tkey = @"NotificationQueueListThreadKey";
if (list->queue == q) if (list->queue == q)
return; /* Queue already registered. */ return; /* Queue already registered. */
elem = [NotificationQueueList new]; elem = NSAllocateObject(self, 0, NSDefaultMallocZone());
elem->queue = q; elem->queue = q;
list->next = elem; list->next = elem;
} }
+ (void)unregisterQueue:(NSNotificationQueue*)q + (void)unregisterQueue: (NSNotificationQueue*)q
{ {
NotificationQueueList* list; NotificationQueueList* list;
if (q == nil) if (q == nil)
return; return;
list = [self currentList]; list = currentList();
if (list->queue == q) if (list->queue == q)
{ {
NSThread* t; NSMutableDictionary *d;
t = GSCurrentThread(); d = GSCurrentThreadDictionary();
if (list->next) if (list->next)
{ {
NotificationQueueList* tmp = list->next; NotificationQueueList* tmp = list->next;
[[t threadDictionary] setObject:tmp forKey:tkey]; [d setObject: tmp forKey: tkey];
[tmp release]; /* retained in dictionary. */ RELEASE(tmp); /* retained in dictionary. */
} }
else else
[[t threadDictionary] removeObjectForKey:tkey]; [d removeObjectForKey: tkey];
} }
else else
{
while (list->next != nil) while (list->next != nil)
{ {
if (list->next->queue == q) if (list->next->queue == q)
@ -148,50 +154,21 @@ static NSString* tkey = @"NotificationQueueListThreadKey";
NotificationQueueList* tmp = list->next; NotificationQueueList* tmp = list->next;
list->next = tmp->next; list->next = tmp->next;
[tmp release]; RELEASE(tmp);
break; break;
} }
} }
}
} }
- (NotificationQueueList*) next
{
return next;
}
- (NSNotificationQueue*) queue
{
return queue;
}
@end @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;
}
}
return ok;
}
/* /*
* NSNotificationQueue queue * NSNotificationQueue queue
*/ */
typedef struct _NSNotificationQueueRegistration { typedef struct _NSNotificationQueueRegistration
{
struct _NSNotificationQueueRegistration* next; struct _NSNotificationQueueRegistration* next;
struct _NSNotificationQueueRegistration* prev; struct _NSNotificationQueueRegistration* prev;
NSNotification* notification; NSNotification* notification;
@ -202,7 +179,8 @@ typedef struct _NSNotificationQueueRegistration {
struct _NSNotificationQueueList; struct _NSNotificationQueueList;
typedef struct _NSNotificationQueueList { typedef struct _NSNotificationQueueList
{
struct _NSNotificationQueueRegistration* head; struct _NSNotificationQueueRegistration* head;
struct _NSNotificationQueueRegistration* tail; struct _NSNotificationQueueRegistration* tail;
} NSNotificationQueueList; } NSNotificationQueueList;
@ -216,29 +194,47 @@ typedef struct _NSNotificationQueueList {
* tail ---------------------------------------------> * 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 static void
remove_from_queue( remove_from_queue(
NSNotificationQueueList* queue, NSNotificationQueueList* queue,
NSNotificationQueueRegistration* item, NSNotificationQueueRegistration* item,
NSZone* zone) NSZone* zone)
{ {
if (item->prev) remove_from_queue_no_release(queue, item);
item->prev->next = item->next; RELEASE(item->notification);
else { RELEASE(item->modes);
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); NSZoneFree(zone, item);
} }
@ -252,10 +248,10 @@ add_to_queue(
NSNotificationQueueRegistration* item = NSNotificationQueueRegistration* item =
NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueRegistration)); NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueRegistration));
item->notification = [notification retain]; item->notification = RETAIN(notification);
item->name = [notification name]; item->name = [notification name];
item->object = [notification object]; item->object = [notification object];
item->modes = [modes copyWithZone:[modes zone]]; item->modes = [modes copyWithZone: [modes zone]];
item->prev = NULL; item->prev = NULL;
item->next = queue->tail; item->next = queue->tail;
@ -266,6 +262,8 @@ add_to_queue(
queue->head = item; queue->head = item;
} }
/* /*
* NSNotificationQueue class implementation * NSNotificationQueue class implementation
*/ */
@ -274,14 +272,18 @@ add_to_queue(
+ (NSNotificationQueue*)defaultQueue + (NSNotificationQueue*)defaultQueue
{ {
NotificationQueueList* list; NotificationQueueList *list;
NSNotificationQueue* item; NSNotificationQueue *item;
list = [NotificationQueueList currentList]; list = currentList();
item = [list queue]; item = list->queue;
if (item == nil) if (item == nil)
item = [self new]; {
item = (NSNotificationQueue*)NSAllocateObject(self,
0, NSDefaultMallocZone());
item = [item initWithNotificationCenter:
[NSNotificationCenter defaultCenter]];
}
return item; return item;
} }
@ -291,17 +293,17 @@ add_to_queue(
[NSNotificationCenter defaultCenter]]; [NSNotificationCenter defaultCenter]];
} }
- (id)initWithNotificationCenter:(NSNotificationCenter*)notificationCenter - (id)initWithNotificationCenter: (NSNotificationCenter*)notificationCenter
{ {
zone = [self zone]; zone = [self zone];
// init queue // init queue
center = [notificationCenter retain]; center = RETAIN(notificationCenter);
asapQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList)); asapQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList));
idleQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList)); idleQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList));
// insert in global queue list // insert in global queue list
[NotificationQueueList registerQueue:self]; [NotificationQueueList registerQueue: self];
return self; return self;
} }
@ -311,7 +313,7 @@ add_to_queue(
NSNotificationQueueRegistration* item; NSNotificationQueueRegistration* item;
// remove from classs instances list // remove from classs instances list
[NotificationQueueList unregisterQueue:self]; [NotificationQueueList unregisterQueue: self];
// release self // release self
for (item = asapQueue->head; item; item=item->prev) for (item = asapQueue->head; item; item=item->prev)
@ -322,14 +324,14 @@ add_to_queue(
remove_from_queue(idleQueue, item, zone); remove_from_queue(idleQueue, item, zone);
NSZoneFree(zone, idleQueue); NSZoneFree(zone, idleQueue);
[center release]; RELEASE(center);
[super dealloc]; [super dealloc];
} }
/* Inserting and Removing Notifications From a Queue */ /* Inserting and Removing Notifications From a Queue */
- (void)dequeueNotificationsMatching:(NSNotification*)notification - (void)dequeueNotificationsMatching: (NSNotification*)notification
coalesceMask:(NSNotificationCoalescing)coalesceMask coalesceMask: (NSNotificationCoalescing)coalesceMask
{ {
NSNotificationQueueRegistration* item; NSNotificationQueueRegistration* item;
NSNotificationQueueRegistration* next; NSNotificationQueueRegistration* next;
@ -340,7 +342,7 @@ add_to_queue(
for (item = asapQueue->tail; item; item=next) { for (item = asapQueue->tail; item; item=next) {
next = item->next; next = item->next;
if ((coalesceMask & NSNotificationCoalescingOnName) if ((coalesceMask & NSNotificationCoalescingOnName)
&& [name isEqual:item->name]) && [name isEqual: item->name])
{ {
remove_from_queue(asapQueue, item, zone); remove_from_queue(asapQueue, item, zone);
continue; continue;
@ -357,7 +359,7 @@ add_to_queue(
for (item = idleQueue->tail; item; item=next) { for (item = idleQueue->tail; item; item=next) {
next = item->next; next = item->next;
if ((coalesceMask & NSNotificationCoalescingOnName) if ((coalesceMask & NSNotificationCoalescingOnName)
&& [name isEqual:item->name]) && [name isEqual: item->name])
{ {
remove_from_queue(asapQueue, item, zone); remove_from_queue(asapQueue, item, zone);
continue; continue;
@ -371,34 +373,41 @@ add_to_queue(
} }
} }
- (void)postNotification:(NSNotification*)notification forModes:(NSArray*)modes - (void) postNotification: (NSNotification*)notification
forModes: (NSArray*)modes
{ {
if (validMode(modes)) NSString *mode = [NSRunLoop currentMode];
[center postNotification:notification];
// 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 - (void)enqueueNotification: (NSNotification*)notification
postingStyle:(NSPostingStyle)postingStyle postingStyle: (NSPostingStyle)postingStyle
{ {
[self enqueueNotification:notification [self enqueueNotification: notification
postingStyle:postingStyle postingStyle: postingStyle
coalesceMask:NSNotificationCoalescingOnName + coalesceMask: NSNotificationCoalescingOnName +
NSNotificationCoalescingOnSender NSNotificationCoalescingOnSender
forModes:nil]; forModes: nil];
} }
- (void)enqueueNotification:(NSNotification*)notification - (void)enqueueNotification: (NSNotification*)notification
postingStyle:(NSPostingStyle)postingStyle postingStyle: (NSPostingStyle)postingStyle
coalesceMask:(NSNotificationCoalescing)coalesceMask coalesceMask: (NSNotificationCoalescing)coalesceMask
forModes:(NSArray*)modes forModes: (NSArray*)modes
{ {
if (coalesceMask != NSNotificationNoCoalescing) if (coalesceMask != NSNotificationNoCoalescing)
[self dequeueNotificationsMatching:notification [self dequeueNotificationsMatching: notification
coalesceMask:coalesceMask]; coalesceMask: coalesceMask];
switch (postingStyle) { switch (postingStyle) {
case NSPostNow: case NSPostNow:
[self postNotification:notification forModes:modes]; [self postNotification: notification forModes: modes];
break; break;
case NSPostASAP: case NSPostASAP:
add_to_queue(asapQueue, notification, modes, zone); add_to_queue(asapQueue, notification, modes, zone);
@ -409,72 +418,87 @@ add_to_queue(
} }
} }
/*
* NotificationQueue internals
*/
+ (void)runLoopIdle
{
NotificationQueueList* item;
for (item=[NotificationQueueList currentList]; item; item=[item next])
[[item queue] notifyIdle];
}
+ (BOOL)runLoopMore
{
NotificationQueueList* item;
for (item=[NotificationQueueList currentList]; item; item = [item next])
if ([[item queue] notifyMore] == YES)
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 @end
/*
* The following code handles sending of queued notifications by
* NSRunLoop.
*/
static inline void notifyASAP(NSNotificationQueue *q)
{
NSNotificationQueueList *list = ((accessQueue)q)->asapQueue;
/*
* 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);
}
}
void
GSNotifyASAP()
{
NotificationQueueList *item;
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;
}

View file

@ -1,5 +1,5 @@
/* Implementation of object for waiting on several input sources /* 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 <mccallum@gnu.ai.mit.edu> Original by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
Created: March 1996 Created: March 1996
@ -23,36 +23,8 @@
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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 <config.h> #include <config.h>
#include <base/preface.h> #include <base/preface.h>
#include <base/Heap.h>
#include <Foundation/NSMapTable.h> #include <Foundation/NSMapTable.h>
#include <Foundation/NSDate.h> #include <Foundation/NSDate.h>
#include <Foundation/NSValue.h> #include <Foundation/NSValue.h>
@ -73,8 +45,8 @@
#include <string.h> /* for memset() */ #include <string.h> /* for memset() */
static int debug_run_loop = 0; 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. * extended, and the methods must be modified to handle the new type.
* *
* The internal variables if the RunLoopWatcher are used as follows - * 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. * be removed from the runloop when next encountered.
* *
* The 'data' variable is used to identify the resource/event that the * 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 * NSRunLoops [-acceptInputForMode: beforeDate: ] method MUST contain
* code to watch for events of each type. * 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 * To set this variable, the method adding the RunLoopWatcher to the
* runloop must ask the 'receiver' (or its delegate) to supply a date * runloop must ask the 'receiver' (or its delegate) to supply a date
* using the '[-limitDateForMode: ]' message. * 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. * NB. This class is private to NSRunLoop and must not be subclassed.
*/ */
@interface RunLoopWatcher: NSObject <GCFinalization> static SEL eventSel = @selector(receivedEvent:type:extra:forMode:);
@interface RunLoopWatcher: NSObject
{ {
@public @public
BOOL invalidated; NSDate *_date; /* First to match layout of NSTimer */
BOOL handleEvent; // New-style event handling BOOL _invalidated; /* 2nd to match layout of NSTimer */
BOOL (*handleIsValid)(); IMP handleEvent; /* New-style event handling */
void *data; void *data;
id receiver; id receiver;
RunLoopEventType type; RunLoopEventType type;
NSDate *limit;
unsigned count; unsigned count;
} }
- (void) eventFor: (void*)info
mode: (NSString*)mode;
- initWithType: (RunLoopEventType)type - initWithType: (RunLoopEventType)type
receiver: (id)anObj receiver: (id)anObj
data: (void*)data; data: (void*)data;
- (void) invalidate;
- (BOOL) isValid;
@end @end
@implementation RunLoopWatcher @implementation RunLoopWatcher
- (void) dealloc - (void) dealloc
{ {
[self gcFinalize]; RELEASE(_date);
RELEASE(limit);
RELEASE(receiver); RELEASE(receiver);
[super dealloc]; [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 - (id) initWithType: (RunLoopEventType)aType
receiver: (id)anObj receiver: (id)anObj
data: (void*)item data: (void*)item
{ {
invalidated = NO; _invalidated = NO;
switch (aType) switch (aType)
{ {
@ -190,38 +125,54 @@ static SEL isValidSel = @selector(isValid);
format: @"NSRunLoop - unknown event type"]; format: @"NSRunLoop - unknown event type"];
} }
receiver = RETAIN(anObj); receiver = RETAIN(anObj);
if ([receiver respondsToSelector: if ([receiver respondsToSelector: eventSel] == YES)
@selector(receivedEvent:type:extra:forMode:)]) handleEvent = [receiver methodForSelector: eventSel];
handleEvent = YES;
else else
handleEvent = NO; handleEvent = 0;
data = item; data = item;
if ([receiver respondsToSelector: isValidSel])
handleIsValid = (BOOL(*)())[receiver methodForSelector: isValidSel];
return self; 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 @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 <base/FastArray.x>
@interface NSRunLoop (TimedPerformers) @interface NSRunLoop (TimedPerformers)
@ -450,22 +401,17 @@ static SEL isValidSel = @selector(isValid);
limit-date order. */ limit-date order. */
- (void) _addWatcher: (RunLoopWatcher*) item forMode: (NSString*)mode - (void) _addWatcher: (RunLoopWatcher*) item forMode: (NSString*)mode
{ {
NSMutableArray *watchers; FastArray watchers;
id obj; id obj;
NSDate *limit;
int count;
watchers = NSMapGet(_mode_2_watchers, mode); 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); 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]; NSDate *d = [obj limitDateForMode: mode];
ASSIGN(item->limit, d); ASSIGN(item->_date, d);
} }
else if ([obj respondsToSelector: @selector(delegate)]) else if ([obj respondsToSelector: @selector(delegate)])
{ {
@ -487,38 +433,14 @@ static SEL isValidSel = @selector(isValid);
{ {
NSDate *d = [obj limitDateForMode: mode]; 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 else
{ ASSIGN(item->_date, theFuture);
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];
}
} }
else
ASSIGN(item->_date, theFuture);
FastArrayInsertSorted(watchers, (FastArrayItem)item, aSort);
} }
- (void) _checkPerformers - (void) _checkPerformers
@ -720,8 +642,6 @@ static SEL isValidSel = @selector(isValid);
@implementation NSRunLoop @implementation NSRunLoop
static NSDate *theFuture;
#if GS_WITH_GC == 0 #if GS_WITH_GC == 0
static SEL wRelSel = @selector(release); static SEL wRelSel = @selector(release);
static SEL wRetSel = @selector(retain); static SEL wRetSel = @selector(retain);
@ -750,6 +670,27 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
#define WatcherMapValueCallBacks NSOwnedPointerMapValueCallBacks #define WatcherMapValueCallBacks NSOwnedPointerMapValueCallBacks
#endif #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 + (void) initialize
{ {
if (self == [NSRunLoop class]) if (self == [NSRunLoop class])
@ -786,9 +727,9 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
[super init]; [super init];
_current_mode = NSDefaultRunLoopMode; _current_mode = NSDefaultRunLoopMode;
_mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks, _mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 0); ArrayMapValueCallBacks, 0);
_mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks, _mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 0); ArrayMapValueCallBacks, 0);
_performers = [[NSMutableArray alloc] initWithCapacity: 8]; _performers = [[NSMutableArray alloc] initWithCapacity: 8];
_timedPerformers = [[NSMutableArray alloc] initWithCapacity: 8]; _timedPerformers = [[NSMutableArray alloc] initWithCapacity: 8];
_rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks, _rfdMap = NSCreateMapTable (NSIntMapKeyCallBacks,
@ -825,17 +766,18 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
- (void) addTimer: timer - (void) addTimer: timer
forMode: (NSString*)mode forMode: (NSString*)mode
{ {
Heap *timers; FastArray timers;
timers = NSMapGet(_mode_2_timers, mode); timers = NSMapGet(_mode_2_timers, mode);
if (!timers) 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); NSMapInsert(_mode_2_timers, mode, timers);
RELEASE(timers);
} }
/* xxx Should we make sure it isn't already there? */ FastArrayInsertSorted(timers, (FastArrayItem)timer, aSort);
[timers addObject: timer];
} }
@ -845,10 +787,10 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
- limitDateForMode: (NSString*)mode - limitDateForMode: (NSString*)mode
{ {
id saved_mode; id saved_mode;
Heap *timers; FastArray timers;
NSTimer *min_timer = nil; NSTimer *min_timer = nil;
RunLoopWatcher *min_watcher = nil; RunLoopWatcher *min_watcher = nil;
NSMutableArray *watchers; FastArray watchers;
NSDate *when; NSDate *when;
saved_mode = _current_mode; saved_mode = _current_mode;
@ -857,31 +799,39 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
timers = NSMapGet(_mode_2_timers, mode); timers = NSMapGet(_mode_2_timers, mode);
if (timers) 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; min_timer = nil;
continue; continue;
} }
if ([[min_timer fireDate] timeIntervalSinceNow] > 0) if ([timerDate(min_timer) timeIntervalSinceNow] > 0)
{ {
break; break;
} }
RETAIN(min_timer); FastArrayRemoveItemAtIndexNoRelease(timers, 0);
[timers removeFirstObject];
/* Firing will also increment its fireDate, if it is repeating. */ /* Firing will also increment its fireDate, if it is repeating. */
[min_timer fire]; [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; min_timer = nil;
[NSNotificationQueue runLoopASAP]; /* Post notifications. */ GSNotifyASAP(); /* Post notifications. */
} }
} }
@ -890,19 +840,19 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
watchers = NSMapGet(_mode_2_watchers, mode); watchers = NSMapGet(_mode_2_watchers, mode);
if (watchers) 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; min_watcher = nil;
continue; continue;
} }
when = min_watcher->limit; when = min_watcher->_date;
if (when == nil || [when timeIntervalSinceNow] > 0) if ([when timeIntervalSinceNow] > 0)
{ {
break; break;
} }
@ -937,15 +887,18 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
} }
if (nxt && [nxt timeIntervalSinceNow] > 0.0) if (nxt && [nxt timeIntervalSinceNow] > 0.0)
{ {
unsigned index;
/* /*
* If the watcher has been given a revised limit date - * If the watcher has been given a revised limit date -
* re-insert it into the queue in the correct place. * re-insert it into the queue in the correct place.
*/ */
RETAIN(min_watcher); FastArrayRemoveItemAtIndexNoRelease(watchers, 0);
ASSIGN(min_watcher->limit, nxt); ASSIGN(min_watcher->_date, nxt);
[watchers removeObjectAtIndex: 0]; index = FastArrayInsertionPosition(watchers,
[self _addWatcher: min_watcher forMode: mode]; (FastArrayItem)min_watcher, aSort);
RELEASE(min_watcher); FastArrayInsertItemNoRetain(watchers,
(FastArrayItem)min_watcher, index);
} }
else else
{ {
@ -954,8 +907,8 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
* remove it from the queue so that we don't need to * remove it from the queue so that we don't need to
* check it again. * check it again.
*/ */
[min_watcher invalidate]; min_watcher->_invalidated = YES;
[watchers removeObjectAtIndex: 0]; FastArrayRemoveItemAtIndex(watchers, 0);
} }
min_watcher = nil; min_watcher = nil;
} }
@ -978,29 +931,16 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
* If there are watchers, set the limit date to that of the earliest * 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 * watcher (or leave it as the date of the earliest timer if that is
* before the watchers limit). * 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) 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) if (when == nil)
{ {
when = lim; when = min_watcher->_date;
} }
else else
{ {
when = [when earlierDate: lim]; when = [when earlierDate: min_watcher->_date];
} }
} }
@ -1022,9 +962,7 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
type: (RunLoopEventType)type type: (RunLoopEventType)type
forMode: (NSString*)mode forMode: (NSString*)mode
{ {
NSArray *watchers; FastArray watchers;
RunLoopWatcher *info;
int count;
if (mode == nil) if (mode == nil)
{ {
@ -1032,17 +970,16 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
} }
watchers = NSMapGet(_mode_2_watchers, mode); watchers = NSMapGet(_mode_2_watchers, mode);
if (watchers == nil) if (watchers)
{ {
return nil; unsigned i = FastArrayCount(watchers);
}
for (count = 0; count < [watchers count]; count++)
{
info = [watchers objectAtIndex: count];
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; return info;
} }
@ -1055,7 +992,7 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
type: (RunLoopEventType)type type: (RunLoopEventType)type
forMode: (NSString*)mode forMode: (NSString*)mode
{ {
NSMutableArray *watchers; FastArray watchers;
if (mode == nil) if (mode == nil)
{ {
@ -1065,17 +1002,17 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
watchers = NSMapGet(_mode_2_watchers, mode); watchers = NSMapGet(_mode_2_watchers, mode);
if (watchers) 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) if (info->type == type && info->data == data)
{ {
[info invalidate]; info->_invalidated = YES;
[watchers removeObject: info]; FastArrayRemoveItemAtIndex(watchers, i);
} }
} }
} }
@ -1164,18 +1101,19 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
/* Do the pre-listening set-up for the file descriptors of this mode. */ /* Do the pre-listening set-up for the file descriptors of this mode. */
{ {
NSMutableArray *watchers; FastArray watchers;
watchers = NSMapGet(_mode_2_watchers, mode); watchers = NSMapGet(_mode_2_watchers, mode);
if (watchers) { if (watchers) {
int i; int i;
for (i = [watchers count]; i > 0; i--) { for (i = FastArrayCount(watchers); i > 0; i--) {
RunLoopWatcher* info = [watchers objectAtIndex: (i-1)]; RunLoopWatcher *info;
int fd; int fd;
if ([info isValid] == NO) { info = FastArrayItemAtIndex(watchers, i-1).obj;
[watchers removeObjectAtIndex: (i-1)]; if (info->_invalidated == YES) {
FastArrayRemoveItemAtIndex(watchers, i-1);
continue; continue;
} }
switch (info->type) { switch (info->type) {
@ -1226,7 +1164,7 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
/* Detect if the NSRunLoop is idle, and if necessary - dispatch the /* Detect if the NSRunLoop is idle, and if necessary - dispatch the
notifications from NSNotificationQueue's idle queue? */ notifications from NSNotificationQueue's idle queue? */
if (num_inputs == 0 && [NSNotificationQueue runLoopMore]) if (num_inputs == 0 && GSNotifyMore())
{ {
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 0; timeout.tv_usec = 0;
@ -1260,7 +1198,7 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
{ {
NSResetMapTable(_rfdMap); NSResetMapTable(_rfdMap);
NSResetMapTable(_wfdMap); NSResetMapTable(_wfdMap);
[NSNotificationQueue runLoopIdle]; GSNotifyIdle();
[self _checkPerformers]; [self _checkPerformers];
_current_mode = saved_mode; _current_mode = saved_mode;
return; return;
@ -1280,25 +1218,64 @@ const NSMapTableValueCallBacks WatcherMapValueCallBacks =
RunLoopWatcher *watcher; RunLoopWatcher *watcher;
watcher = NSMapGet(_wfdMap, (void*)fd_index); watcher = NSMapGet(_wfdMap, (void*)fd_index);
[watcher eventFor: (void*)(gsaddr)fd_index mode: _current_mode]; if (watcher->_invalidated == NO)
[NSNotificationQueue runLoopASAP]; {
/*
* 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)) if (FD_ISSET (fd_index, &read_fds))
{ {
RunLoopWatcher *watcher; RunLoopWatcher *watcher;
watcher = (RunLoopWatcher*)NSMapGet(_rfdMap, (void*)fd_index); watcher = (RunLoopWatcher*)NSMapGet(_rfdMap, (void*)fd_index);
[watcher eventFor: (void*)(gsaddr)fd_index mode: _current_mode]; if (watcher->_invalidated == NO)
[NSNotificationQueue runLoopASAP]; {
/*
* 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. */ /* Clean up before returning. */
NSResetMapTable(_rfdMap); NSResetMapTable(_rfdMap);
NSResetMapTable(_wfdMap); NSResetMapTable(_wfdMap);
[self _checkPerformers]; [self _checkPerformers];
[NSNotificationQueue runLoopASAP]; GSNotifyASAP();
_current_mode = saved_mode; _current_mode = saved_mode;
} }

View file

@ -37,11 +37,8 @@
userInfo: info userInfo: info
repeats: (BOOL)f repeats: (BOOL)f
{ {
[super init];
_interval = seconds; _interval = seconds;
_fire_date = [[NSDate alloc] initWithTimeIntervalSinceNow: seconds]; _date = [[NSDate alloc] initWithTimeIntervalSinceNow: seconds];
_retain_count = 0;
_is_valid = YES;
_target = t; _target = t;
_selector = sel; _selector = sel;
_info = info; _info = info;
@ -51,7 +48,7 @@
- (void) dealloc - (void) dealloc
{ {
[_fire_date release]; RELEASE(_date);
[super dealloc]; [super dealloc];
} }
@ -59,12 +56,11 @@
invocation: invocation invocation: invocation
repeats: (BOOL)f repeats: (BOOL)f
{ {
return [[[self alloc] initWithTimeInterval: ti return AUTORELEASE([[self alloc] initWithTimeInterval: ti
targetOrInvocation: invocation targetOrInvocation: invocation
selector: NULL selector: NULL
userInfo: nil userInfo: nil
repeats: f] repeats: f]);
autorelease];
} }
+ timerWithTimeInterval: (NSTimeInterval)ti + timerWithTimeInterval: (NSTimeInterval)ti
@ -73,12 +69,11 @@
userInfo: info userInfo: info
repeats: (BOOL)f repeats: (BOOL)f
{ {
return [[[self alloc] initWithTimeInterval: ti return AUTORELEASE([[self alloc] initWithTimeInterval: ti
targetOrInvocation: object targetOrInvocation: object
selector: selector selector: selector
userInfo: info userInfo: info
repeats: f] repeats: f]);
autorelease];
} }
+ scheduledTimerWithTimeInterval: (NSTimeInterval)ti + scheduledTimerWithTimeInterval: (NSTimeInterval)ti
@ -117,32 +112,44 @@
if (!_repeats) if (!_repeats)
[self invalidate]; [self invalidate];
else if (_is_valid) else if (!_invalidated)
{ {
NSTimeInterval ti = [_fire_date timeIntervalSinceReferenceDate]; NSTimeInterval ti = [_date timeIntervalSinceReferenceDate];
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; NSTimeInterval now = GSTimeNow();
int inc = -1;
NSAssert(now < 0.0, NSInternalInconsistencyException); NSAssert(now < 0.0, NSInternalInconsistencyException);
while (ti < now) // xxx remove this while (ti <= now) // xxx remove this
{
inc++;
ti += _interval; ti += _interval;
[_fire_date release]; }
_fire_date = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate: ti]; #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 - (void) invalidate
{ {
NSAssert(_is_valid, NSInternalInconsistencyException); NSAssert(_invalidated == NO, NSInternalInconsistencyException);
_is_valid = NO; _invalidated = YES;
} }
- (BOOL) isValid - (BOOL) isValid
{ {
return _is_valid; return !_invalidated;
} }
- fireDate - fireDate
{ {
return _fire_date; return _date;
} }
- userInfo - userInfo
@ -152,6 +159,6 @@
- (int)compare:(NSTimer*)anotherTimer - (int)compare:(NSTimer*)anotherTimer
{ {
return [_fire_date compare: anotherTimer->_fire_date]; return [_date compare: anotherTimer->_date];
} }
@end @end

View file

@ -32,7 +32,7 @@
*/ */
#define FAST_ARRAY_RETAIN(X) X #define FAST_ARRAY_RETAIN(X) X
#define FAST_ARRAY_RELEASE(X) #define FAST_ARRAY_RELEASE(X)
#define FAST_ARRAY__TYPES GSUNION_OBJ #define FAST_ARRAY_TYPES GSUNION_OBJ|GSUNION_SEL|GSUNION_STR
#include <base/FastArray.x> #include <base/FastArray.x>