mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 08:21:25 +00:00
Attempt notification queue fix
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@29073 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
ee898e98e1
commit
1f22968eb4
3 changed files with 122 additions and 67 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2009-11-27 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/NSNotificationQueue.m: Rewrite queue handling to attempt to
|
||||||
|
fix bug #28104 by posting notifications matching the current run loop
|
||||||
|
mode and leaving others queued.
|
||||||
|
Also, change the meanining of a nil modes argument when enqueing a
|
||||||
|
notification to match OSX and assume NSDefaultRunLoopMode.
|
||||||
|
* Source/Additions/GSXML.m: Fix minor sax callback bug.
|
||||||
|
|
||||||
2009-11-27 Richard Frith-Macdonald <rfm@gnu.org>
|
2009-11-27 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/NSPropertyList.m: When serializing 'xml' style property lists
|
* Source/NSPropertyList.m: When serializing 'xml' style property lists
|
||||||
|
|
|
@ -3484,7 +3484,7 @@ fatalErrorFunction(void *ctx, const unsigned char *msg, ...)
|
||||||
SETCB(hasExternalSubset, hasExternalSubset);
|
SETCB(hasExternalSubset, hasExternalSubset);
|
||||||
SETCB(getEntity, getEntity:);
|
SETCB(getEntity, getEntity:);
|
||||||
SETCB(entityDecl, entityDecl:type:public:system:content:);
|
SETCB(entityDecl, entityDecl:type:public:system:content:);
|
||||||
SETCB(notationDecl, notationDecl:public:);
|
SETCB(notationDecl, notationDecl:public:system:);
|
||||||
SETCB(attributeDecl, attributeDecl:name:type:typeDefValue:defaultValue:);
|
SETCB(attributeDecl, attributeDecl:name:type:typeDefValue:defaultValue:);
|
||||||
SETCB(elementDecl, elementDecl:type:);
|
SETCB(elementDecl, elementDecl:type:);
|
||||||
SETCB(unparsedEntityDecl, unparsedEntityDecl:public:system:notationName:);
|
SETCB(unparsedEntityDecl, unparsedEntityDecl:public:system:notationName:);
|
||||||
|
|
|
@ -278,8 +278,7 @@ add_to_queue(NSNotificationQueueList *queue, NSNotification *notification,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@interface NSNotificationQueue (Private)
|
@interface NSNotificationQueue (Private)
|
||||||
- (void) _postNotification: (NSNotification*)notification
|
- (NSNotificationCenter*) _center;
|
||||||
forModes: (NSArray*)modes;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -291,6 +290,16 @@ add_to_queue(NSNotificationQueueList *queue, NSNotification *notification,
|
||||||
*/
|
*/
|
||||||
@implementation NSNotificationQueue
|
@implementation NSNotificationQueue
|
||||||
|
|
||||||
|
static NSArray *defaultMode = nil;
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
|
if (defaultMode == nil)
|
||||||
|
{
|
||||||
|
defaultMode = [[NSArray alloc] initWithObjects: &NSDefaultRunLoopMode
|
||||||
|
count: 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default notification queue for use in this thread. It will
|
* Returns the default notification queue for use in this thread. It will
|
||||||
|
@ -515,13 +524,17 @@ add_to_queue(NSNotificationQueueList *queue, NSNotification *notification,
|
||||||
* in which case they are removed through a call to
|
* in which case they are removed through a call to
|
||||||
* -dequeueNotificationsMatching:coalesceMask: . The modes argument
|
* -dequeueNotificationsMatching:coalesceMask: . The modes argument
|
||||||
* determines which [NSRunLoop] mode notification may be posted in (nil means
|
* determines which [NSRunLoop] mode notification may be posted in (nil means
|
||||||
* all modes).
|
* NSDefaultRunLoopMode).
|
||||||
*/
|
*/
|
||||||
- (void) enqueueNotification: (NSNotification*)notification
|
- (void) enqueueNotification: (NSNotification*)notification
|
||||||
postingStyle: (NSPostingStyle)postingStyle
|
postingStyle: (NSPostingStyle)postingStyle
|
||||||
coalesceMask: (NSUInteger)coalesceMask
|
coalesceMask: (NSUInteger)coalesceMask
|
||||||
forModes: (NSArray*)modes
|
forModes: (NSArray*)modes
|
||||||
{
|
{
|
||||||
|
if (modes == nil)
|
||||||
|
{
|
||||||
|
modes = defaultMode;
|
||||||
|
}
|
||||||
if (coalesceMask != NSNotificationNoCoalescing)
|
if (coalesceMask != NSNotificationNoCoalescing)
|
||||||
{
|
{
|
||||||
[self dequeueNotificationsMatching: notification
|
[self dequeueNotificationsMatching: notification
|
||||||
|
@ -530,11 +543,21 @@ add_to_queue(NSNotificationQueueList *queue, NSNotification *notification,
|
||||||
switch (postingStyle)
|
switch (postingStyle)
|
||||||
{
|
{
|
||||||
case NSPostNow:
|
case NSPostNow:
|
||||||
[self _postNotification: notification forModes: modes];
|
{
|
||||||
|
NSString *mode;
|
||||||
|
|
||||||
|
mode = [[NSRunLoop currentRunLoop] currentMode];
|
||||||
|
if (mode == nil || [modes indexOfObject: mode] != NSNotFound)
|
||||||
|
{
|
||||||
|
[_center postNotification: notification];
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NSPostASAP:
|
case NSPostASAP:
|
||||||
add_to_queue(_asapQueue, notification, modes, _zone);
|
add_to_queue(_asapQueue, notification, modes, _zone);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NSPostWhenIdle:
|
case NSPostWhenIdle:
|
||||||
add_to_queue(_idleQueue, notification, modes, _zone);
|
add_to_queue(_idleQueue, notification, modes, _zone);
|
||||||
break;
|
break;
|
||||||
|
@ -545,48 +568,82 @@ add_to_queue(NSNotificationQueueList *queue, NSNotification *notification,
|
||||||
|
|
||||||
@implementation NSNotificationQueue (Private)
|
@implementation NSNotificationQueue (Private)
|
||||||
|
|
||||||
- (void) _postNotification: (NSNotification*)notification
|
- (NSNotificationCenter*) _center
|
||||||
forModes: (NSArray*)modes
|
|
||||||
{
|
{
|
||||||
NSString *mode = [[NSRunLoop currentRunLoop] currentMode];
|
return _center;
|
||||||
|
|
||||||
// check to see if run loop is in a valid mode
|
|
||||||
if (mode == nil || modes == nil
|
|
||||||
|| [modes indexOfObject: mode] != NSNotFound)
|
|
||||||
{
|
|
||||||
[_center postNotification: notification];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
static void
|
||||||
|
notify(NSNotificationCenter *center, NSNotificationQueueList *list,
|
||||||
|
NSString *mode, NSZone *zone)
|
||||||
|
{
|
||||||
|
BOOL allocated = NO;
|
||||||
|
NSNotificationQueueRegistration *buf[100];
|
||||||
|
NSNotificationQueueRegistration **ptr = buf;
|
||||||
|
unsigned len = sizeof(buf) / sizeof(*buf);
|
||||||
|
unsigned pos = 0;
|
||||||
|
NSNotificationQueueRegistration *item = list->head;
|
||||||
|
|
||||||
|
/* Gather matching items into a buffer.
|
||||||
|
*/
|
||||||
|
while (item != 0)
|
||||||
|
{
|
||||||
|
if (mode == nil || [item->modes indexOfObject: mode] != NSNotFound)
|
||||||
|
{
|
||||||
|
if (pos == len)
|
||||||
|
{
|
||||||
|
unsigned want;
|
||||||
|
|
||||||
|
want = (len == 0) ? 2 : len * 2;
|
||||||
|
if (NO == allocated)
|
||||||
|
{
|
||||||
|
void *tmp;
|
||||||
|
|
||||||
|
tmp = NSZoneMalloc(NSDefaultMallocZone(),
|
||||||
|
want * sizeof(void*));
|
||||||
|
memcpy(tmp, (void*)ptr, len * sizeof(void*));
|
||||||
|
ptr = tmp;
|
||||||
|
allocated = YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ptr = NSZoneRealloc(NSDefaultMallocZone(),
|
||||||
|
ptr, want * sizeof(void*));
|
||||||
|
}
|
||||||
|
len = want;
|
||||||
|
}
|
||||||
|
ptr[pos++] = item;
|
||||||
|
}
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
len = pos; // Number of items found
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
for (pos = 0; pos < len; pos++)
|
||||||
|
{
|
||||||
|
NSNotification *notification;
|
||||||
|
|
||||||
|
item = ptr[pos];
|
||||||
|
notification = RETAIN(item->notification);
|
||||||
|
remove_from_queue(list, item, zone);
|
||||||
|
[center postNotification: notification];
|
||||||
|
RELEASE(notification);
|
||||||
|
}
|
||||||
|
if (allocated)
|
||||||
|
{
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following code handles sending of queued notifications by
|
* The following code handles sending of queued notifications by
|
||||||
* NSRunLoop.
|
* NSRunLoop.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline void
|
|
||||||
notifyASAP(NSNotificationQueue *q, NSString *mode)
|
|
||||||
{
|
|
||||||
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
|
void
|
||||||
GSPrivateNotifyASAP(NSString *mode)
|
GSPrivateNotifyASAP(NSString *mode)
|
||||||
{
|
{
|
||||||
|
@ -596,37 +653,14 @@ GSPrivateNotifyASAP(NSString *mode)
|
||||||
{
|
{
|
||||||
if (item->queue)
|
if (item->queue)
|
||||||
{
|
{
|
||||||
notifyASAP(item->queue, mode);
|
notify(((accessQueue)item->queue)->_center,
|
||||||
|
((accessQueue)item->queue)->_asapQueue,
|
||||||
|
mode,
|
||||||
|
((accessQueue)item->queue)->_zone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
notifyIdle(NSNotificationQueue *q, NSString *mode)
|
|
||||||
{
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
notifyASAP(q, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
GSPrivateNotifyIdle(NSString *mode)
|
GSPrivateNotifyIdle(NSString *mode)
|
||||||
{
|
{
|
||||||
|
@ -636,7 +670,10 @@ GSPrivateNotifyIdle(NSString *mode)
|
||||||
{
|
{
|
||||||
if (item->queue)
|
if (item->queue)
|
||||||
{
|
{
|
||||||
notifyIdle(item->queue, mode);
|
notify(((accessQueue)item->queue)->_center,
|
||||||
|
((accessQueue)item->queue)->_idleQueue,
|
||||||
|
mode,
|
||||||
|
((accessQueue)item->queue)->_zone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -648,9 +685,18 @@ GSPrivateNotifyMore(NSString *mode)
|
||||||
|
|
||||||
for (item = currentList(); item; item = item->next)
|
for (item = currentList(); item; item = item->next)
|
||||||
{
|
{
|
||||||
if (item->queue && ((accessQueue)item->queue)->_idleQueue->head)
|
if (item->queue != nil)
|
||||||
{
|
{
|
||||||
return YES;
|
NSNotificationQueueRegistration *r;
|
||||||
|
|
||||||
|
r = ((accessQueue)item->queue)->_idleQueue->head;
|
||||||
|
while (r != 0)
|
||||||
|
{
|
||||||
|
if (mode == nil || [r->modes indexOfObject: mode] != NSNotFound)
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NO;
|
return NO;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue