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
* 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 <base/GSUnion.h>
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)
{

View file

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

View file

@ -24,7 +24,7 @@
/* Interface for NSNotificationQueue for GNUStep
Copyright (C) 1996 Free Software Foundation, Inc.
Modified by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Modified by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
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__ */

View file

@ -30,17 +30,20 @@
#include <base/preface.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
{
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. */

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 <mccallum@gnu.ai.mit.edu>
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 <config.h>
#include <base/preface.h>
#include <base/Heap.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSDate.h>
#include <Foundation/NSValue.h>
@ -73,8 +45,8 @@
#include <string.h> /* 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 <GCFinalization>
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 <base/FastArray.x>
@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;
}

View file

@ -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

View file

@ -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 <base/FastArray.x>