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