Author: rfm
Date: Sat May 16 12:31:08 2015
New Revision: 38506
URL: http://svn.gna.org/viewcvs/gnustep?rev=38506&view=rev
Log:
Expose GSIOThread, add easier customisation of FIFO, make IOThread pool a little
safer with checks for finished/cancelled thread and lock protection of count.
Modified:
libs/performance/trunk/GSFIFO.h
libs/performance/trunk/GSFIFO.m
libs/performance/trunk/GSIOThreadPool.h
libs/performance/trunk/GSIOThreadPool.m
Modified: libs/performance/trunk/GSFIFO.h
URL:
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/GSFIFO.h?rev=38506&r1=38505&r2=38506&view=diff
==============================================================================
--- libs/performance/trunk/GSFIFO.h (original)
+++ libs/performance/trunk/GSFIFO.h Sat May 16 12:31:08 2015
@@ -193,6 +193,8 @@
* The GSFIFOSingleConsumerNNN boolean is NO by default.<br />
* The GSFIFOSingleProducerNNN boolean is NO by default.<br />
* The GSFIFOBoundariesNNN array is missing by default.<br />
+ * If no default is found for the specific named FIFO, the default set
+ * for a FIFO with an empty name is used.
*/
- (id) initWithName: (NSString*)n;
Modified: libs/performance/trunk/GSFIFO.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/GSFIFO.m?rev=38506&r1=38505&r2=38506&view=diff
==============================================================================
--- libs/performance/trunk/GSFIFO.m (original)
+++ libs/performance/trunk/GSFIFO.m Sat May 16 12:31:08 2015
@@ -570,6 +570,7 @@
{
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSString *key;
+ NSInteger i;
uint16_t g;
uint16_t t;
BOOL mc;
@@ -577,19 +578,27 @@
NSArray *b;
key = [NSString stringWithFormat: @"GSFIFOCapacity%@", n];
- if ([defs integerForKey: key] > 0)
- {
- c = [defs integerForKey: key];
- }
+ if (nil == [defs objectForKey: key]) key = @"GSFIFOCapacity";
+ i = [defs integerForKey: key];
+ if (i > 0)
+ {
+ c = i;
+ }
+
key = [NSString stringWithFormat: @"GSFIFOGranularity%@", n];
+ if (nil == [defs objectForKey: key]) key = @"GSFIFOGranularity";
g = [defs integerForKey: key];
key = [NSString stringWithFormat: @"GSFIFOTimeout%@", n];
+ if (nil == [defs objectForKey: key]) key = @"GSFIFOTimeout";
t = [defs integerForKey: key];
key = [NSString stringWithFormat: @"GSFIFOSingleConsumer%@", n];
+ if (nil == [defs objectForKey: key]) key = @"GSFIFOSingleConsumer";
mc = (YES == [defs boolForKey: key]) ? NO : YES;
key = [NSString stringWithFormat: @"GSFIFOSingleProducer%@", n];
+ if (nil == [defs objectForKey: key]) key = @"GSFIFOSingleProducer";
mp = (YES == [defs boolForKey: key]) ? NO : YES;
key = [NSString stringWithFormat: @"GSFIFOBoundaries%@", n];
+ if (nil == [defs objectForKey: key]) key = @"GSFIFOBoundaries";
b = [defs arrayForKey: key];
return [self initWithCapacity: c
Modified: libs/performance/trunk/GSIOThreadPool.h
URL:
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/GSIOThreadPool.h?rev=38506&r1=38505&r2=38506&view=diff
==============================================================================
--- libs/performance/trunk/GSIOThreadPool.h (original)
+++ libs/performance/trunk/GSIOThreadPool.h Sat May 16 12:31:08 2015
@@ -23,13 +23,32 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#import <Foundation/NSObject.h>
+#import <Foundation/NSThread.h>
#if !defined (GNUSTEP) && (MAC_OS_X_VERSION_MAX_ALLOWED<=MAC_OS_X_VERSION_10_4)
typedef unsigned int NSUInteger;
#endif
-@class NSThread;
@class NSLock;
+@class NSTimer;
+
+/** This is the class for threads in the pool.<br />
+ * Each thread runs a runloop and is kept 'alive' waiting for a timer in
+ * the far future, but can be terminated earlier using the -terminate:
+ * method (which is called when the pool size is changed and the pool
+ * wishes to stop an idle thread).<br />
+ */
+@interface GSIOThread : NSThread
+{
+@private
+ NSTimer *_timer; /** Pool termination timer */
+ NSUInteger _count; /** Number of times acquired */
+}
+/** Terminates the thread by the specified date (as soon as possible if
+ * the date is nil or is in the past).
+ */
+- (void) terminate: (NSDate*)when;
+@end
/** This class provides a thread pool for performing methods which need to
* make use of a runloop for I/O and/or timers.<br />
@@ -61,7 +80,9 @@
*/
+ (GSIOThreadPool*) sharedPool;
-/** Selects a thread from the pool to be used for some job.
+/** Selects a thread from the pool to be used for some job.<br />
+ * This method selectes the least used thread in the pool (ie the
+ * one with the lowest acquire count).
*/
- (NSThread*) acquireThread;
@@ -94,7 +115,10 @@
*/
- (NSTimeInterval) timeout;
-/** Releases a thread previously selected from the pool.
+/** Releases a thread previously selected from the pool. This decreases the
+ * acquire count for the thread. If a thread has a zero acquire count, it is
+ * a candidatre for termination and removal from the pool if/when the pool
+ * has its size changed.
*/
- (void) unacquireThread: (NSThread*)aThread;
Modified: libs/performance/trunk/GSIOThreadPool.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/performance/trunk/GSIOThreadPool.m?rev=38506&r1=38505&r2=38506&view=diff
==============================================================================
--- libs/performance/trunk/GSIOThreadPool.m (original)
+++ libs/performance/trunk/GSIOThreadPool.m Sat May 16 12:31:08 2015
@@ -31,30 +31,71 @@
#import <Foundation/NSUserDefaults.h>
#import "GSIOThreadPool.h"
-@interface GSIOThread : NSThread
-{
- NSTimer *timer;
- @public
- NSUInteger count;
-}
-- (void) exit: (NSTimer*)t;
-- (void) run;
-- (void) terminate: (NSDate*)when;
+/* Protect changes to a thread's counter
+ */
+static NSLock *countLock = nil;
+
+@interface GSIOThread (Private)
+- (NSUInteger) _count;
+- (void) _finish: (NSTimer*)t;
+- (void) _run;
+- (void) _setCount: (NSUInteger)c;
@end
+@implementation GSIOThread (Private)
+
++ (void) initialize
+{
+ if (nil == countLock)
+ {
+ countLock = [NSLock new];
+ }
+}
+
+- (NSUInteger) _count
+{
+ return _count;
+}
+
+/* Force termination of this thread.
+ */
+- (void) _finish: (NSTimer*)t
+{
+ _timer = nil;
+ [NSThread exit];
+}
+
+/* Run the thread's main runloop until terminated.
+ */
+- (void) _run
+{
+ NSDate *when = [NSDate distantFuture];
+ NSTimeInterval delay = [when timeIntervalSinceNow];
+
+ _timer = [NSTimer scheduledTimerWithTimeInterval: delay
+ target: self
+ selector: @selector(_finish:)
+ userInfo: nil
+ repeats: NO];
+ [[NSRunLoop currentRunLoop] run];
+}
+
+- (void) _setCount: (NSUInteger)c
+{
+ if (NSNotFound != _count)
+ {
+ _count = c;
+ }
+}
+
+@end
+
@implementation GSIOThread
-
-/* Force termination of this thread.
- */
-- (void) exit: (NSTimer*)t
-{
- [NSThread exit];
-}
#if defined(GNUSTEP) || (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4)
- (id) init
{
- self = [super initWithTarget: self selector: @selector(run) object: nil];
+ self = [super initWithTarget: self selector: @selector(_run) object: nil];
if (nil != self)
{
[self start];
@@ -63,40 +104,38 @@
}
#endif
-/* Run the thread's main runloop until terminated.
- */
-- (void) run
-{
- NSDate *when = [NSDate distantFuture];
- NSTimeInterval delay = [when timeIntervalSinceNow];
-
- timer = [NSTimer scheduledTimerWithTimeInterval: delay
- target: self
- selector: @selector(exit:)
- userInfo: nil
- repeats: NO];
- [[NSRunLoop currentRunLoop] run];
-}
-
/* End execution of the thread by the specified date.
*/
- (void) terminate: (NSDate*)when
{
- NSTimeInterval delay = [when timeIntervalSinceNow];
-
- [timer invalidate];
+ NSTimeInterval delay = 0.0;
+
+ if ([when isKindOfClass: [NSDate class]])
+ {
+ delay = [when timeIntervalSinceNow];
+ }
+ [_timer invalidate];
+
+ [countLock lock];
+ if (0 == _count || delay <= 0.0)
+ {
+ _count = NSNotFound; // Mark as terminating
+ _timer = nil;
+ delay = 0.0;
+ }
+ [countLock unlock];
+
if (delay > 0.0)
{
- timer = [NSTimer scheduledTimerWithTimeInterval: delay
- target: self
- selector: @selector(exit:)
- userInfo: nil
- repeats: NO];
+ _timer = [NSTimer scheduledTimerWithTimeInterval: delay
+ target: self
+ selector: @selector(_finish:)
+ userInfo: nil
+ repeats: NO];
}
else
{
- timer = nil;
- [self exit: nil];
+ [self _finish: nil];
}
}
@end
@@ -119,11 +158,20 @@
{
GSIOThread *o = [a objectAtIndex: c];
- if (o->count < l)
- {
- t = o;
- l = o->count;
- }
+ if ([o isExecuting])
+ {
+ NSUInteger i;
+
+ if ((i = [o _count]) < l)
+ {
+ t = o;
+ l = i;
+ }
+ }
+ else if ([o isCancelled] || [o isFinished])
+ {
+ [a removeObjectAtIndex: c];
+ }
}
return t;
}
@@ -153,6 +201,7 @@
- (NSThread*) acquireThread
{
GSIOThread *t;
+ NSUInteger c;
[poolLock lock];
if (0 == maxThreads)
@@ -160,14 +209,17 @@
[poolLock unlock];
return [NSThread mainThread];
}
+ [countLock lock];
t = best(threads);
- if (nil == t || (t->count > 0 && [threads count] < maxThreads))
+ if (nil == t || ((c = [t _count]) > 0 && [threads count] < maxThreads))
{
t = [GSIOThread new];
[threads addObject: t];
[t release];
- }
- t->count++;
+ c = 0;
+ }
+ [t _setCount: c + 1];
+ [countLock unlock];
[poolLock unlock];
return t;
}
@@ -179,7 +231,7 @@
[poolLock lock];
if ([threads indexOfObjectIdenticalTo: aThread] != NSNotFound)
{
- count = ((GSIOThread*)aThread)->count;
+ count = [((GSIOThread*)aThread) _count];
}
[poolLock unlock];
return count;
@@ -250,15 +302,20 @@
[poolLock lock];
if ([threads indexOfObjectIdenticalTo: aThread] != NSNotFound)
{
- if (0 == ((GSIOThread*)aThread)->count)
+ NSUInteger c;
+
+ [countLock lock];
+ c = [((GSIOThread*)aThread) _count];
+ if (0 == c)
{
+ [countLock unlock];
[poolLock unlock];
[NSException raise: NSInternalInconsistencyException
format: @"-unacquireThread: called too many times"];
}
- ((GSIOThread*)aThread)->count--;
- if (0 == ((GSIOThread*)aThread)->count
- && [threads count] > maxThreads)
+ [((GSIOThread*)aThread) _setCount: --c];
+ [countLock unlock];
+ if (0 == c && [threads count] > maxThreads)
{
[aThread retain];
[threads removeObjectIdenticalTo: aThread];
_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs