mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 01:31:08 +00:00
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:
parent
7fd494e6ec
commit
76c9b88542
12 changed files with 654 additions and 527 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -105,6 +105,8 @@ typedef double NSTimeInterval;
|
|||
NSTimeInterval seconds_since_ref;
|
||||
}
|
||||
@end
|
||||
|
||||
NSTimeInterval GSTimeNow(); /* Get time since reference date */
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
Loading…
Reference in a new issue