diff options
Diffstat (limited to 'src/threads')
-rw-r--r-- | src/threads/Makefile.am | 11 | ||||
-rw-r--r-- | src/threads/mutex.cpp | 90 | ||||
-rw-r--r-- | src/threads/mutex.h | 86 | ||||
-rw-r--r-- | src/threads/sema.cpp | 76 | ||||
-rw-r--r-- | src/threads/sema.h | 44 | ||||
-rw-r--r-- | src/threads/thread.cpp | 108 | ||||
-rw-r--r-- | src/threads/thread.h | 59 |
7 files changed, 474 insertions, 0 deletions
diff --git a/src/threads/Makefile.am b/src/threads/Makefile.am new file mode 100644 index 0000000..221bddf --- /dev/null +++ b/src/threads/Makefile.am @@ -0,0 +1,11 @@ +AM_CPPFLAGS = -Wall -I$(top_srcdir)/src + +noinst_LIBRARIES = libthread.a + +libthread_a_SOURCES =\ + thread.cpp\ + mutex.cpp\ + sema.cpp\ + thread.h\ + mutex.h\ + sema.h diff --git a/src/threads/mutex.cpp b/src/threads/mutex.cpp new file mode 100644 index 0000000..0ae2a99 --- /dev/null +++ b/src/threads/mutex.cpp @@ -0,0 +1,90 @@ +/* + Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <string> +#include <iostream> +#include "mutex.h" +#include "thread.h" + +using namespace std; + +/////////////////////////// +// t_mutex +/////////////////////////// + +t_mutex::t_mutex() { + pthread_mutex_init(&mutex, NULL); +} + +t_mutex::t_mutex(bool recursive) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + + + int ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); + if (ret != 0) throw string( + "t_mutex::t_mutex failed to create a recursive mutex."); + + pthread_mutex_init(&mutex, &attr); + pthread_mutexattr_destroy(&attr); +} + +t_mutex::~t_mutex() { + pthread_mutex_destroy(&mutex); +} + +void t_mutex::lock(void) { + int ret = pthread_mutex_lock(&mutex); + if (ret != 0) throw string("t_mutex::lock failed."); +} + +int t_mutex::trylock(void) { + int ret = pthread_mutex_trylock(&mutex); + switch (ret) { + case 0: + case EBUSY: + return ret; + default: + throw string("t_mutex::trylock failed."); + } +} + +void t_mutex::unlock(void) { + int ret = pthread_mutex_unlock(&mutex); + if (ret != 0) throw ("t_mutex::unlock failed."); +} + +/////////////////////////// +// t_recursive_mutex +/////////////////////////// + +t_recursive_mutex::t_recursive_mutex() : t_mutex(true) {} + +t_recursive_mutex::~t_recursive_mutex() {} + +/////////////////////////// +// t_guard_mutex +/////////////////////////// + +t_mutex_guard::t_mutex_guard(t_mutex &mutex) : mutex_(mutex) { + mutex_.lock(); +} + +t_mutex_guard::~t_mutex_guard() { + mutex_.unlock(); +} diff --git a/src/threads/mutex.h b/src/threads/mutex.h new file mode 100644 index 0000000..9970e08 --- /dev/null +++ b/src/threads/mutex.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _H_MUTEX +#define _H_MUTEX + +#include <errno.h> +#include <pthread.h> + +/** + * @file + * Mutex operations + */ + +class t_mutex { +protected: + pthread_mutex_t mutex; + +public: + t_mutex(); + + // Throws a string exception (error message) when failing. + t_mutex(bool recursive); + + virtual ~t_mutex(); + + // These methods throw a string exception when the operation + // fails. + virtual void lock(void); + + // Returns: + // 0 - success + // EBUSY - already locked + // For other errors a string exception is thrown + virtual int trylock(void); + virtual void unlock(void); +}; + +class t_recursive_mutex : public t_mutex { +public: + t_recursive_mutex(); + ~t_recursive_mutex(); +}; + + +/** + * Guard pattern for a mutex . + * The constructor of a guard locks a mutex and the destructor + * unlocks it. This way a guard object can be created at entrance + * of a function. Then at exit, the mutex is automically unlocked + * as the guard object goes out of scope. + */ +class t_mutex_guard { +private: + /** The guarding mutex. */ + t_mutex &mutex_; + +public: + /** + * The constructor will lock the mutex. + * @param mutex [in] Mutex to lock. + */ + t_mutex_guard(t_mutex &mutex); + + /** + * The destructor will unlock the mutex. + */ + ~t_mutex_guard(); +}; + +#endif diff --git a/src/threads/sema.cpp b/src/threads/sema.cpp new file mode 100644 index 0000000..8eb686b --- /dev/null +++ b/src/threads/sema.cpp @@ -0,0 +1,76 @@ +/* + Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <cerrno> +#include <cstring> +#include <string> +#include "sema.h" +#include "util.h" + +using namespace std; + +t_semaphore::t_semaphore(unsigned int value) { + int ret; + + ret = sem_init(&sem, 0, value); + if (ret != 0) { + string err = get_error_str(errno); + string exception = + "t_semaphore::t_semaphore failed to create a semaphore.\n"; + exception += err; + throw exception; + } +} + +t_semaphore::~t_semaphore() { + sem_destroy(&sem); +} + +void t_semaphore::up(void) { + int ret; + + ret = sem_post(&sem); + if (ret != 0) { + string err = get_error_str(errno); + string exception = "t_semaphore::up failed.\n"; + exception += err; + throw exception; + } +} + +void t_semaphore::down(void) { + while (true) { + int ret = sem_wait(&sem); + + if (ret != 0 && errno == EINTR) { + // In NPTL threading sem_wait can be interrupted. + // In LinuxThreads threading sem_wait is non-interruptable. + // Continue with sem_wait if an interrupt is caught. + continue; + } + + break; + } +} + +bool t_semaphore::try_down(void) { + int ret; + + ret = sem_trywait(&sem); + return (ret == 0); +} diff --git a/src/threads/sema.h b/src/threads/sema.h new file mode 100644 index 0000000..0cd04a5 --- /dev/null +++ b/src/threads/sema.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _H_SEMAPHORE +#define _H_SEMAPHORE + +#include <semaphore.h> + +class t_semaphore { +private: + sem_t sem; + +public: + // Throws a string exception (error message) when failing. + t_semaphore(unsigned int value); + + ~t_semaphore(); + + // Throws a string exception (error message) when failing. + void up(void); + + void down(void); + + // Returns true if downing the semaphore succeeded. + // Returns false if the semaphore was zero already. + bool try_down(void); +}; + +#endif diff --git a/src/threads/thread.cpp b/src/threads/thread.cpp new file mode 100644 index 0000000..30fa2fa --- /dev/null +++ b/src/threads/thread.cpp @@ -0,0 +1,108 @@ +/* + Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <signal.h> +#include <cstdio> +#include <cstdlib> +#include <sys/types.h> +#include <unistd.h> +#include "thread.h" + +// Scratch variables for checking LinuxThreads vs NPTL +static pid_t pid_thread; + +t_thread::t_thread(void *(*start_routine)(void *), void *arg) { + int ret; + + ret = pthread_create(&tid, NULL, start_routine, arg); + if (ret != 0) throw ret; +} + +void t_thread::join(void) { + int ret = pthread_join(tid, NULL); + if (ret != 0) throw ret; +} + +void t_thread::detach(void) { + int ret = pthread_detach(tid); + if (ret != 0) throw ret; +} + +void t_thread::kill(void) { + int ret = pthread_kill(tid, SIGKILL); + if (ret != 0) throw ret; +} + +void t_thread::cancel(void) { + int ret = pthread_cancel(tid); + if (ret != 0) throw ret; +} + +void t_thread::set_sched_fifo(int priority) { + struct sched_param sp; + + sp.sched_priority = priority; + int ret = pthread_setschedparam(tid, SCHED_FIFO, &sp); + if (ret != 0) throw ret; +} + +pthread_t t_thread::get_tid(void) const { + return tid; +} + +pthread_t t_thread::self(void) { + return pthread_self(); +} + +bool t_thread::is_equal(const t_thread &thr) const { + return pthread_equal(tid, thr.get_tid()); +} + +bool t_thread::is_equal(const pthread_t &_tid) const { + return pthread_equal(tid, _tid); +} + +bool t_thread::is_self(void) const { + return pthread_equal(tid, pthread_self()); +} + +bool t_thread::is_self(const pthread_t &_tid) { + return pthread_equal(_tid, pthread_self()); +} + +void *check_threading_impl(void *arg) { + pid_thread = getpid(); + pthread_exit(NULL); +} + +bool t_thread::is_LinuxThreads(void) { + t_thread *thr = new t_thread(check_threading_impl, NULL); + + try { + thr->join(); + } catch (int) { + // Thread is already terminated. + } + + delete thr; + + // In LinuxThreads each thread has a different pid. + // In NPTL all threads have the same pid. + return (getpid() != pid_thread); +} + diff --git a/src/threads/thread.h b/src/threads/thread.h new file mode 100644 index 0000000..f839a25 --- /dev/null +++ b/src/threads/thread.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _H_THREAD +#define _H_THREAD + +#include <pthread.h> + +class t_thread { +private: + pthread_t tid; // Thread id + +public: + t_thread(void *(*start_routine)(void *), void *arg); + + // These methods throw an int (return value of libpthread function) + // when they fail + void join(void); + void detach(void); + void kill(void); + void cancel(void); + void set_sched_fifo(int priority); + + // Get thread id + pthread_t get_tid(void) const; + + // Get thread id of current thread + static pthread_t self(void); + + // Check if 2 threads are equal + bool is_equal(const t_thread &thr) const; + bool is_equal(const pthread_t &_tid) const; + bool is_self(void) const; + static bool is_self(const pthread_t &_tid); + + // Check if LinuxThreads or NPTL is active. This check is needed + // for correctly handling signals. Signal handling in LinuxThreads + // is quite different from signal handling in NPTL. + // This checks creates a new thread and waits on its termination, + // so you better cache its result for efficient future checks. + static bool is_LinuxThreads(void); +}; + +#endif |