Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -56,10 +56,11 @@ @public # else @private # endif of_thread_t _thread; + of_thread_attr_t _attr; enum { OF_THREAD_NOT_RUNNING, OF_THREAD_RUNNING, OF_THREAD_WAITING_FOR_JOIN } _running; @@ -77,10 +78,12 @@ # ifdef OF_HAVE_PROPERTIES # ifdef OF_HAVE_BLOCKS @property (copy) of_thread_block_t threadBlock; # endif @property (copy) OFString *name; +@property float priority; +@property size_t stackSize; # endif /*! * @brief Creates a new thread. * @@ -213,7 +216,40 @@ * @brief Sets the name for the thread. * * @param name The name for the thread */ - (void)setName: (OFString*)name; + +/*! + * @brief Returns the priority of the thread. + * + * @return The priority of the thread + */ +- (float)priority; + +/*! + * @brief Sets the priority of the thread. + * + * @note This has to be set before the thread is started! + * + * @param priority The priority for the thread, with 0.0 being the lowest and + * 1.0 the highest + */ +- (void)setPriority: (float)priority; + +/*! + * @brief Returns the stack size of the thread. + * + * @return The stack size of the thread + */ +- (size_t)stackSize; + +/*! + * @brief Sets the stack size of the thread. + * + * @note This has to be set before the thread is started! + * + * @param stackSize The stack size for the thread + */ +- (void)setStackSize: (size_t)stackSize; #endif @end Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -91,11 +91,11 @@ thread->_pool = objc_autoreleasePoolPush(); /* * Nasty workaround for thread implementations which can't return a - * value on join. + * pointer on join. */ # ifdef OF_HAVE_BLOCKS if (thread->_threadBlock != NULL) thread->_returnValue = [thread->_threadBlock() retain]; else @@ -257,15 +257,31 @@ if (!of_tlskey_set(threadSelfKey, mainThread)) @throw [OFInitializationFailedException exceptionWithClass: self]; } + +- init +{ + self = [super init]; + + @try { + if (!of_thread_attr_init(&_attr)) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} # ifdef OF_HAVE_BLOCKS - initWithThreadBlock: (of_thread_block_t)threadBlock { - self = [super init]; + self = [self init]; @try { _threadBlock = [threadBlock copy]; } @catch (id e) { [self release]; @@ -306,11 +322,11 @@ [self retain]; _running = OF_THREAD_RUNNING; - if (!of_thread_new(&_thread, callMain, self)) { + if (!of_thread_new(&_thread, callMain, self, &_attr)) { [self release]; @throw [OFThreadStartFailedException exceptionWithThread: self]; } if (_name != nil) @@ -368,10 +384,38 @@ else of_thread_set_name(_thread, class_getName([self class])); } } + +- (float)priority +{ + return _attr.priority; +} + +- (void)setPriority: (float)priority +{ + if (_running == OF_THREAD_RUNNING) + @throw [OFThreadStillRunningException + exceptionWithThread: self]; + + _attr.priority = priority; +} + +- (size_t)stackSize +{ + return _attr.stackSize; +} + +- (void)setStackSize: (size_t)stackSize +{ + if (_running == OF_THREAD_RUNNING) + @throw [OFThreadStillRunningException + exceptionWithThread: self]; + + _attr.stackSize = stackSize; +} - (void)dealloc { if (_running == OF_THREAD_RUNNING) @throw [OFThreadStillRunningException Index: src/threading.h ================================================================== --- src/threading.h +++ src/threading.h @@ -25,10 +25,11 @@ #import "OFObject.h" #if defined(OF_HAVE_PTHREADS) # include +# include typedef pthread_t of_thread_t; typedef pthread_key_t of_tlskey_t; typedef pthread_mutex_t of_mutex_t; typedef pthread_cond_t of_condition_t; typedef pthread_once_t of_once_t; @@ -63,19 +64,28 @@ #elif defined(OF_HAVE_PTHREAD_SPINLOCKS) typedef pthread_spinlock_t of_spinlock_t; #else typedef of_mutex_t of_spinlock_t; #endif + +#ifdef OF_HAVE_SCHED_YIELD +# include +#endif #ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES # define of_rmutex_t of_mutex_t #else typedef struct { of_mutex_t mutex; of_tlskey_t count; } of_rmutex_t; #endif + +typedef struct of_thread_attr_t { + float priority; + size_t stackSize; +} of_thread_attr_t; #if defined(OF_HAVE_PTHREADS) # define of_thread_is_current(t) pthread_equal(t, pthread_self()) # define of_thread_current pthread_self #elif defined(_WIN32) @@ -84,11 +94,13 @@ #else # error of_thread_is_current not implemented! # error of_thread_current not implemented! #endif -extern bool of_thread_new(of_thread_t *thread, id (*function)(id), id data); +extern bool of_thread_attr_init(of_thread_attr_t *attr); +extern bool of_thread_new(of_thread_t *thread, id (*function)(id), id data, + const of_thread_attr_t *attr); extern void of_thread_set_name(of_thread_t thread, const char *name); extern bool of_thread_join(of_thread_t thread); extern bool of_thread_detach(of_thread_t thread); extern void OF_NO_RETURN of_thread_exit(void); extern void of_once(of_once_t *control, void (*func)(void)); Index: src/threading.m ================================================================== --- src/threading.m +++ src/threading.m @@ -11,10 +11,12 @@ * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ + +#include "config.h" #import "threading.h" #if defined(OF_HAVE_PTHREADS) # include "threading_pthread.m" Index: src/threading_pthread.m ================================================================== --- src/threading_pthread.m +++ src/threading_pthread.m @@ -12,17 +12,86 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#import "threading.h" +bool +of_thread_attr_init(of_thread_attr_t *attr) +{ + pthread_attr_t pattr; + + if (pthread_attr_init(&pattr) != 0) + return false; + + @try { + int policy, minPrio, maxPrio; + struct sched_param param; + + if (pthread_attr_getschedpolicy(&pattr, &policy) != 0) + return false; + + minPrio = sched_get_priority_min(policy); + maxPrio = sched_get_priority_max(policy); + + if (pthread_attr_getschedparam(&pattr, ¶m) != 0) + return false; + + attr->priority = (float)(param.sched_priority - minPrio) / + (maxPrio - minPrio); + + if (pthread_attr_getstacksize(&pattr, &attr->stackSize) != 0) + return false; + + return true; + } @finally { + pthread_attr_destroy(&pattr); + } +} bool -of_thread_new(of_thread_t *thread, id (*function)(id), id data) +of_thread_new(of_thread_t *thread, id (*function)(id), id data, + const of_thread_attr_t *attr) { - return (pthread_create(thread, NULL, (void*(*)(void*))function, - (__bridge void*)data) == 0); + pthread_attr_t pattr; + + if (pthread_attr_init(&pattr) != 0) + return false; + + @try { + if (attr != NULL) { + int policy, minPrio, maxPrio; + struct sched_param param; + + if (attr->priority < 0 || attr->priority > 1) + return false; + + if (pthread_attr_getschedpolicy(&pattr, &policy) != 0) + return false; + + minPrio = sched_get_priority_min(policy); + maxPrio = sched_get_priority_max(policy); + + param.sched_priority = (float)minPrio + + attr->priority * (maxPrio - minPrio); + + if (pthread_attr_setinheritsched(&pattr, + PTHREAD_EXPLICIT_SCHED) != 0) + return false; + + if (pthread_attr_setschedparam(&pattr, ¶m) != 0) + return false; + + if (pthread_attr_setstacksize(&pattr, + attr->stackSize) != 0) + return false; + } + + return (pthread_create(thread, &pattr, + (void*(*)(void*))function, (__bridge void*)data) == 0); + } @finally { + pthread_attr_destroy(&pattr); + } } bool of_thread_join(of_thread_t thread) { Index: src/threading_winapi.m ================================================================== --- src/threading_winapi.m +++ src/threading_winapi.m @@ -12,19 +12,47 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#import "threading.h" +bool +of_thread_attr_init(of_thread_attr_t *attr) +{ + attr->priority = + (float)(THREAD_PRIORITY_NORMAL - THREAD_PRIORITY_LOWEST) / + (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_LOWEST); + attr->stackSize = 0; + + return true; +} bool -of_thread_new(of_thread_t *thread, id (*function)(id), id data) +of_thread_new(of_thread_t *thread, id (*function)(id), id data, + const of_thread_attr_t *attr) { - *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)function, - (__bridge void*)data, 0, NULL); + size_t stackSize = 0; + int priority = 0; + + if (attr != NULL) { + if (attr->priority < 0 || attr->priority > 1) + return false; + + priority = THREAD_PRIORITY_LOWEST + attr->priority * + (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_LOWEST); + stackSize = attr->stackSize; + } + + *thread = CreateThread(NULL, stackSize, + (LPTHREAD_START_ROUTINE)function, (__bridge void*)data, 0, NULL); + + if (thread == NULL) + return false; - return (thread != NULL); + if (priority > 0) + return SetThreadPriority(*thread, priority); + else + return true; } bool of_thread_join(of_thread_t thread) {