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:
parent
61055c0583
commit
ab8aebe696
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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 OO_DEBUG
|
||||
[_pendingOpsLock lock];
|
||||
[_pendingCompletableOperations addObject:task];
|
||||
[_pendingOpsLock unlock];
|
||||
#endif
|
||||
|
||||
return [_taskQueue enqueue:loader];
|
||||
}
|
||||
|
||||
if (EXPECT_NOT(task == nil)) return NO;
|
||||
|
||||
#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];
|
||||
}
|
||||
[super noteTaskQueued:task];
|
||||
#endif
|
||||
// Priority is ignored.
|
||||
return [_taskQueue enqueue:task];
|
||||
}
|
||||
|
||||
|
||||
- (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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user