improve linked list api

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@31440 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2010-09-29 14:04:18 +00:00
parent 0c664e3100
commit dd2dc9ef19
5 changed files with 641 additions and 317 deletions

View file

@ -1,3 +1,12 @@
2010-09-29 Richard Frith-Macdonald <rfm@gnu.org>
* GSLinkedList.h:
* GSLinkedList.m:
Revise structure and API for greater flexibility.
* GSThreadPool.h
* GSThreadPool.m
Modify for new linked list api.
2010-09-23 Richard Frith-Macdonald <rfm@gnu.org> 2010-09-23 Richard Frith-Macdonald <rfm@gnu.org>
* performance/GSThreadPool.h: * performance/GSThreadPool.h:

View file

@ -24,107 +24,247 @@
*/ */
#import <Foundation/NSObject.h> #import <Foundation/NSObject.h>
/** GSLinkedList provides simple doubly linked list functionality to @class GSLinkedList;
/** GSListLink provides simple doubly linked list functionality to
* avoid the need to constantly re-invent it (as the OpenStep/Cocoa * avoid the need to constantly re-invent it (as the OpenStep/Cocoa
* APIs do not provide this). The emphasis is on speed of operation * APIs do not provide this). The emphasis is on speed of operation
* so instance variables are directly accessible and functions are * so instance variables are directly accessible and inline functions
* provided to manipulate them, but you can/should avoid these direct * are provided to manipulate them (without error cehcking), but you
* access features unless speed is really critical.<br /> * can/should avoid these direct access features unless speed is
* A list is handled simply as a pointer to the link whose 'prev' * really critical.<br />
* pointer is nil. <br /> * A list may either be 'normal' ... (where the head/tail ends of
* While the item value of a link is retaned by the link, links in a * the list have a nil pointer to the previous/next link) or 'circular'
* list are not retained, so you must manage retain/relase yourself. * in which case the list is not terminated. <br />
* The GSListLink item carries a minimal payload of a single item which
* is retained by the link.<br />
* The GSListLink owner is an optional pointer to an object which 'owns'
* the link ... a GSLinkedList instance may use this to check link
* ownership when manipulating links.
*/
@interface GSListLink : NSObject
{
@public
GSListLink *next; // Not retained
GSListLink *previous; // Not retained
GSLinkedList *owner; // Not retained
NSObject *item;
}
/** Initialise the receiver as a link for a circular linked list.
*/
- (id) initCircular;
/** Return the next item in the list containing the receiver,
* or nil if there are no more items.
*/
- (GSListLink*) next;
/** Return the list which owns the receiver or nil if the receiver is
* not in a list.
*/
- (GSLinkedList*) owner;
/** Return the previous item in the list containing the receiver,
* or nil if there are no more items.
*/
- (GSListLink*) previous;
/** Set an item value by retaining it and releasing any previous value.
*/
- (void) setItem: (NSObject*)anItem;
@end
/** Inserts link after at in a circular list.<br />
* Arguments must not be nil and link must not be in a list
* (ie its next and previous pointers must point to itsself).
*/
static inline void
GSLinkCircularInsertAfter(GSListLink *link, GSListLink *at)
{
link->next = at->next;
link->previous = at;
link->next->previous = link;
link->previous->next = link;
}
/** Inserts link before at in a circular list.<br />
* Arguments must not be nil and link must not be in a list
* (ie its next and previous pointers must point to itsself).
*/
static inline void
GSLinkCircularInsertBefore(GSListLink *link, GSListLink *at)
{
link->next = at;
link->previous = at->previous;
link->next->previous = link;
link->previous->next = link;
}
/** Removes link from any list it is in.<br />
* The link argument must not be nil.
*/
static inline void
GSLinkCircularRemove(GSListLink *link)
{
link->next->previous = link->previous;
link->previous->next = link->next;
link->next = link->previous = link;
}
/** Inserts link after at in a normal list.<br />
* Arguments must not be nil and link must not be in a list
* (ie its next and previous pointers must both be nil).
*/
static inline void
GSLinkInsertAfter(GSListLink *link, GSListLink *at)
{
if (nil != at->next)
{
at->next->previous = link;
}
link->previous = at;
at->next = link;
}
/** Inserts link before at in a normal list.<br />
* Arguments must not be nil and link must not be in a list
* (ie its next and previous pointers must both be nil).
*/
static inline void
GSLinkInsertBefore(GSListLink *link, GSListLink *at)
{
if (nil != at->previous)
{
at->previous->next = link;
}
link->next = at;
at->previous = link;
}
/** Removes link from the list it is in.<br />
* The link argument must not be nil.
*/
static inline void
GSLinkRemove(GSListLink *link)
{
if (nil != link->next)
{
link->next->previous = link->previous;
}
if (nil != link->previous)
{
link->previous->next = link->next;
}
link->next = link->previous = nil;
}
/** GSLinkedList manages a list of GSListLink objects.
*/ */
@interface GSLinkedList : NSObject @interface GSLinkedList : NSObject
{ {
@public @public
GSLinkedList *next; // Not retained GSListLink *head; // First link in the list.
GSLinkedList *prev; // Not retained GSListLink *tail; // Last link in the list.
NSObject *item; NSUInteger count; // Number of links in the list.
} }
/** Appends other at the end of the linked list contining the receiver. /** Appends link at the end of the linked list managed by the receiver.<br />
* Retains the link.
*/ */
- (void) append: (GSLinkedList*)other; - (void) append: (GSListLink*)link;
/** Searches the linked list containing the receiver from the /** Returns the number of links in the list.
* receiver onwards, returning the link containing object or nil */
- (NSUInteger) count;
/** Remove all links from the list and release them all.
*/
- (void) empty;
/** Searches the linked list returning the link containing object or nil
* if it is not found.<br /> * if it is not found.<br />
* The comparison is performed using the -isEqual: method of object.<br /> * The comparison is performed using the [NSObject-isEqual:] method
* This method will <em>not</em> find links containins nil items. * of object.<br />
* If start is nil then the whole list is searched.<br />
* This method will <em>not</em> find links containing nil items.
*/ */
- (id) findEqual: (NSObject*)object; - (GSListLink*) findEqual: (NSObject*)object
from: (GSListLink*)start
back: (BOOL)aFlag;
/** Searches the linked list containing the receiver, from the receiver /** Searches the linked list returning the link containing object or nil
* onwards, returning the link containing object or nil if it is not found. * if it is not found.<br />
* If start is nil then the whole list is searched.<br />
* A direct pointer comparison is used to determine equality. * A direct pointer comparison is used to determine equality.
*/ */
- (id) findIdentical: (NSObject*)object; - (GSListLink*) findIdentical: (NSObject*)object
from: (GSListLink*)start
back: (BOOL)aFlag;
/** Returns the first link in the list. /** Returns the first link in the list.
*/ */
- (id) head; - (GSListLink*) head;
/** Inserts other immediately before the receiver. /** Inserts other immediately after the receiver.<br />
* Retains the link.
*/ */
- (void) insert: (GSLinkedList*)other; - (void) insert: (GSListLink*)link after: (GSListLink*)at;
/** Returns the item in the link represented by the receiver.<br /> /** Inserts other immediately before the receiver.<br />
* The item may be nil. * Retains the link.
*/ */
- (NSObject*) item; - (void) insert: (GSListLink*)link before: (GSListLink*)at;
/** Returns the next link in the list, or nil if the receiver is at the tail. /** Removes the link from the receiver.<br />
* releases the link.
*/ */
- (id) next; - (void) removeLink: (GSListLink*)link;
/** Returns the previous link in the list, or nil if the receiver is at the
* head.
*/
- (id) previous;
/** Removes the receiver from the linked list containing it.<br />
* Returns the link which was next after the receiver.
*/
- (id) remove;
/** Replaces any existing item in the receiver with the supplied object.<br />
* The item may be nil.
*/
- (void) setItem: (NSObject*)object;
/** Returns the last link in the list. /** Returns the last link in the list.
*/ */
- (id) tail; - (GSListLink*) tail;
@end @end
/** Appends link at the end of the list. /** Searches from list to the end looking for the first link containing
* object (as determined by using object's [NSObject-isEqual:] method).<br />
* If from is nil the list is search from head or tail as appropriate
* to the direction in which it is searched.
*/ */
extern void extern GSListLink*
GSLinkedListAppend(GSLinkedList *link, GSLinkedList *list); GSLinkedListFindEqual(NSObject *object, GSLinkedList *list,
GSListLink *from, BOOL back);
/** Searches from list to the end looking for the first link containing /** Searches from list to the end looking for the first link containing
* object (as determiend by using object's -isEqual: method). * object (as determined by direct pointer comparison).<br />
* If from is nil the list is search from head or tail as appropriate
* to the direction in which it is searched.
*/ */
extern id extern GSListLink*
GSLinkedListFindEqual(NSObject *object, GSLinkedList *list); GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list,
GSListLink *from, BOOL back);
/** Searches from list to the end looking for the first link containing /** Inserts link immediately after at.<br />
* object (as determiend by direct pointer comparison). * Updates the head, tail and count variables of list.<br />
*/ * Does not retain link.
extern id
GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list);
/** Inserts link immediately before at.
*/ */
extern void extern void
GSLinkedListInsert(GSLinkedList *link, GSLinkedList *at); GSLinkedListInsertAfter(GSListLink *link, GSLinkedList *list, GSListLink *at);
/** Removes link from it list and returns the next item in the list /** Inserts link immediately before at.<br />
* or nil if there is no next item. * Updates the head, tail and count variables of list.<br />
* Does not retain link.
*/ */
extern id extern void
GSLinkedListRemove(GSLinkedList *link); GSLinkedListInsertBefore(GSListLink *link, GSLinkedList *list, GSListLink *at);
/** Removes link from the list.<br />
* Updates the head, tail and count variables of list.<br />
* Does not release link.
*/
extern void
GSLinkedListRemove(GSListLink *link, GSLinkedList *list);
#endif #endif

