summaryrefslogtreecommitdiffstats
path: root/src/threads
diff options
context:
space:
mode:
Diffstat (limited to 'src/threads')
-rw-r--r--src/threads/Makefile.am11
-rw-r--r--src/threads/mutex.cpp90
-rw-r--r--src/threads/mutex.h86
-rw-r--r--src/threads/sema.cpp76
-rw-r--r--src/threads/sema.h44
-rw-r--r--src/threads/thread.cpp108
-rw-r--r--src/threads/thread.h59
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