/*- * Copyright 2005-2007 Guram Dukashvili * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //--------------------------------------------------------------------------- #ifndef _thread_H_ #define _thread_H_ //--------------------------------------------------------------------------- namespace ksys { //--------------------------------------------------------------------------- #ifndef PTHREAD_STACK_MIN #if defined(__WIN32__) || defined(__WIN64__) #define PTHREAD_STACK_MIN getpagesize() #else #define PTHREAD_STACK_MIN getpagesize() #endif #endif //--------------------------------------------------------------------------- #if !defined(__WIN32__) && !defined(__WIN64__) /*#ifndef PTHREAD_DEFAULT_PRIORITY #if __FreeBSD__ #define PTHREAD_DEFAULT_PRIORITY 15 #else #define PTHREAD_DEFAULT_PRIORITY 0 #endif #endif #ifndef PTHREAD_MIN_PRIORITY #if __FreeBSD__ #define PTHREAD_MIN_PRIORITY 0 #else #define PTHREAD_MIN_PRIORITY 0 #endif #endif #ifndef PTHREAD_MAX_PRIORITY #if __FreeBSD__ #define PTHREAD_MAX_PRIORITY 31 #else #define PTHREAD_MAX_PRIORITY 0 #endif #endif #ifndef PTHREAD_RT_PRIORITY #if __FreeBSD__ #define PTHREAD_RT_PRIORITY 64 #else #define PTHREAD_RT_PRIORITY 0 #endif #endif*/ int schedGetPriorityMin(); int schedGetPriorityMax(); #define THREAD_PRIORITY_QUANT ((schedGetPriorityMin() + schedGetPriorityMax() + 1) / 7.) #define THREAD_PRIORITY_IDLE schedGetPriorityMin() #define THREAD_PRIORITY_LOWEST (THREAD_PRIORITY_IDLE + int(THREAD_PRIORITY_QUANT)) #define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_IDLE + int(THREAD_PRIORITY_QUANT * 2)) #define THREAD_PRIORITY_NORMAL ((schedGetPriorityMin() + schedGetPriorityMax() + 1) / 2) #define THREAD_PRIORITY_TIME_CRITICAL schedGetPriorityMax() #define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_TIME_CRITICAL - int(THREAD_PRIORITY_QUANT * 2)) #define THREAD_PRIORITY_HIGHEST (THREAD_PRIORITY_TIME_CRITICAL - int(THREAD_PRIORITY_QUANT)) #endif //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- class Thread : virtual public Object { friend void initialize(int,char **); friend void cleanup(); public: virtual ~Thread(); Thread(); #if defined(__WIN32__) || defined(__WIN64__) static uintptr_t waitForSignal(uintptr_t mId = WM_QUIT); #else static uintptr_t waitForSignal(uintptr_t sId = 0); #endif Thread & resume(); Thread & suspend(); static bool isSuspended(uintptr_t tid); bool isSuspended() const; Thread & wait(); uintptr_t id() const; const intptr_t & exitCode() const; bool active() const; volatile const bool & started() const; Thread & terminate(); volatile const bool & terminated() const; volatile const bool & finished() const; Thread & stackSize(uintptr_t newStackSize); const uintptr_t & stackSize() const; Thread & priority(uintptr_t pri,bool noThrow = true); uintptr_t priority() const; class Action { public: ~Action(); Action(void * handler = NULL, void * data = NULL); void * const & handler() const; void * const & data() const; bool operator == (const Action & action) const; protected: private: void * handler_; void * data_; }; static Array & beforeExecuteActions(); static Array & afterExecuteActions(); virtual void threadExecute() {} protected: void afterConstruction(); void beforeDestruction() { wait(); } virtual void threadBeforeWait() {} virtual void threadAfterWait() {} uintptr_t stackSize_; #if defined(__WIN32__) || defined(__WIN64__) HANDLE handle_; DWORD id_; #else pthread_t handle_; //pthread_mutex_t mutex_; #endif intptr_t exitCode_; volatile bool started_; volatile bool terminated_; volatile bool finished_; private: static uint8_t beforeExecuteActions_[]; static uint8_t afterExecuteActions_[]; #if defined(__WIN32__) || defined(__WIN64__) static DWORD WINAPI threadFunc(LPVOID thread); #else static void * threadFunc(void * thread); #endif Thread(const Thread &); void operator = (const Thread &); static void initialize(); static void cleanup(); }; //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- inline Thread::Action::~Action() { } //--------------------------------------------------------------------------- inline Thread::Action::Action(void * handler, void * data) : handler_(handler), data_(data) { } //--------------------------------------------------------------------------- inline void * const & Thread::Action::handler() const { return handler_; } //--------------------------------------------------------------------------- inline void * const & Thread::Action::data() const { return data_; } //--------------------------------------------------------------------------- inline bool Thread::Action::operator ==(const Action & action) const { return handler_ == action.handler_ && data_ == action.data_; } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- inline Thread::~Thread() { } //--------------------------------------------------------------------------- inline bool Thread::isSuspended() const { #if defined(__WIN32__) || defined(__WIN64__) return isSuspended(id_); #else return false; #endif } //--------------------------------------------------------------------------- inline uintptr_t Thread::id() const { #if defined(__WIN32__) || defined(__WIN64__) return id_; #else return (uintptr_t) handle_; #endif } //--------------------------------------------------------------------------- inline const intptr_t & Thread::exitCode() const { return exitCode_; } //--------------------------------------------------------------------------- inline bool Thread::active() const { #if defined(__WIN32__) || defined(__WIN64__) DWORD exitCode; return (GetExitCodeThread(handle_,&exitCode) != 0 && exitCode == STILL_ACTIVE) || (started_ && !finished_) ; #else return started_ && !finished_; #endif } //--------------------------------------------------------------------------- inline volatile const bool & Thread::started() const { return started_; } //--------------------------------------------------------------------------- inline Thread & Thread::terminate() { terminated_ = true; return *this; } //--------------------------------------------------------------------------- inline volatile const bool & Thread::terminated() const { return terminated_; } //--------------------------------------------------------------------------- inline volatile const bool & Thread::finished() const { return finished_; } //--------------------------------------------------------------------------- inline Thread & Thread::stackSize(uintptr_t newStackSize) { #if HAVE_PTHREAD_H if( newStackSize < PTHREAD_STACK_MIN ) newStackSize = PTHREAD_STACK_MIN; #endif stackSize_ = newStackSize; return *this; } //--------------------------------------------------------------------------- inline const uintptr_t & Thread::stackSize() const { return stackSize_; } //--------------------------------------------------------------------------- inline Array & Thread::beforeExecuteActions() { return *reinterpret_cast *>(beforeExecuteActions_); } //--------------------------------------------------------------------------- inline Array & Thread::afterExecuteActions() { return *reinterpret_cast *>(afterExecuteActions_); } //--------------------------------------------------------------------------- extern uint8_t currentThreadPlaceHolder[]; inline ThreadLocalVariable & currentThread() { return *reinterpret_cast *>(currentThreadPlaceHolder); } //--------------------------------------------------------------------------- } // namespace ksys //--------------------------------------------------------------------------- #if !HAVE_GETTID inline uintptr_t gettid() { #if defined(__WIN32__) || defined(__WIN64__) return (uintptr_t) GetCurrentThreadId(); #elif HAVE_PTHREAD_SELF return (uintptr_t) pthread_self(); #elif defined(__linux__) && defined(__i386__) pid_t ret; __asm__ __volatile__ ( "int $0x80" : "=a" (ret) : "0" (224) ); if( ret < 0 ) ret = -1; return ret; #else #error gettid not implemented #endif } #endif //--------------------------------------------------------------------------- #endif /* _thread_H_ */ //---------------------------------------------------------------------------