From 687d52c9afa5b2d7c0b677eb3a27b2a550742d11 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 12 Nov 2015 12:16:08 +0100 Subject: [PATCH] Add abstraction classes for system thread primitives --- common/os/CMakeLists.txt | 2 + common/os/Mutex.cxx | 162 +++++++++++++++++++++++++++++++++++++++ common/os/Mutex.h | 64 ++++++++++++++++ common/os/Thread.cxx | 122 +++++++++++++++++++++++++++++ common/os/Thread.h | 53 +++++++++++++ 5 files changed, 403 insertions(+) create mode 100644 common/os/Mutex.cxx create mode 100644 common/os/Mutex.h create mode 100644 common/os/Thread.cxx create mode 100644 common/os/Thread.h diff --git a/common/os/CMakeLists.txt b/common/os/CMakeLists.txt index f082eefa..b5749594 100644 --- a/common/os/CMakeLists.txt +++ b/common/os/CMakeLists.txt @@ -1,6 +1,8 @@ include_directories(${CMAKE_SOURCE_DIR}/common) add_library(os STATIC + Mutex.cxx + Thread.cxx w32tiger.c os.cxx) diff --git a/common/os/Mutex.cxx b/common/os/Mutex.cxx new file mode 100644 index 00000000..fcbd0ac7 --- /dev/null +++ b/common/os/Mutex.cxx @@ -0,0 +1,162 @@ +/* Copyright 2015 Pierre Ossman for Cendio AB + * + * This 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 software 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 software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef WIN32 +#include +#else +#include +#endif + +#include + +#include + +using namespace os; + +Mutex::Mutex() +{ +#ifdef WIN32 + systemMutex = new CRITICAL_SECTION; + InitializeCriticalSection((CRITICAL_SECTION*)systemMutex); +#else + int ret; + + systemMutex = new pthread_mutex_t; + ret = pthread_mutex_init((pthread_mutex_t*)systemMutex, NULL); + if (ret != 0) + throw rdr::SystemException("Failed to create mutex", ret); +#endif +} + +Mutex::~Mutex() +{ +#ifdef WIN32 + DeleteCriticalSection((CRITICAL_SECTION*)systemMutex); + delete (CRITICAL_SECTION*)systemMutex; +#else + int ret; + + ret = pthread_mutex_destroy((pthread_mutex_t*)systemMutex); + delete (pthread_mutex_t*)systemMutex; + if (ret != 0) + throw rdr::SystemException("Failed to destroy mutex", ret); +#endif +} + +void Mutex::lock() +{ +#ifdef WIN32 + EnterCriticalSection((CRITICAL_SECTION*)systemMutex); +#else + int ret; + + ret = pthread_mutex_lock((pthread_mutex_t*)systemMutex); + if (ret != 0) + throw rdr::SystemException("Failed to lock mutex", ret); +#endif +} + +void Mutex::unlock() +{ +#ifdef WIN32 + LeaveCriticalSection((CRITICAL_SECTION*)systemMutex); +#else + int ret; + + ret = pthread_mutex_unlock((pthread_mutex_t*)systemMutex); + if (ret != 0) + throw rdr::SystemException("Failed to unlock mutex", ret); +#endif +} + +Condition::Condition(Mutex* mutex) +{ + this->mutex = mutex; + +#ifdef WIN32 + systemCondition = new CONDITION_VARIABLE; + InitializeConditionVariable((CONDITION_VARIABLE*)systemCondition); +#else + int ret; + + systemCondition = new pthread_cond_t; + ret = pthread_cond_init((pthread_cond_t*)systemCondition, NULL); + if (ret != 0) + throw rdr::SystemException("Failed to create condition variable", ret); +#endif +} + +Condition::~Condition() +{ +#ifdef WIN32 + delete (CONDITION_VARIABLE*)systemCondition; +#else + int ret; + + ret = pthread_cond_destroy((pthread_cond_t*)systemCondition); + delete (pthread_cond_t*)systemCondition; + if (ret != 0) + throw rdr::SystemException("Failed to destroy condition variable", ret); +#endif +} + +void Condition::wait() +{ +#ifdef WIN32 + BOOL ret; + + ret = SleepConditionVariableCS((CONDITION_VARIABLE*)systemCondition, + (CRITICAL_SECTION*)mutex->systemMutex, + INFINITE); + if (!ret) + throw rdr::SystemException("Failed to wait on condition variable", GetLastError()); +#else + int ret; + + ret = pthread_cond_wait((pthread_cond_t*)systemCondition, + (pthread_mutex_t*)mutex->systemMutex); + if (ret != 0) + throw rdr::SystemException("Failed to wait on condition variable", ret); +#endif +} + +void Condition::signal() +{ +#ifdef WIN32 + WakeConditionVariable((CONDITION_VARIABLE*)systemCondition); +#else + int ret; + + ret = pthread_cond_signal((pthread_cond_t*)systemCondition); + if (ret != 0) + throw rdr::SystemException("Failed to signal condition variable", ret); +#endif +} + +void Condition::broadcast() +{ +#ifdef WIN32 + WakeAllConditionVariable((CONDITION_VARIABLE*)systemCondition); +#else + int ret; + + ret = pthread_cond_broadcast((pthread_cond_t*)systemCondition); + if (ret != 0) + throw rdr::SystemException("Failed to broadcast condition variable", ret); +#endif +} diff --git a/common/os/Mutex.h b/common/os/Mutex.h new file mode 100644 index 00000000..2a54b205 --- /dev/null +++ b/common/os/Mutex.h @@ -0,0 +1,64 @@ +/* Copyright 2015 Pierre Ossman for Cendio AB + * + * This 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 software 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 software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __OS_MUTEX_H__ +#define __OS_MUTEX_H__ + +namespace os { + class Condition; + + class Mutex { + public: + Mutex(); + ~Mutex(); + + void lock(); + void unlock(); + + private: + friend Condition; + + void* systemMutex; + }; + + class AutoMutex { + public: + AutoMutex(Mutex* mutex) { m = mutex; m->lock(); } + ~AutoMutex() { m->unlock(); } + private: + Mutex* m; + }; + + class Condition { + public: + Condition(Mutex* mutex); + ~Condition(); + + void wait(); + + void signal(); + void broadcast(); + + private: + Mutex* mutex; + void* systemCondition; + }; + +} + +#endif diff --git a/common/os/Thread.cxx b/common/os/Thread.cxx new file mode 100644 index 00000000..7150a7f2 --- /dev/null +++ b/common/os/Thread.cxx @@ -0,0 +1,122 @@ +/* Copyright 2015 Pierre Ossman for Cendio AB + * + * This 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 software 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 software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef WIN32 +#include +#else +#include +#endif + +#include + +#include +#include + +using namespace os; + +Thread::Thread() : running(false), threadId(NULL) +{ + mutex = new Mutex; + +#ifdef WIN32 + threadId = new HANDLE; +#else + threadId = new pthread_t; +#endif +} + +Thread::~Thread() +{ +#ifdef WIN32 + delete (HANDLE*)threadId; +#else + if (isRunning()) + pthread_cancel(*(pthread_t*)threadId); + delete (pthread_t*)threadId; +#endif + + delete mutex; +} + +void Thread::start() +{ + AutoMutex a(mutex); + +#ifdef WIN32 + *(HANDLE*)threadId = CreateThread(NULL, 0, startRoutine, this, 0, NULL); + if (*(HANDLE*)threadId == NULL) + throw rdr::SystemException("Failed to create thread", GetLastError()); +#else + int ret; + + ret = pthread_create((pthread_t*)threadId, NULL, startRoutine, this); + if (ret != 0) + throw rdr::SystemException("Failed to create thread", ret); +#endif + + running = true; +} + +void Thread::wait() +{ + if (!isRunning()) + return; + +#ifdef WIN32 + DWORD ret; + + ret = WaitForSingleObject(*(HANDLE*)threadId, INFINITE); + if (ret != WAIT_OBJECT_0) + throw rdr::SystemException("Failed to join thread", GetLastError()); +#else + int ret; + + ret = pthread_join(*(pthread_t*)threadId, NULL); + if (ret != 0) + throw rdr::SystemException("Failed to join thread", ret); +#endif +} + +bool Thread::isRunning() +{ + AutoMutex a(mutex); + + return running; +} + +#ifdef WIN32 +long unsigned __stdcall Thread::startRoutine(void* data) +#else +void* Thread::startRoutine(void* data) +#endif +{ + Thread *self; + + self = (Thread*)data; + + try { + self->worker(); + } catch(...) { + } + + self->mutex->lock(); + self->running = false; + self->mutex->unlock(); + + return 0; +} diff --git a/common/os/Thread.h b/common/os/Thread.h new file mode 100644 index 00000000..41d94868 --- /dev/null +++ b/common/os/Thread.h @@ -0,0 +1,53 @@ +/* Copyright 2015 Pierre Ossman for Cendio AB + * + * This 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 software 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 software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __OS_THREAD_H__ +#define __OP_THREAD_H__ + +namespace os { + class Mutex; + + class Thread { + public: + Thread(); + virtual ~Thread(); + + void start(); + void wait(); + + bool isRunning(); + + protected: + virtual void worker() = 0; + + private: +#ifdef WIN32 + static long unsigned __stdcall startRoutine(void* data); +#else + static void* startRoutine(void* data); +#endif + + private: + Mutex *mutex; + bool running; + + void *threadId; + }; +} + +#endif -- 2.39.5