Turned OOTextureLoadDispatcher into more general OOAsyncWorkManager.

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@2536 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2009-09-19 21:47:05 +00:00
parent 61055c0583
commit ab8aebe696
6 changed files with 109 additions and 503 deletions

View File

@ -553,6 +553,8 @@
1AB812900E90179D00A84923 /* TextureStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 25161134099544390037C2E1 /* TextureStore.h */; };
1AB813090E90D8E500A84923 /* OOLogOutputHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AB813070E90D8E500A84923 /* OOLogOutputHandler.m */; };
1AB8130A0E90D8E500A84923 /* OOLogOutputHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AB813080E90D8E500A84923 /* OOLogOutputHandler.h */; };
1AB987B61065842700AF9B0A /* OOAsyncWorkManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1AB987B41065842700AF9B0A /* OOAsyncWorkManager.h */; };
1AB987B71065842700AF9B0A /* OOAsyncWorkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AB987B51065842700AF9B0A /* OOAsyncWorkManager.m */; };
1ABAD7310F350B3400FD2CBF /* OOShipGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ABAD72F0F350B3400FD2CBF /* OOShipGroup.m */; };
1ABAD7320F350B3400FD2CBF /* OOShipGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ABAD7300F350B3400FD2CBF /* OOShipGroup.h */; };
1ABB688C0D044306008BE96D /* OOLoggingExtended.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ABB688B0D044306008BE96D /* OOLoggingExtended.h */; };
@ -1627,6 +1629,8 @@
1AB784F80D554F7B00517983 /* OOJSSoundSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOJSSoundSource.m; sourceTree = "<group>"; };
1AB813070E90D8E500A84923 /* OOLogOutputHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOLogOutputHandler.m; sourceTree = "<group>"; };
1AB813080E90D8E500A84923 /* OOLogOutputHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOLogOutputHandler.h; sourceTree = "<group>"; };
1AB987B41065842700AF9B0A /* OOAsyncWorkManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OOAsyncWorkManager.h; path = Materials/OOAsyncWorkManager.h; sourceTree = "<group>"; };
1AB987B51065842700AF9B0A /* OOAsyncWorkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OOAsyncWorkManager.m; path = Materials/OOAsyncWorkManager.m; sourceTree = "<group>"; };
1ABAD72F0F350B3400FD2CBF /* OOShipGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOShipGroup.m; sourceTree = "<group>"; };
1ABAD7300F350B3400FD2CBF /* OOShipGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOShipGroup.h; sourceTree = "<group>"; };
1ABB688B0D044306008BE96D /* OOLoggingExtended.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOLoggingExtended.h; sourceTree = "<group>"; };
@ -2508,8 +2512,6 @@
1A8A3BFB0B963F91007D20B8 /* Utilities */ = {
isa = PBXGroup;
children = (
1A3BA257106555D100C5C6F3 /* NSNumberOOExtensions.h */,
1A3BA258106555D100C5C6F3 /* NSNumberOOExtensions.m */,
1ABAD7300F350B3400FD2CBF /* OOShipGroup.h */,
1ABAD72F0F350B3400FD2CBF /* OOShipGroup.m */,
1A20F7040F36EE0500156DE9 /* OOExcludeObjectEnumerator.h */,
@ -2524,6 +2526,8 @@
1A047A440DCA0F4F00EE1CD0 /* NSDictionaryOOExtensions.m */,
1A8A37550B960337007D20B8 /* NSMutableDictionaryOOExtensions.h */,
1A8A37540B960337007D20B8 /* NSMutableDictionaryOOExtensions.m */,
1A3BA257106555D100C5C6F3 /* NSNumberOOExtensions.h */,
1A3BA258106555D100C5C6F3 /* NSNumberOOExtensions.m */,
1A8A394D0B96229C007D20B8 /* NSFileManagerOOExtensions.h */,
1A8A394C0B96229C007D20B8 /* NSFileManagerOOExtensions.m */,
1A8A3A360B962AEF007D20B8 /* NSScannerOOExtensions.h */,
@ -2551,6 +2555,8 @@
1A2A8E020BC67CCC001E00FB /* OOWeakReference.m */,
1A2A17D40BD1587D00152975 /* OOCPUInfo.h */,
1A2A17D50BD1587D00152975 /* OOCPUInfo.m */,
1AB987B41065842700AF9B0A /* OOAsyncWorkManager.h */,
1AB987B51065842700AF9B0A /* OOAsyncWorkManager.m */,
1A7D83380C40147700E4A5F5 /* OOAsyncQueue.h */,
1A7D83390C40147700E4A5F5 /* OOAsyncQueue.m */,
1A6B1F340C9AAA60000717CF /* OOPriorityQueue.m */,
@ -3058,6 +3064,7 @@
1A11273B105994D000DF9D12 /* OOExhaustPlumeEntity.h in Headers */,
1A1F2842105AAB7900ADB8C5 /* OOSparkEntity.h in Headers */,
1A3BA259106555D100C5C6F3 /* NSNumberOOExtensions.h in Headers */,
1AB987B61065842700AF9B0A /* OOAsyncWorkManager.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -3403,6 +3410,7 @@
1A11273C105994D000DF9D12 /* OOExhaustPlumeEntity.m in Sources */,
1A1F2843105AAB7900ADB8C5 /* OOSparkEntity.m in Sources */,
1A3BA25A106555D100C5C6F3 /* NSNumberOOExtensions.m in Sources */,
1AB987B71065842700AF9B0A /* OOAsyncWorkManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -27,9 +27,11 @@ SOFTWARE.
*/
@class OOAsyncQueue;
#import "OOCocoa.h"
@class OOAsyncQueue;
@protocol OOAsyncWorkTask;
@ -59,7 +61,7 @@ typedef enum
@end
@protocol OOAsyncWorkTask
@protocol OOAsyncWorkTask <NSObject>
// Called on a worker thread. There may be multiple worker threads.
- (void) performAsyncTask;

View File

@ -25,15 +25,24 @@ SOFTWARE.
*/
#import "OOTextureLoadDispatcher.h"
#import "OOAsyncWorkManager.h"
#import "OOAsyncQueue.h"
#import "OOCPUInfo.h"
#import "OOCollectionExtractors.h"
#import "NSThreadOOExtensions.h"
#import "OONSOperation.h"
#import <pthread.h>
static OOTextureLoadDispatcher *sSingleton = nil;
static OOAsyncWorkManager *sSingleton = nil;
@interface NSThread (MethodsThatMayExistDependingOnSystem)
- (BOOL) isMainThread;
+ (BOOL) isMainThread;
@end
/* OOAsyncWorkManagerInternal: shared superclass of our two implementations,
@ -43,10 +52,19 @@ static OOTextureLoadDispatcher *sSingleton = nil;
{
@private
OOAsyncQueue *_readyQueue;
#if OO_DEBUG
NSMutableSet *_pendingCompletableOperations;
NSLock *_pendingOpsLock;
#endif
}
- (void) queueResult:(id<OOAsyncWorkTask>)task;
#if OO_DEBUG
- (void) noteTaskQueued:(id<OOAsyncWorkTask>)task;
#endif
@end
@ -64,11 +82,6 @@ static OOTextureLoadDispatcher *sSingleton = nil;
@interface OOOperationQueueAsyncWorkManager: OOAsyncWorkManagerInternal
{
OONSOperationQueue _operationQueue;
#if OO_DEBUG
NSMutableSet *_pendingCompletableOperations;
NSLock *_pendingOpsLock;
#endif
}
#if !OO_HAVE_NSOPERATION
@ -78,7 +91,7 @@ static OOTextureLoadDispatcher *sSingleton = nil;
@end
static void InitAsyncWorkManager
static void InitAsyncWorkManager(void)
{
NSCAssert(sSingleton == nil, @"Async Work Manager singleton not nil in one-time init");
@ -131,6 +144,7 @@ static void InitAsyncWorkManager
- (void) dealloc
{
abort();
[super dealloc];
}
@ -180,6 +194,17 @@ static void InitAsyncWorkManager
[self release];
return nil;
}
#if OO_DEBUG
_pendingCompletableOperations = [[NSMutableSet alloc] init];
_pendingOpsLock = [[NSLock alloc] init];
if (_pendingOpsLock == nil)
{
[self release];
return nil;
}
#endif
}
return self;
@ -188,16 +213,27 @@ static void InitAsyncWorkManager
- (void) waitForTaskToComplete:(id<OOAsyncWorkTask>)task
{
OOTextureLoader *next = nil;
#if OO_DEBUG
NSParameterAssert([(id)task respondsToSelector:@selector(completeAsyncTask)]);
NSAssert1(![NSThread respondsToSelector:@selector(isMainThread)] || [[NSThread self] isMainThread], @"%s can only be called from the main thread.", __FUNCTION__);
NSParameterAssert([task respondsToSelector:@selector(completeAsyncTask)]);
NSAssert(![NSThread respondsToSelector:@selector(isMainThread)] || [NSThread isMainThread], @"%s can only be called from the main thread.", __FUNCTION__);
[_pendingOpsLock lock];
BOOL exists = [_pendingCompletableOperations containsObject:task];
if (exists) [_pendingCompletableOperations removeObject:task];
[_pendingOpsLock unlock];
if (!exists)
{
[NSException raise:NSInternalInconsistencyException format:@"%s: attempt to wait for a task that has not been queued.", __FUNCTION__];
}
#endif
id next = nil;
do
{
// Dequeue a task and complete it.
next = [_readyQueue dequeue];
[(id)next completeAsyncTask];
[next completeAsyncTask];
} while (next != task); // We don't control order, so keep looking until we get the one we care about.
}
@ -211,11 +247,21 @@ static void InitAsyncWorkManager
}
}
#if OO_DEBUG
- (void) noteTaskQueued:(id<OOAsyncWorkTask>)task
{
[_pendingOpsLock lock];
[_pendingCompletableOperations addObject:task];
[_pendingOpsLock unlock];
}
#endif
@end
/******* OOTextureLoadManualDispatcher - manual thread management *******/
/******* OOManualDispatchAsyncWorkManager - manual thread management *******/
enum
{
@ -224,7 +270,7 @@ enum
#if !OO_HAVE_NSOPERATION
@implementation OOTextureLoadManualDispatcher
@implementation OOManualDispatchAsyncWorkManager
- (id) init
{
@ -236,17 +282,10 @@ enum
_taskQueue = [[OOAsyncQueue alloc] init];
if (_taskQueue == nil)
{
// Must necessarily leak, as superclass is un-deletable. If we get here, we're probably crashing anyway.
[self release];
return nil;
}
#if OO_DEBUG
_pendingCompletableOperations = [[NSMutableSet alloc] init];
_pendingOpsLock = [[NSLock alloc] init];
if (_pendingOpsLock == nil) return nil;
#endif
// Set up loading threads.
OOUInteger threadCount, threadNumber = 1;
#if OO_DEBUG
@ -268,38 +307,19 @@ enum
- (BOOL) addTask:(id<OOAsyncWorkTask>)task priority:(OOAsyncWorkPriority)priority
{
if (EXPECT_NOT(task == nil)) return NO;
#if OO_DEBUG
[_pendingOpsLock lock];
[_pendingCompletableOperations addObject:task];
[_pendingOpsLock unlock];
[super noteTaskQueued:task];
#endif
return [_taskQueue enqueue:loader];
// Priority is ignored.
return [_taskQueue enqueue:task];
}
#if OO_DEBUG
- (void) waitForTaskToComplete:(id<OOAsyncWorkTask>)task
{
[_pendingOpsLock lock];
BOOL exists = [_pendingCompletableOperations containsObject:task];
if (exists) [_pendingCompletableOperations removeObject:task];
[_pendingOpsLock unlock];
if (!exists)
{
[NSException raise:NSInternalInconsistencyException format:@"%s: attempt to wait for a task that has not been queued.", __FUNCTION__];
}
[super waitForLoaderToComplete:task];
}
#endif
- (void) queueTask:(NSNumber *)threadNumber
{
NSAutoreleasePool *rootPool = nil, *pool = nil;
id<OOAsyncWorkTask> task = nil;
rootPool = [[NSAutoreleasePool alloc] init];
@ -315,7 +335,7 @@ enum
[task performAsyncTask];
NS_HANDLER
NS_ENDHANDLER
[self queueResult:loader];
[self queueResult:task];
[pool release];
}
@ -327,10 +347,10 @@ enum
#endif
/******* OOTextureLoadOperationQueueDispatcher - dispatch through NSOperationQueue if available *******/
/******* OOOperationQueueAsyncWorkManager - dispatch through NSOperationQueue if available *******/
@implementation OOTextureLoadOperationQueueDispatcher
@implementation OOOperationQueueAsyncWorkManager
#if !OO_HAVE_NSOPERATION
+ (BOOL) canBeUsed
@ -366,24 +386,33 @@ enum
}
- (BOOL) dispatchLoader:(OOTextureLoader *)loader
- (BOOL) addTask:(id<OOAsyncWorkTask>)task priority:(OOAsyncWorkPriority)priority
{
id operation = [[OONSInvocationOperationClass() alloc] initWithTarget:self selector:@selector(performLoadOperation:) object:loader];
if (EXPECT_NOT(task == nil)) return NO;
id operation = [[OONSInvocationOperationClass() alloc] initWithTarget:self selector:@selector(dispatchTask:) object:task];
if (operation == nil) return NO;
if (priority == kOOAsyncPriorityLow) [operation setQueuePriority:OONSOperationQueuePriorityLow];
else if (priority == kOOAsyncPriorityHigh) [operation setQueuePriority:OONSOperationQueuePriorityHigh];
[_operationQueue addOperation:operation];
[operation release];
#if OO_DEBUG
[super noteTaskQueued:task];
#endif
return YES;
}
- (void) performLoadOperation:(OOTextureLoader *) loader
- (void) dispatchTask:(id<OOAsyncWorkTask>)task
{
NS_DURING
[loader performLoad];
[task performAsyncTask];
NS_HANDLER
NS_ENDHANDLER
[self queueResult:loader];
[self queueResult:task];
}
@end

View File

@ -1,79 +0,0 @@
/*
OOTextureLoadDispatcher.h
Manages dispatch of OOTextureLoaders. This is a class cluster; there are
different implementations for different platform capabilities.
OOTextureLoadDispatcher's public interface is not thread-safe; it is assumed
it will only be used from the main thread.
Oolite
Copyright (C) 2004-2009 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
This file may also be distributed under the MIT/X11 license:
Copyright (C) 2007-2009 Jens Ayton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#import "OOTextureLoader.h"
@class OOAsyncQueue;
@interface OOTextureLoadDispatcher: NSObject
{
@private
OOAsyncQueue *_readyQueue;
}
+ (id) sharedTextureLoadDispatcher;
- (BOOL) dispatchLoader:(OOTextureLoader *)loader;
- (void) waitForLoaderToComplete:(OOTextureLoader *)loader;
@end
@interface OOTextureLoader (DispatchInternal)
- (void) performLoad;
- (void) markAsReady;
@end

View File

@ -1,354 +0,0 @@
/*
OOTextureLoadDispatcher.h
Oolite
Copyright (C) 2004-2009 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
This file may also be distributed under the MIT/X11 license:
Copyright (C) 2007-2009 Jens Ayton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#import "OOTextureLoadDispatcher.h"
#import "OOAsyncQueue.h"
#import "OOCPUInfo.h"
#import "OOCollectionExtractors.h"
#import "NSThreadOOExtensions.h"
#import "OONSOperation.h"
static OOTextureLoadDispatcher *sSingleton = nil;
@interface OOTextureLoadDispatcher (Internal)
- (void) queueResult:(OOTextureLoader *)loader;
@end
#if !OO_HAVE_NSOPERATION
@interface OOTextureLoadManualDispatcher: OOTextureLoadDispatcher
{
@private
OOAsyncQueue *_loadQueue;
BOOL _haveInited;
}
@end
#endif
@interface OOTextureLoadOperationQueueDispatcher: OOTextureLoadDispatcher
{
id _operationQueue;
}
#if !OO_HAVE_NSOPERATION
+ (BOOL) canBeUsed;
#endif
@end
@implementation OOTextureLoadDispatcher
+ (id) sharedTextureLoadDispatcher
{
if (sSingleton == nil)
{
#if !OO_HAVE_NSOPERATION
if ([OOTextureLoadOperationQueueDispatcher canBeUsed])
{
sSingleton = [[OOTextureLoadOperationQueueDispatcher alloc] init];
}
if (sSingleton == nil)
{
sSingleton = [[OOTextureLoadManualDispatcher alloc] init];
}
#else
sSingleton = [[OOTextureLoadOperationQueueDispatcher alloc] init];
#endif
if (sSingleton == nil)
{
OOLog(@"textureLoader.setUpDispatcher.failed", @"***** FATAL ERROR: could not set up texture load dispatcher!");
exit(EXIT_FAILURE);
}
OOLog(@"textureLoader.dispatchMethod", @"Selected texture load dispatcher: %@", [sSingleton class]);
}
return sSingleton;
}
+ (id) allocWithZone:(NSZone *)zone
{
if (sSingleton != nil) return [sSingleton retain];
return [super allocWithZone:zone];
}
- (id) init
{
if ((self = [super init]))
{
_readyQueue = [[OOAsyncQueue alloc] init];
if (_readyQueue == nil)
{
[self release];
return nil;
}
}
return self;
}
- (void) dealloc
{
if (self == sSingleton) sSingleton = nil;
[_readyQueue release];
[super dealloc];
}
- (BOOL) dispatchLoader:(OOTextureLoader *)loader
{
OOLogGenericSubclassResponsibility();
return NO;
}
/* In order for a texture loader to be considered loaded, it must be pulled
off the "ready queue". Since the order of items in the ready queue is not
necessarily (or generally) the order in which they're used, we keep pulling
texture loaders off and marking them as loaded until we get the one we're
looking for. If the loading isn't actually completed, we'll stall on the
dequeue operation until one of the loader threads pushes a loader.
*/
- (void) waitForLoaderToComplete:(OOTextureLoader *)target
{
OOTextureLoader *next = nil;
do
{
// Dequeue a loader and mark it as done.
next = [_readyQueue dequeue];
[next markAsReady];
} while (next != target); // We don't control order, so keep looking until we get the one we care about.
}
- (void) queueResult:(OOTextureLoader *)loader
{
[_readyQueue enqueue:loader];
}
@end
/******* OOTextureLoadManualDispatcher - manual thread management *******/
enum
{
kMaxWorkThreads = 4U
};
#if !OO_HAVE_NSOPERATION
@implementation OOTextureLoadManualDispatcher
- (id) init
{
if (_haveInited) return self; // Might reinit if alloc returns existing instance.
if ((self = [super init]))
{
// Set up work queues.
_loadQueue = [[OOAsyncQueue alloc] init];
if (_loadQueue == nil)
{
[self release];
return nil;
}
// Set up loading threads.
OOUInteger threadCount, threadNumber = 1;
#if OO_DEBUG
threadCount = kMaxWorkThreads;
#else
threadCount = MIN(OOCPUCount(), (unsigned)kMaxWorkThreads);
#endif
do
{
[NSThread detachNewThreadSelector:@selector(queueTask:) toTarget:self withObject:[NSNumber numberWithInt:threadNumber++]];
} while (--threadCount > 0);
_haveInited = YES;
}
return self;
}
- (void) dealloc
{
[_loadQueue release];
[super dealloc];
}
- (BOOL) dispatchLoader:(OOTextureLoader *)loader
{
return [_loadQueue enqueue:loader];
}
- (void) queueTask:(NSNumber *)threadNumber
{
NSAutoreleasePool *rootPool = nil, *pool = nil;
OOTextureLoader *loader = nil;
rootPool = [[NSAutoreleasePool alloc] init];
[[self retain] autorelease];
/* Lower thread priority so the loader doesn't go "Hey! This thread's
just woken up, let's give it exclusive use of the CPU for a second or
five!", thus stopping graphics from happening, which is somewhat
against the point.
This leads to priority inversion when the main thread blocks for
texture load completion. I'm assuming people aren't going to be
running other CPU-hogging tasks at the same time as Oolite, so it
won't be a problem.
-- Ahruman
*/
[NSThread setThreadPriority:0.5];
[NSThread ooSetCurrentThreadName:[NSString stringWithFormat:@"OOTextureLoader loader thread %@", threadNumber]];
for (;;)
{
pool = [[NSAutoreleasePool alloc] init];
loader = [_loadQueue dequeue];
NS_DURING
[loader performLoad];
NS_HANDLER
NS_ENDHANDLER
[self queueResult:loader];
[pool release];
}
[rootPool release];
}
@end
#endif
/******* OOTextureLoadOperationQueueDispatcher - dispatch through NSOperationQueue if available *******/
@implementation OOTextureLoadOperationQueueDispatcher
#if !OO_HAVE_NSOPERATION
+ (BOOL) canBeUsed
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"disable-operation-queue-texture-loader"]) return NO;
return [OONSInvocationOperationClass() class] != Nil;
}
#endif
- (id) init
{
if ((self = [super init]))
{
_operationQueue = [[OONSOperationQueueClass() alloc] init];
if (_operationQueue == nil)
{
[self release];
return nil;
}
}
return self;
}
- (void) dealloc
{
[_operationQueue release];
[super dealloc];
}
- (BOOL) dispatchLoader:(OOTextureLoader *)loader
{
id operation = [[OONSInvocationOperationClass() alloc] initWithTarget:self selector:@selector(performLoadOperation:) object:loader];
if (operation == nil) return NO;
[_operationQueue addOperation:operation];
[operation release];
return YES;
}
- (void) performLoadOperation:(OOTextureLoader *) loader
{
NS_DURING
[loader performLoad];
NS_HANDLER
NS_ENDHANDLER
[self queueResult:loader];
}
@end

