diff options
Diffstat (limited to 'mcop_mt/threads_posix.cpp')
-rw-r--r-- | mcop_mt/threads_posix.cpp | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/mcop_mt/threads_posix.cpp b/mcop_mt/threads_posix.cpp new file mode 100644 index 0000000..6fa953c --- /dev/null +++ b/mcop_mt/threads_posix.cpp @@ -0,0 +1,398 @@ + /* + + Copyright (C) 2001 Stefan Westerfeld + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* only compile this if we have libpthread available */ +#ifdef HAVE_LIBPTHREAD + +#include <gsl/gslconfig.h> +#include <gsl/gslcommon.h> + +#include <sys/types.h> +#include <stddef.h> +#include <stdarg.h> +#include <pthread.h> +#include <semaphore.h> +#include <debug.h> +#include <string.h> +#include "thread.h" + +/* + * define this if you want to protect mutexes against being locked twice by + * the same thread + */ +#undef PTHREAD_DEBUG + +namespace Arts { + +extern void *gslGlobalMutexTable; + +namespace PosixThreads { + +class ThreadCondition_impl; + +class Mutex_impl : public Arts::Mutex_impl { +protected: + friend class ThreadCondition_impl; + pthread_mutex_t mutex; + +#ifdef PTHREAD_DEBUG + pthread_t owner; +#endif + +public: + Mutex_impl() + { + pthread_mutex_init(&mutex, 0); +#ifdef PTHREAD_DEBUG + owner = 0; +#endif + } + void lock() + { +#ifdef PTHREAD_DEBUG + pthread_t self = pthread_self(); + arts_assert(owner != self); +#endif + + pthread_mutex_lock(&mutex); + +#ifdef PTHREAD_DEBUG + arts_assert(!owner); + owner = self; +#endif + } + bool tryLock() + { +#ifdef PTHREAD_DEBUG + pthread_t self = pthread_self(); + arts_assert(owner != self); +#endif + + int result = pthread_mutex_trylock(&mutex); + +#ifdef PTHREAD_DEBUG + if(result == 0) + { + arts_assert(!owner); + owner = self; + } +#endif + return(result == 0); + } + void unlock() + { +#ifdef PTHREAD_DEBUG + arts_assert(owner == pthread_self()); + owner = 0; +#endif + + pthread_mutex_unlock(&mutex); + } +}; + +class RecMutex_impl : public Arts::Mutex_impl { +protected: + friend class ThreadCondition_impl; + pthread_mutex_t mutex; + pthread_t owner; + int count; + +public: + RecMutex_impl() + { + pthread_mutex_init(&mutex, 0); + owner = 0; + count = 0; + } + void lock() + { + pthread_t self = pthread_self(); + if(owner != self) + { + pthread_mutex_lock(&mutex); +#ifdef PTHREAD_DEBUG + arts_assert(count == 0); + arts_assert(!owner); +#endif + owner = self; + } + count++; + } + bool tryLock() + { + pthread_t self = pthread_self(); + if(owner != self) + { + int result = pthread_mutex_trylock(&mutex); + if(result != 0) + return false; + +#ifdef PTHREAD_DEBUG + arts_assert(count == 0); + arts_assert(!owner); +#endif + owner = self; + } + count++; + return true; + } + void unlock() + { +#ifdef PTHREAD_DEBUG + arts_assert(owner == pthread_self()); + arts_assert(count > 0); +#endif + + count--; + if(count == 0) + { + owner = 0; + pthread_mutex_unlock(&mutex); + } + } +}; + + +class Thread_impl : public Arts::Thread_impl { +protected: + friend class PosixThreads; + pthread_t pthread; + Thread *thread; + +public: + Thread_impl(Thread *thread) : thread(thread) { + } + void setPriority(int priority) { + struct sched_param sp; + sp.sched_priority = priority; + if (pthread_setschedparam(pthread, SCHED_FIFO, &sp)) + arts_debug("Thread::setPriority: sched_setscheduler failed"); + } + static pthread_key_t privateDataKey; + static void *threadStartInternal(void *impl) + { + pthread_setspecific(privateDataKey, impl); + + ((Thread_impl *)impl)->thread->run(); + return 0; + } + void start() { + pthread_create(&pthread,0,threadStartInternal,this); + } + void waitDone() { + void *foo; + pthread_join(pthread,&foo); + } +}; + +pthread_key_t Thread_impl::privateDataKey; + +class ThreadCondition_impl : public Arts::ThreadCondition_impl { +protected: + pthread_cond_t cond; + +public: + ThreadCondition_impl() { + pthread_cond_init(&cond, 0); + } + ~ThreadCondition_impl() { + pthread_cond_destroy(&cond); + } + void wakeOne() { + pthread_cond_signal(&cond); + } + void wakeAll() { + pthread_cond_broadcast(&cond); + } + void wait(Arts::Mutex_impl *mutex) { +#ifdef PTHREAD_DEBUG + pthread_t self = pthread_self(); + arts_assert(((Mutex_impl *)mutex)->owner == self); + ((Mutex_impl *)mutex)->owner = 0; +#endif + + pthread_cond_wait(&cond, &((Mutex_impl*)mutex)->mutex); + +#ifdef PTHREAD_DEBUG + arts_assert(((Mutex_impl *)mutex)->owner == 0); + ((Mutex_impl *)mutex)->owner = self; +#endif + } +}; + +class Semaphore_impl : public Arts::Semaphore_impl +{ +private: + sem_t semaphore; + +public: + Semaphore_impl(int shared, int count) { + sem_init(&semaphore, shared, count); + } + + ~Semaphore_impl() { + sem_destroy(&semaphore); + } + + void wait() { + sem_wait(&semaphore); + } + + int tryWait() { + return sem_trywait(&semaphore); + } + + void post() { + sem_post(&semaphore); + } + + int getValue() { + int retval; + sem_getvalue(&semaphore, &retval); + return retval; + } +}; + +class PosixThreads : public SystemThreads { +private: + pthread_t mainThread; +public: + PosixThreads() { + mainThread = pthread_self(); + } + bool isMainThread() { + return pthread_equal(pthread_self(), mainThread); + } + Arts::Mutex_impl *createMutex_impl() { + return new Mutex_impl(); + } + Arts::Mutex_impl *createRecMutex_impl() { + return new RecMutex_impl(); + } + Arts::Thread_impl *createThread_impl(Arts::Thread *thread) { + return new Thread_impl(thread); + } + Arts::ThreadCondition_impl *createThreadCondition_impl() { + return new ThreadCondition_impl(); + } + Thread *getCurrentThread() { + void *data = pthread_getspecific(Thread_impl::privateDataKey); + + if(data) + return ((Thread_impl *)data)->thread; + else + return 0; /* main thread */ + } + Arts::Semaphore_impl *createSemaphore_impl(int shared, int count) { + return new Semaphore_impl(shared, count); + } +}; + +// set posix threads on startup +static class SetSystemThreads { +private: + PosixThreads posixThreads; + +public: + SetSystemThreads() { + if(pthread_key_create(&Thread_impl::privateDataKey, 0)) + arts_debug("SystemThreads init: pthread_key_create failed"); + + SystemThreads::init(&posixThreads); + + } + ~SetSystemThreads() { + SystemThreads::init(0); + + if(pthread_key_delete(Thread_impl::privateDataKey)) + arts_debug("SystemThreads init: pthread_key_delete failed"); + } +} initOnStartup; + +/* -fast- locking for gsl on platforms with unix98 support */ +#if (GSL_HAVE_MUTEXATTR_SETTYPE > 0) +static void pth_mutex_init (GslMutex *mutex) +{ + /* need NULL attribute here, which is the fast mutex on glibc + * and cannot be chosen through the pthread_mutexattr_settype() + */ + pthread_mutex_init ((pthread_mutex_t*) mutex, NULL); +} +static void pth_rec_mutex_init (GslRecMutex *mutex) +{ + pthread_mutexattr_t attr; + + pthread_mutexattr_init (&attr); + pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init ((pthread_mutex_t*) mutex, &attr); + pthread_mutexattr_destroy (&attr); +} +static void pth_rec_cond_init (GslCond *cond) +{ + pthread_cond_init ((pthread_cond_t*) cond, NULL); +} +static void pth_rec_cond_wait_timed (GslCond *cond, GslMutex *mutex, + gulong abs_secs, gulong abs_usecs) +{ + struct ::timespec abstime; + + abstime.tv_sec = abs_secs; + abstime.tv_nsec = abs_usecs * 1000; + pthread_cond_timedwait ((pthread_cond_t*) cond, (pthread_mutex_t*) mutex, &abstime); +} +static GslMutexTable pth_mutex_table = { + pth_mutex_init, + (void (*) (GslMutex*)) pthread_mutex_lock, + (int (*) (GslMutex*)) pthread_mutex_trylock, + (void (*) (GslMutex*)) pthread_mutex_unlock, + (void (*) (GslMutex*)) pthread_mutex_destroy, + pth_rec_mutex_init, + (void (*) (GslRecMutex*)) pthread_mutex_lock, + (int (*) (GslRecMutex*)) pthread_mutex_trylock, + (void (*) (GslRecMutex*)) pthread_mutex_unlock, + (void (*) (GslRecMutex*)) pthread_mutex_destroy, + pth_rec_cond_init, + (void (*) (GslCond*)) pthread_cond_signal, + (void (*) (GslCond*)) pthread_cond_broadcast, + (void (*) (GslCond*, GslMutex*)) pthread_cond_wait, + pth_rec_cond_wait_timed, + (void (*) (GslCond*)) pthread_cond_destroy, +}; + +static class SetGslMutexTable { +public: + SetGslMutexTable() + { + gslGlobalMutexTable = &pth_mutex_table; + } +} initGslMutexTable; +#endif + +} + +} + +#endif |