View file

@ -23,186 +23,430 @@
#import <Foundation/NSException.h> #import <Foundation/NSException.h>
#import "GSLinkedList.h" #import "GSLinkedList.h"
@implementation GSLinkedList @implementation GSListLink
- (void) append: (GSLinkedList*)other
{
if (nil == other)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] nil argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (other->next || other->prev)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] other link is still in a list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
GSLinkedListAppend(other, self);
}
- (void) dealloc - (void) dealloc
{ {
if (next || prev) NSAssert(nil != owner, NSInternalInconsistencyException);
{
[NSException raise: NSInternalInconsistencyException
format: @"[%@-%@] receiver is still in a list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
[item release]; [item release];
[super dealloc]; [super dealloc];
} }
- (id) findEqual: (NSObject*)object; - (id) initCircular
{ {
return GSLinkedListFindEqual(object, self); if ((self = [super init]) != nil)
}
- (id) findIdentical: (NSObject*)object;
{
return GSLinkedListFindIdentical(object, self);
}
- (id) head
{
GSLinkedList *link = self;
while (nil != link->prev)
{ {
link = link->prev; next = previous = self;
} }
return link; return self;
} }
- (void) insert: (GSLinkedList*)other - (id) item
{ {
if (nil == other) return item;
}
- (GSListLink*) next
{
if (next == self)
{
return nil;
}
return next;
}
- (GSLinkedList*) owner
{
return owner;
}
- (GSListLink*) previous
{
if (previous == self)
{
return nil;
}
return previous;
}
- (void) setItem: (NSObject*)anItem
{
id o = item;
item = [anItem retain];
[o release];
}
@end
@implementation GSLinkedList
- (void) append: (GSListLink*)link
{
if (nil == link)
{ {
[NSException raise: NSInvalidArgumentException [NSException raise: NSInvalidArgumentException
format: @"[%@-%@] nil argument", format: @"[%@-%@] nil argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
} }
if (other->next || other->prev) if (self == link->owner)
{
if (link != tail)
{
GSLinkedListRemove(link, self);
GSLinkedListInsertAfter(link, self, tail);
}
}
else
{
if (nil != link->owner || nil != link->next || nil != link->previous)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] other link is still in a list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
GSLinkedListInsertAfter(link, self, tail);
[link retain];
}
}
- (NSUInteger) count
{
return count;
}
- (void) dealloc
{
count = 0;
tail = nil;
while (nil != head)
{
GSListLink *link = head;
head = link->next;
head->next = head->previous = nil;
head->owner = nil;
[head release];
}
[super dealloc];
}
- (void) empty
{
GSListLink *link;
while (nil != (link = head))
{
head = link->next;
link->owner = nil;
link->next = link->previous = nil;
[link release];
}
tail = nil;
count = 0;
}
- (GSListLink*) findEqual: (NSObject*)object
from: (GSListLink*)start
back: (BOOL)aFlag
{
if (nil != start && start->owner != self)
{ {
[NSException raise: NSInvalidArgumentException [NSException raise: NSInvalidArgumentException
format: @"[%@-%@] other link is still in a list", format: @"[%@-%@] start link is not in this list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
} }
GSLinkedListInsert(other, self); return GSLinkedListFindEqual(object, self, start, aFlag);
} }
- (NSObject*) item - (GSListLink*) findIdentical: (NSObject*)object
from: (GSListLink*)start
back: (BOOL)aFlag
{ {
return item; if (nil != start && start->owner != self)
}
- (id) next
{
return next;
}
- (id) previous
{
return prev;
}
- (id) remove
{
return GSLinkedListRemove(self);
}
- (void) setItem: (NSObject*)object
{
id o = item;
item = [object retain];
[o release];
}
- (id) tail
{
GSLinkedList *link = self;
while (nil != link->next)
{ {
link = link->next; [NSException raise: NSInvalidArgumentException
format: @"[%@-%@] start link is not in this list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
} }
return link; return GSLinkedListFindIdentical(object, self, start, aFlag);
}
- (GSListLink*) head
{
return head;
}
- (void) insert: (GSListLink*)link after: (GSListLink*)at
{
if (nil == link)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] nil link argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (nil == at)
{
at = tail;
}
if (at->owner != self)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] 'at' link is not in this list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (at == link)
{
return;
}
if (link->owner == self)
{
GSLinkedListRemove(link, self);
GSLinkedListInsertAfter(link, self, at);
}
else
{
if (nil != link->owner || nil != link->next || nil != link->previous)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] other link is still in a list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
GSLinkedListInsertAfter(link, self, at);
[link retain];
}
}
- (void) insert: (GSListLink*)link before: (GSListLink*)at
{
if (nil == link)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] nil link argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (nil == at)
{
at = head;
}
if (at->owner != self)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] 'at' link is not in this list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (at == link)
{
return;
}
if (link->owner == self)
{
GSLinkedListRemove(link, self);
GSLinkedListInsertBefore(link, self, at);
}
else
{
if (nil != link->owner || nil != link->next || nil != link->previous)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] other link is still in a list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
GSLinkedListInsertBefore(link, self, at);
[link retain];
}
}
- (void) removeLink: (GSListLink*)link
{
if (nil == link)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] nil link argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
if (link->owner != self)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] link is not in this list",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
GSLinkedListRemove(link, self);
[link release];
}
- (GSListLink*) tail
{
return tail;
} }
@end @end
void void
GSLinkedListAppend(GSLinkedList *link, GSLinkedList *list) GSLinkedListInsertBefore(GSListLink *link, GSLinkedList *list, GSListLink *at)
{ {
while (nil != list->next) if (nil == list->head)
{ {
list = list->next; list->head = list->tail = link;
} }
link->prev = list; else
list->next = link; {
link->previous = at->previous;
if (nil == link->previous)
{
list->head = link;
}
else
{
link->previous->next = link;
}
at->previous = link;
link->next = at;
}
link->owner = list;
list->count++;
} }
void void
GSLinkedListInsert(GSLinkedList *link, GSLinkedList *at) GSLinkedListInsertAfter(GSListLink *link, GSLinkedList *list, GSListLink *at)
{ {
link->next = at; if (nil == list->head)
if (nil != at->prev)
{ {
at->prev->next = link; list->head = list->tail = link;
link->prev = at->prev;
} }
at->prev = link; else
{
link->next = at->next;
if (nil == link->next)
{
list->tail = link;
}
else
{
link->next->previous = link;
}
at->next = link;
link->previous = at;
}
link->owner = list;
list->count++;
} }
id void
GSLinkedListRemove(GSLinkedList *link) GSLinkedListRemove(GSListLink *link, GSLinkedList *list)
{ {
GSLinkedList *next = link->next; if (list->head == link)
if (nil != link->next)
{ {
link->next->prev = link->prev; list->head = link->next;
if (nil != list->head)
{
list->head->previous = nil;
}
} }
if (nil != link->prev) else
{ {
link->prev->next = link->next; link->previous->next = link->next;
} }
link->next = nil; if (list->tail == link)
link->prev = nil; {
return next; list->tail = link->previous;
if (nil != list->tail)
{
list->tail->next = nil;
}
}
else
{
link->next->previous = link->previous;
}
link->next = link->previous = nil;
link->owner = nil;
list->count--;
} }
id GSListLink*
GSLinkedListFindEqual(NSObject *object, GSLinkedList *list) GSLinkedListFindEqual(NSObject *object, GSLinkedList *list,
GSListLink *from, BOOL back)
{ {
if (nil == from)
{
if (YES == back)
{
from = list->tail;
}
else
{
from = list->head;
}
}
if (nil != object) if (nil != object)
{ {
BOOL (*imp)(id, SEL, id); BOOL (*imp)(id, SEL, id);
imp = (BOOL(*)(id,SEL,id))[object methodForSelector: @selector(isEqual:)]; imp = (BOOL(*)(id,SEL,id))[object methodForSelector: @selector(isEqual:)];
while (nil != list) if (YES == back)
{ {
if (YES == (*imp)(object, @selector(isEqual:), list->item)) while (nil != from)
{ {
return list; if (YES == (*imp)(object, @selector(isEqual:), from->item))
{
return from;
}
from = from->previous;
} }
list = list->next;
} }
} else
return nil;
}
id
GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list)
{
while (nil != list)
{
if (object == list->item)
{ {
return list; while (nil != from)
{
if (YES == (*imp)(object, @selector(isEqual:), from->item))
{
return from;
}
from = from->next;
}
}
}
return nil;
}
GSListLink*
GSLinkedListFindIdentical(NSObject *object, GSLinkedList *list,
GSListLink *from, BOOL back)
{
if (nil == from)
{
if (YES == back)
{
from = list->tail;
}
else
{
from = list->head;
}
}
if (YES == back)
{
while (nil != from)
{
if (object == from->item)
{
return from;
}
from = from->previous;
}
}
else
{
while (nil != from)
{
if (object == from->item)
{
return from;
}
from = from->next;
} }
list = list->next;
} }
return nil; return nil;
} }