View File

@ -53,7 +53,7 @@ SOFTWARE.
#import "Universe.h"
#import "OOTextureScaling.h"
#import <stdlib.h>
#import "OOTextureLoadDispatcher.h"
#import "OOAsyncWorkManager.h"
static unsigned sGLMaxSize;
@ -70,7 +70,7 @@ static BOOL sHaveSetUp = NO;
@end
@interface OOTextureLoader (OOTextureLoadingThread)
@interface OOTextureLoader (OOAsyncWorkTask) <OOAsyncWorkTask>
- (void)applySettings;
- (void)getDesiredWidth:(uint32_t *)outDesiredWidth andHeight:(uint32_t *)outDesiredHeight;
@ -105,7 +105,7 @@ static BOOL sHaveSetUp = NO;
if (result != nil)
{
if (![[OOTextureLoadDispatcher sharedTextureLoadDispatcher] dispatchLoader:result]) result = nil;
if (![[OOAsyncWorkManager sharedAsyncWorkManager] addTask:result priority:kOOAsyncPriorityMedium]) result = nil;
}
return result;
@ -180,12 +180,6 @@ static BOOL sHaveSetUp = NO;
}
- (void) markAsReady
{
ready = YES;
}
- (BOOL)getResult:(void **)outData
format:(OOTextureDataFormat *)outFormat
width:(uint32_t *)outWidth
@ -193,7 +187,7 @@ static BOOL sHaveSetUp = NO;
{
if (!ready)
{
[[OOTextureLoadDispatcher sharedTextureLoadDispatcher] waitForLoaderToComplete:self];
[[OOAsyncWorkManager sharedAsyncWorkManager] waitForTaskToComplete:self];
}
if (data != NULL)
@ -249,9 +243,9 @@ static BOOL sHaveSetUp = NO;
/*** Methods performed on the loader thread. ***/
@implementation OOTextureLoader (OOTextureLoadingThread)
@implementation OOTextureLoader (OOAsyncWorkTask)
- (void)performLoad
- (void)performAsyncTask
{
NS_DURING
OOLog(@"textureLoader.asyncLoad", @"Loading texture %@", [path lastPathComponent]);
@ -369,4 +363,10 @@ static BOOL sHaveSetUp = NO;
if (outDesiredHeight != NULL) *outDesiredHeight = desiredHeight;
}
- (void) completeAsyncTask
{
ready = YES;
}
@end