View file

@ -24,8 +24,7 @@
*/ */
#import <Foundation/NSObject.h> #import <Foundation/NSObject.h>
@class GSOperation; @class GSLinkedList;
@class GSThreadLink;
@class NSLock; @class NSLock;
/** This class provides a thread pool for performing methods /** This class provides a thread pool for performing methods
@ -41,16 +40,11 @@
BOOL shutdown; BOOL shutdown;
BOOL suspended; BOOL suspended;
NSUInteger maxThreads; NSUInteger maxThreads;
NSUInteger threadCount; GSLinkedList *idle;
NSUInteger activeCount; GSLinkedList *live;
GSThreadLink *idle;
GSThreadLink *live;
NSUInteger maxOperations; NSUInteger maxOperations;
NSUInteger operationCount; GSLinkedList *operations;
GSOperation *operations; GSLinkedList *unused;
GSOperation *lastOperation;
NSUInteger unusedCount;
GSOperation *unused;
NSUInteger processed; NSUInteger processed;
} }

View file

@ -5,7 +5,7 @@
@class GSThreadPool; @class GSThreadPool;
@interface GSOperation : GSLinkedList @interface GSOperation : GSListLink
{ {
@public @public
SEL sel; SEL sel;
@ -20,7 +20,7 @@
} }
@end @end
@interface GSThreadLink : GSLinkedList @interface GSThreadLink : GSListLink
{ {
@public @public
GSThreadPool *pool; // Not retained GSThreadPool *pool; // Not retained
@ -28,6 +28,7 @@
GSOperation *op; GSOperation *op;
} }
@end @end
@implementation GSThreadLink @implementation GSThreadLink
- (void) dealloc - (void) dealloc
{ {
@ -44,7 +45,7 @@
return self; return self;
} }
@end @end
;
@interface GSThreadPool (Internal) @interface GSThreadPool (Internal)
- (void) _any; - (void) _any;
- (void) _dead: (GSThreadLink*)link; - (void) _dead: (GSThreadLink*)link;
@ -58,35 +59,33 @@
- (void) dealloc - (void) dealloc
{ {
GSThreadLink *link;
[poolLock lock]; [poolLock lock];
while (nil != operations) [operations release];
operations = nil;
[unused release];
unused = nil;
if (nil != idle)
{ {
id link = operations; while (nil != (link = (GSThreadLink*)idle->head))
{
operations = [link remove]; GSLinkedListRemove(link, idle);
[link release]; [link->lock lock];
[link->lock unlockWithCondition: 1];
}
[idle release];
idle = nil;
} }
while (nil != unused) if (nil != live)
{ {
id link = operations; while (nil != (link = (GSThreadLink*)live->head))
{
unused = [link remove]; GSLinkedListRemove(link, live);
[link release]; link->pool = nil;
} }
while (nil != idle) [live release];
{ live = nil;
GSThreadLink *link = idle;
idle = [link remove];
[link->lock lock];
[link->lock unlockWithCondition: 1];
}
while (nil != live)
{
GSThreadLink *link = live;
live = [link remove];
link->pool = nil;
} }
[poolLock unlock]; [poolLock unlock];
[poolLock release]; [poolLock release];
@ -100,8 +99,8 @@
[poolLock lock]; [poolLock lock];
result = [NSString stringWithFormat: result = [NSString stringWithFormat:
@"%@ queue: %u(%u) threads: %u(%u) active: %u processed: %u", @"%@ queue: %u(%u) threads: %u(%u) active: %u processed: %u",
[super description], operationCount, maxOperations, [super description], operations->count, maxOperations,
threadCount, maxThreads, activeCount, processed]; idle->count + live->count, maxThreads, live->count, processed];
[poolLock unlock]; [poolLock unlock];
return result; return result;
} }
@ -123,15 +122,8 @@
NSUInteger counter; NSUInteger counter;
[poolLock lock]; [poolLock lock];
counter = operationCount; counter = operations->count;
while (nil != operations) [operations empty];
{
id o = operations;
operations = [o remove];
operationCount--;
[o release];
}
[poolLock unlock]; [poolLock unlock];
return counter; return counter;
} }
@ -141,6 +133,10 @@
if ((self = [super init]) != nil) if ((self = [super init]) != nil)
{ {
poolLock = [NSRecursiveLock new]; poolLock = [NSRecursiveLock new];
idle = [GSLinkedList new];
live = [GSLinkedList new];
operations = [GSLinkedList new];
unused = [GSLinkedList new];
[self setOperations: 100]; [self setOperations: 100];
[self setThreads: 2]; [self setThreads: 2];
} }
@ -149,12 +145,12 @@
- (BOOL) isEmpty - (BOOL) isEmpty
{ {
return (nil == operations) ? YES : NO; return (0 == operations->count) ? YES : NO;
} }
- (BOOL) isIdle - (BOOL) isIdle
{ {
return (nil == live) ? YES : NO; return (0 == live->count) ? YES : NO;
} }
- (BOOL) isSuspended - (BOOL) isSuspended
@ -201,33 +197,23 @@
format: @"Nil receiver"]; format: @"Nil receiver"];
} }
[poolLock lock]; [poolLock lock];
if (operationCount < maxOperations && maxThreads > 0) if (operations->count < maxOperations && maxThreads > 0)
{ {
GSOperation *op = unused; GSOperation *op = (GSOperation*)unused->head;
if (nil == op) if (nil == op)
{ {
op = [GSOperation new]; // Need a new one op = [GSOperation new]; // Need a new one
} }
else else
{ {
unused = [op remove]; // Re-use an old one GSLinkedListRemove(op, unused); // Re-use an old one
unusedCount--;
} }
[op setItem: aReceiver]; [op setItem: aReceiver];
op->sel = aSelector; op->sel = aSelector;
op->arg = [anArgument retain]; op->arg = [anArgument retain];
if (nil == operations) GSLinkedListInsertAfter(op, operations, operations->tail);
{
operations = lastOperation = op;
}
else
{
[lastOperation append: op];
}
lastOperation = op;
operationCount++;
[self _any]; [self _any];
[poolLock unlock]; [poolLock unlock];
} }
@ -276,17 +262,16 @@
} }
[poolLock lock]; [poolLock lock];
} }
while (maxThreads < threadCount && idle != nil) while (maxThreads < idle->count + live->count && idle->count > 0)
{ {
GSThreadLink *link = idle; GSThreadLink *link = (GSThreadLink*)idle->head;
/* Remove thread link from the idle list, then start up the /* Remove thread link from the idle list, then start up the
* thread using the condition lock ... the thread will see * thread using the condition lock ... the thread will see
* that it has no operation to work with and will terminate * that it has no operation to work with and will terminate
* itsself and release the link. * itsself and release the link.
*/ */
idle = [idle remove]; GSLinkedListRemove(link, idle);
threadCount--;
[link->lock lock]; [link->lock lock];
[link->lock unlockWithCondition: 1]; [link->lock unlockWithCondition: 1];
} }
@ -313,30 +298,27 @@
{ {
GSOperation *op; GSOperation *op;
while (nil != (op = operations)) while (nil != (op = (GSOperation*)operations->head))
{ {
GSThreadLink *link = idle; GSThreadLink *link = (GSThreadLink*)idle->head;
if (nil == link) if (nil == link)
{ {
if (maxThreads > threadCount) if (maxThreads > idle->count + live->count)
{ {
NSThread *thread; NSThread *thread;
/* Create a new link, add it to the idle list, and start the /* Create a new link, add it to the idle list, and start the
* thread which will work withn it. * thread which will work withn it.
*/ */
threadCount++;
link = [GSThreadLink new]; link = [GSThreadLink new];
link->pool = self; link->pool = self;
thread = [[NSThread alloc] initWithTarget: self thread = [[NSThread alloc] initWithTarget: self
selector: @selector(_run:) selector: @selector(_run:)
object: link]; object: link];
[link release]; // Retained by thread
[link setItem: thread]; [link setItem: thread];
[thread release]; // Retained by link [thread release]; // Retained by link
[idle insert: link]; GSLinkedListInsertAfter(link, idle, idle->tail);
idle = link;
[thread start]; [thread start];
} }
else else
@ -344,16 +326,9 @@
break; // No idle thread to perform operation break; // No idle thread to perform operation
} }
} }
operations = [op remove]; GSLinkedListRemove(op, operations);
operationCount--; GSLinkedListRemove(link, idle);
if (nil == operations) GSLinkedListInsertAfter(link, live, live->tail);
{
lastOperation = nil;
}
idle = [link remove];
[live insert: link];
live = link;
activeCount++;
link->op = op; link->op = op;
[link->lock lock]; [link->lock lock];
[link->lock unlockWithCondition: 1]; [link->lock unlockWithCondition: 1];
@ -364,29 +339,9 @@
- (void) _dead: (GSThreadLink*)link - (void) _dead: (GSThreadLink*)link
{ {
[poolLock lock]; [poolLock lock];
if (nil == link->next) if (link->owner != nil)
{ {
if (link == live) GSLinkedListRemove(link, link->owner);
{
live = [link remove];
threadCount--;
}
else if (link == idle)
{
idle = [link remove];
threadCount--;
}
else
{
// Already dead ... don't change threadCount.
}
}
else
{
if (link == live) live = [link remove];
else if (link == idle) idle = [link remove];
else [link remove];
threadCount--;
} }
[poolLock unlock]; [poolLock unlock];
} }
@ -399,28 +354,17 @@
BOOL madeIdle = YES; BOOL madeIdle = YES;
[poolLock lock]; [poolLock lock];
if (link == live) if (link->owner != nil)
{ {
live = [link remove]; GSLinkedListRemove(link, link->owner);
} }
else if (link == idle) if (idle->count + live->count > maxThreads)
{ {
idle = [link remove];
}
else
{
[link remove];
}
activeCount--;
if (threadCount > maxThreads)
{
threadCount--;
madeIdle = NO; // Made dead instead madeIdle = NO; // Made dead instead
} }
else else
{ {
[idle insert: link]; GSLinkedListInsertAfter(link, idle, idle->tail);
idle = link;
} }
[poolLock unlock]; [poolLock unlock];
return madeIdle; return madeIdle;
@ -437,7 +381,7 @@
[poolLock lock]; [poolLock lock];
processed++; processed++;
if (unusedCount < maxOperations) if (unused->count < maxOperations)
{ {
if (nil != op->arg) if (nil != op->arg)
{ {
@ -445,23 +389,16 @@
op->arg = nil; op->arg = nil;
} }
[op setItem: nil]; [op setItem: nil];
[unused insert: op]; GSLinkedListInsertAfter(op, unused, unused->tail);
unused = op;
unusedCount++;
} }
else else
{ {
[op release]; [op release];
} }
link->op = operations; link->op = (GSOperation*)operations->head;
if (nil != link->op) if (nil != link->op)
{ {
operations = [operations remove]; GSLinkedListRemove(link->op, operations);
operationCount--;
if (nil == operations)
{
lastOperation = nil;
}
more = YES; more = YES;
} }
[poolLock unlock]; [poolLock unlock];