aboutsummaryrefslogtreecommitdiff
path: root/src/threading
diff options
context:
space:
mode:
Diffstat (limited to 'src/threading')
-rw-r--r--src/threading/CMakeLists.txt7
-rw-r--r--src/threading/atomic.h139
-rw-r--r--src/threading/event.cpp89
-rw-r--r--src/threading/event.h72
-rw-r--r--src/threading/mutex.cpp108
-rw-r--r--src/threading/mutex.h81
-rw-r--r--src/threading/mutex_auto_lock.h60
-rw-r--r--src/threading/semaphore.cpp162
-rw-r--r--src/threading/semaphore.h55
-rw-r--r--src/threading/thread.cpp430
-rw-r--r--src/threading/thread.h183
11 files changed, 1386 insertions, 0 deletions
diff --git a/src/threading/CMakeLists.txt b/src/threading/CMakeLists.txt
new file mode 100644
index 000000000..5dd60ef1a
--- /dev/null
+++ b/src/threading/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(JTHREAD_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/event.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mutex.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/thread.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/semaphore.cpp
+ PARENT_SCOPE)
+
diff --git a/src/threading/atomic.h b/src/threading/atomic.h
new file mode 100644
index 000000000..c9a454f20
--- /dev/null
+++ b/src/threading/atomic.h
@@ -0,0 +1,139 @@
+/*
+Minetest
+Copyright (C) 2015 ShadowNinja <shadowninja@minetest.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef THREADING_ATOMIC_H
+#define THREADING_ATOMIC_H
+
+
+#if __cplusplus >= 201103L
+ #include <atomic>
+ template<typename T> using Atomic = std::atomic<T>;
+ template<typename T> using GenericAtomic = std::atomic<T>;
+#else
+
+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+#define CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
+#if GCC_VERSION >= 407 || CLANG_VERSION >= 302
+ #define ATOMIC_LOAD_GENERIC(T, v) do { \
+ T _val; \
+ __atomic_load(&(v), &(_val), __ATOMIC_SEQ_CST); \
+ return _val; \
+ } while(0)
+ #define ATOMIC_LOAD(T, v) return __atomic_load_n (&(v), __ATOMIC_SEQ_CST)
+ #define ATOMIC_STORE(T, v, x) __atomic_store (&(v), &(x), __ATOMIC_SEQ_CST); return x
+ #define ATOMIC_EXCHANGE(T, v, x) return __atomic_exchange (&(v), &(x), __ATOMIC_SEQ_CST)
+ #define ATOMIC_ADD_EQ(T, v, x) return __atomic_add_fetch (&(v), (x), __ATOMIC_SEQ_CST)
+ #define ATOMIC_SUB_EQ(T, v, x) return __atomic_sub_fetch (&(v), (x), __ATOMIC_SEQ_CST)
+ #define ATOMIC_POST_INC(T, v) return __atomic_fetch_add (&(v), 1, __ATOMIC_SEQ_CST)
+ #define ATOMIC_POST_DEC(T, v) return __atomic_fetch_sub (&(v), 1, __ATOMIC_SEQ_CST)
+ #define ATOMIC_CAS(T, v, e, d) return __atomic_compare_exchange(&(v), &(e), &(d), \
+ false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#else
+ #define ATOMIC_USE_LOCK
+ #include "threading/mutex.h"
+
+ #define ATOMIC_LOCK_OP(T, op) do { \
+ m_mutex.lock(); \
+ T _val = (op); \
+ m_mutex.unlock(); \
+ return _val; \
+ } while (0)
+ #define ATOMIC_LOCK_CAS(T, v, e, d) do { \
+ m_mutex.lock(); \
+ bool _eq = (v == e); \
+ if (_eq) \
+ v = d; \
+ m_mutex.unlock(); \
+ return _eq; \
+ } while (0)
+ #define ATOMIC_LOAD(T, v) ATOMIC_LOCK_OP(T, v)
+ #define ATOMIC_LOAD_GENERIC(T, v) ATOMIC_LOAD(T, v)
+ #define ATOMIC_STORE(T, v, x) ATOMIC_LOCK_OP(T, v = x)
+ #define ATOMIC_EXCHANGE(T, v, x) do { \
+ m_mutex.lock(); \
+ T _val = v; \
+ v = x; \
+ m_mutex.unlock(); \
+ return _val; \
+ } while (0)
+ #if GCC_VERSION >= 401
+ #define ATOMIC_ADD_EQ(T, v, x) return __sync_add_and_fetch(&(v), (x))
+ #define ATOMIC_SUB_EQ(T, v, x) return __sync_sub_and_fetch(&(v), (x))
+ #define ATOMIC_POST_INC(T, v) return __sync_fetch_and_add(&(v), 1)
+ #define ATOMIC_POST_DEC(T, v) return __sync_fetch_and_sub(&(v), 1)
+ #define ATOMIC_CAS(T, v, e, d) return __sync_bool_compare_and_swap(&(v), &(e), (d))
+ #else
+ #define ATOMIC_ADD_EQ(T, v, x) ATOMIC_LOCK_OP(T, v += x)
+ #define ATOMIC_SUB_EQ(T, v, x) ATOMIC_LOCK_OP(T, v -= x)
+ #define ATOMIC_POST_INC(T, v) ATOMIC_LOCK_OP(T, v++)
+ #define ATOMIC_POST_DEC(T, v) ATOMIC_LOCK_OP(T, v--)
+ #define ATOMIC_CAS(T, v, e, d) ATOMIC_LOCK_CAS(T, v, e, d)
+ #endif
+#endif
+
+// For usage with integral types.
+template<typename T>
+class Atomic {
+public:
+ Atomic(const T &v = 0) : m_val(v) {}
+
+ operator T () { ATOMIC_LOAD(T, m_val); }
+
+ T exchange(T x) { ATOMIC_EXCHANGE(T, m_val, x); }
+ bool compare_exchange_strong(T &expected, T desired) { ATOMIC_CAS(T, m_val, expected, desired); }
+
+ T operator = (T x) { ATOMIC_STORE(T, m_val, x); }
+ T operator += (T x) { ATOMIC_ADD_EQ(T, m_val, x); }
+ T operator -= (T x) { ATOMIC_SUB_EQ(T, m_val, x); }
+ T operator ++ () { return *this += 1; }
+ T operator -- () { return *this -= 1; }
+ T operator ++ (int) { ATOMIC_POST_INC(T, m_val); }
+ T operator -- (int) { ATOMIC_POST_DEC(T, m_val); }
+private:
+ T m_val;
+#ifdef ATOMIC_USE_LOCK
+ Mutex m_mutex;
+#endif
+};
+
+// For usage with non-integral types like float for example.
+// Needed because the other operations aren't provided by gcc
+// for non-integral types:
+// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/_005f_005fatomic-Builtins.html
+template<typename T>
+class GenericAtomic {
+public:
+ GenericAtomic(const T &v = 0) : m_val(v) {}
+
+ operator T () { ATOMIC_LOAD_GENERIC(T, m_val); }
+
+ T exchange(T x) { ATOMIC_EXCHANGE(T, m_val, x); }
+ bool compare_exchange_strong(T &expected, T desired) { ATOMIC_CAS(T, m_val, expected, desired); }
+
+ T operator = (T x) { ATOMIC_STORE(T, m_val, x); }
+private:
+ T m_val;
+#ifdef ATOMIC_USE_LOCK
+ Mutex m_mutex;
+#endif
+};
+
+#endif // C++11
+
+#endif
diff --git a/src/threading/event.cpp b/src/threading/event.cpp
new file mode 100644
index 000000000..165f9d83f
--- /dev/null
+++ b/src/threading/event.cpp
@@ -0,0 +1,89 @@
+/*
+This file is a part of the JThread package, which contains some object-
+oriented thread wrappers for different thread implementations.
+
+Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#include "threading/event.h"
+
+Event::Event()
+{
+#if __cplusplus < 201103L
+# ifdef _WIN32
+ event = CreateEvent(NULL, false, false, NULL);
+# else
+ pthread_cond_init(&cv, NULL);
+ pthread_mutex_init(&mutex, NULL);
+ notified = false;
+# endif
+#endif
+}
+
+#if __cplusplus < 201103L
+Event::~Event()
+{
+#ifdef _WIN32
+ CloseHandle(event);
+#else
+ pthread_cond_destroy(&cv);
+ pthread_mutex_destroy(&mutex);
+#endif
+}
+#endif
+
+
+void Event::wait()
+{
+#if __cplusplus >= 201103L
+ MutexAutoLock lock(mutex);
+ while (!notified) {
+ cv.wait(lock);
+ }
+ notified = false;
+#elif defined(_WIN32)
+ WaitForSingleObject(event, INFINITE);
+#else
+ pthread_mutex_lock(&mutex);
+ while (!notified) {
+ pthread_cond_wait(&cv, &mutex);
+ }
+ notified = false;
+ pthread_mutex_unlock(&mutex);
+#endif
+}
+
+
+void Event::signal()
+{
+#if __cplusplus >= 201103L
+ MutexAutoLock lock(mutex);
+ notified = true;
+ cv.notify_one();
+#elif defined(_WIN32)
+ SetEvent(event);
+#else
+ pthread_mutex_lock(&mutex);
+ notified = true;
+ pthread_cond_signal(&cv);
+ pthread_mutex_unlock(&mutex);
+#endif
+}
diff --git a/src/threading/event.h b/src/threading/event.h
new file mode 100644
index 000000000..dd5164576
--- /dev/null
+++ b/src/threading/event.h
@@ -0,0 +1,72 @@
+/*
+This file is a part of the JThread package, which contains some object-
+oriented thread wrappers for different thread implementations.
+
+Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef THREADING_EVENT_H
+#define THREADING_EVENT_H
+
+#if __cplusplus >= 201103L
+ #include <condition_variable>
+ #include "threading/mutex.h"
+ #include "threading/mutex_auto_lock.h"
+#elif defined(_WIN32)
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #include <windows.h>
+#else
+ #include <pthread.h>
+#endif
+
+
+/** A syncronization primitive that will wake up one waiting thread when signaled.
+ * Calling @c signal() multiple times before a waiting thread has had a chance
+ * to notice the signal will wake only one thread. Additionally, if no threads
+ * are waiting on the event when it is signaled, the next call to @c wait()
+ * will return (almost) immediately.
+ */
+class Event {
+public:
+ Event();
+#if __cplusplus < 201103L
+ ~Event();
+#endif
+ void wait();
+ void signal();
+
+private:
+#if __cplusplus >= 201103L
+ std::condition_variable cv;
+ Mutex mutex;
+ bool notified;
+#elif defined(_WIN32)
+ HANDLE event;
+#else
+ pthread_cond_t cv;
+ pthread_mutex_t mutex;
+ bool notified;
+#endif
+};
+
+#endif
diff --git a/src/threading/mutex.cpp b/src/threading/mutex.cpp
new file mode 100644
index 000000000..f2b07bec3
--- /dev/null
+++ b/src/threading/mutex.cpp
@@ -0,0 +1,108 @@
+/*
+This file is a part of the JThread package, which contains some object-
+oriented thread wrappers for different thread implementations.
+
+Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+// Windows std::mutex is much slower than the critical section API
+#if __cplusplus < 201103L || defined(_WIN32)
+
+#include "threading/mutex.h"
+
+#ifndef _WIN32
+ #include <cassert>
+#endif
+
+#define UNUSED(expr) do { (void)(expr); } while (0)
+
+Mutex::Mutex()
+{
+ init_mutex(false);
+}
+
+
+Mutex::Mutex(bool recursive)
+{
+ init_mutex(recursive);
+}
+
+void Mutex::init_mutex(bool recursive)
+{
+#ifdef _WIN32
+ // Windows critical sections are recursive by default
+ UNUSED(recursive);
+
+ InitializeCriticalSection(&mutex);
+#else
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+
+ if (recursive)
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+
+ int ret = pthread_mutex_init(&mutex, &attr);
+ assert(!ret);
+ UNUSED(ret);
+
+ pthread_mutexattr_destroy(&attr);
+#endif
+}
+
+Mutex::~Mutex()
+{
+#ifdef _WIN32
+ DeleteCriticalSection(&mutex);
+#else
+ int ret = pthread_mutex_destroy(&mutex);
+ assert(!ret);
+ UNUSED(ret);
+#endif
+}
+
+void Mutex::lock()
+{
+#ifdef _WIN32
+ EnterCriticalSection(&mutex);
+#else
+ int ret = pthread_mutex_lock(&mutex);
+ assert(!ret);
+ UNUSED(ret);
+#endif
+}
+
+void Mutex::unlock()
+{
+#ifdef _WIN32
+ LeaveCriticalSection(&mutex);
+#else
+ int ret = pthread_mutex_unlock(&mutex);
+ assert(!ret);
+ UNUSED(ret);
+#endif
+}
+
+RecursiveMutex::RecursiveMutex()
+ : Mutex(true)
+{}
+
+#endif
+
diff --git a/src/threading/mutex.h b/src/threading/mutex.h
new file mode 100644
index 000000000..dadbd050c
--- /dev/null
+++ b/src/threading/mutex.h
@@ -0,0 +1,81 @@
+/*
+This file is a part of the JThread package, which contains some object-
+oriented thread wrappers for different thread implementations.
+
+Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef THREADING_MUTEX_H
+#define THREADING_MUTEX_H
+
+// Windows std::mutex is much slower than the critical section API
+#if __cplusplus >= 201103L && !defined(_WIN32)
+ #include <mutex>
+ using Mutex = std::mutex;
+ using RecursiveMutex = std::recursive_mutex;
+#else
+
+#ifdef _WIN32
+ #ifndef _WIN32_WINNT
+ #define _WIN32_WINNT 0x0501
+ #endif
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #include <windows.h>
+#else // pthread
+ #include <pthread.h>
+#endif
+
+#include "util/basic_macros.h"
+
+class Mutex
+{
+public:
+ Mutex();
+ ~Mutex();
+ void lock();
+ void unlock();
+
+protected:
+ Mutex(bool recursive);
+ void init_mutex(bool recursive);
+private:
+#ifdef _WIN32
+ CRITICAL_SECTION mutex;
+#else // pthread
+ pthread_mutex_t mutex;
+#endif
+
+ DISABLE_CLASS_COPY(Mutex);
+};
+
+class RecursiveMutex : public Mutex
+{
+public:
+ RecursiveMutex();
+
+ DISABLE_CLASS_COPY(RecursiveMutex);
+};
+
+#endif // C++11
+
+#endif
diff --git a/src/threading/mutex_auto_lock.h b/src/threading/mutex_auto_lock.h
new file mode 100644
index 000000000..25caf7e14
--- /dev/null
+++ b/src/threading/mutex_auto_lock.h
@@ -0,0 +1,60 @@
+/*
+This file is a part of the JThread package, which contains some object-
+oriented thread wrappers for different thread implementations.
+
+Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef THREADING_MUTEX_AUTO_LOCK_H
+#define THREADING_MUTEX_AUTO_LOCK_H
+
+#if __cplusplus >= 201103L
+ #include <mutex>
+ using MutexAutoLock = std::unique_lock<std::mutex>;
+ using RecursiveMutexAutoLock = std::unique_lock<std::recursive_mutex>;
+#else
+
+#include "threading/mutex.h"
+
+
+class MutexAutoLock
+{
+public:
+ MutexAutoLock(Mutex &m) : mutex(m) { mutex.lock(); }
+ ~MutexAutoLock() { mutex.unlock(); }
+
+private:
+ Mutex &mutex;
+};
+
+class RecursiveMutexAutoLock
+{
+public:
+ RecursiveMutexAutoLock(RecursiveMutex &m) : mutex(m) { mutex.lock(); }
+ ~RecursiveMutexAutoLock() { mutex.unlock(); }
+
+private:
+ RecursiveMutex &mutex;
+};
+#endif
+
+#endif
+
diff --git a/src/threading/semaphore.cpp b/src/threading/semaphore.cpp
new file mode 100644
index 000000000..77ceff509
--- /dev/null
+++ b/src/threading/semaphore.cpp
@@ -0,0 +1,162 @@
+/*
+Minetest
+Copyright (C) 2013 sapier <sapier AT gmx DOT net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "threading/semaphore.h"
+
+#include <iostream>
+#include <cstdlib>
+#include <cassert>
+
+#define UNUSED(expr) do { (void)(expr); } while (0)
+
+#ifdef _WIN32
+ #include <climits>
+ #define MAX_SEMAPHORE_COUNT LONG_MAX - 1
+#else
+ #include <cerrno>
+ #include <sys/time.h>
+ #include <pthread.h>
+ #if defined(__MACH__) && defined(__APPLE__)
+ #include <mach/mach.h>
+ #include <mach/task.h>
+ #include <mach/semaphore.h>
+ #include <sys/semaphore.h>
+ #include <unistd.h>
+
+ #undef sem_t
+ #undef sem_init
+ #undef sem_wait
+ #undef sem_post
+ #undef sem_destroy
+ #define sem_t semaphore_t
+ #define sem_init(s, p, c) semaphore_create(mach_task_self(), (s), 0, (c))
+ #define sem_wait(s) semaphore_wait(*(s))
+ #define sem_post(s) semaphore_signal(*(s))
+ #define sem_destroy(s) semaphore_destroy(mach_task_self(), *(s))
+ #endif
+#endif
+
+
+Semaphore::Semaphore(int val)
+{
+#ifdef _WIN32
+ semaphore = CreateSemaphore(NULL, val, MAX_SEMAPHORE_COUNT, NULL);
+#else
+ int ret = sem_init(&semaphore, 0, val);
+ assert(!ret);
+ UNUSED(ret);
+#endif
+}
+
+
+Semaphore::~Semaphore()
+{
+#ifdef _WIN32
+ CloseHandle(semaphore);
+#else
+ int ret = sem_destroy(&semaphore);
+#ifdef __ANDROID__
+ // Workaround for broken bionic semaphore implementation!
+ assert(!ret || errno == EBUSY);
+#else
+ assert(!ret);
+#endif
+ UNUSED(ret);
+#endif
+}
+
+
+void Semaphore::post(unsigned int num)
+{
+ assert(num > 0);
+#ifdef _WIN32
+ ReleaseSemaphore(semaphore, num, NULL);
+#else
+ for (unsigned i = 0; i < num; i++) {
+ int ret = sem_post(&semaphore);
+ assert(!ret);
+ UNUSED(ret);
+ }
+#endif
+}
+
+
+void Semaphore::wait()
+{
+#ifdef _WIN32
+ WaitForSingleObject(semaphore, INFINITE);
+#else
+ int ret = sem_wait(&semaphore);
+ assert(!ret);
+ UNUSED(ret);
+#endif
+}
+
+
+bool Semaphore::wait(unsigned int time_ms)
+{
+#ifdef _WIN32
+ unsigned int ret = WaitForSingleObject(semaphore, time_ms);
+
+ if (ret == WAIT_OBJECT_0) {
+ return true;
+ } else {
+ assert(ret == WAIT_TIMEOUT);
+ return false;
+ }
+#else
+# if defined(__MACH__) && defined(__APPLE__)
+ mach_timespec_t wait_time;
+ wait_time.tv_sec = time_ms / 1000;
+ wait_time.tv_nsec = 1000000 * (time_ms % 1000);
+
+ errno = 0;
+ int ret = semaphore_timedwait(semaphore, wait_time);
+ switch (ret) {
+ case KERN_OPERATION_TIMED_OUT:
+ errno = ETIMEDOUT;
+ break;
+ case KERN_ABORTED:
+ errno = EINTR;
+ break;
+ default:
+ if (ret)
+ errno = EINVAL;
+ }
+# else
+ struct timespec wait_time;
+ struct timeval now;
+
+ if (gettimeofday(&now, NULL) == -1) {
+ std::cerr << "Semaphore::wait(ms): Unable to get time with gettimeofday!" << std::endl;
+ abort();
+ }
+
+ wait_time.tv_nsec = ((time_ms % 1000) * 1000 * 1000) + (now.tv_usec * 1000);
+ wait_time.tv_sec = (time_ms / 1000) + (wait_time.tv_nsec / (1000 * 1000 * 1000)) + now.tv_sec;
+ wait_time.tv_nsec %= 1000 * 1000 * 1000;
+
+ int ret = sem_timedwait(&semaphore, &wait_time);
+# endif
+
+ assert(!ret || (errno == ETIMEDOUT || errno == EINTR));
+ return !ret;
+#endif
+}
+
diff --git a/src/threading/semaphore.h b/src/threading/semaphore.h
new file mode 100644
index 000000000..822856396
--- /dev/null
+++ b/src/threading/semaphore.h
@@ -0,0 +1,55 @@
+/*
+Minetest
+Copyright (C) 2013 sapier <sapier AT gmx DOT net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef THREADING_SEMAPHORE_H
+#define THREADING_SEMAPHORE_H
+
+#if defined(_WIN32)
+ #include <windows.h>
+#elif defined(__MACH__) && defined(__APPLE__)
+ #include <mach/semaphore.h>
+#else
+ #include <semaphore.h>
+#endif
+
+#include "util/basic_macros.h"
+
+class Semaphore {
+public:
+ Semaphore(int val=0);
+ ~Semaphore();
+
+ void post(unsigned int num=1);
+ void wait();
+ bool wait(unsigned int time_ms);
+
+private:
+#if defined(WIN32)
+ HANDLE semaphore;
+#elif defined(__MACH__) && defined(__APPLE__)
+ semaphore_t semaphore;
+#else
+ sem_t semaphore;
+#endif
+
+ DISABLE_CLASS_COPY(Semaphore);
+};
+
+#endif
+
diff --git a/src/threading/thread.cpp b/src/threading/thread.cpp
new file mode 100644
index 000000000..5161a6c01
--- /dev/null
+++ b/src/threading/thread.cpp
@@ -0,0 +1,430 @@
+/*
+This file is a part of the JThread package, which contains some object-
+oriented thread wrappers for different thread implementations.
+
+Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#include "threading/thread.h"
+#include "threading/mutex_auto_lock.h"
+#include "log.h"
+#include "porting.h"
+
+#define UNUSED(expr) do { (void)(expr); } while (0)
+
+#if USE_CPP11_THREADS
+ #include <chrono>
+ #include <system_error>
+#elif USE_WIN_THREADS
+ #ifndef _WIN32_WCE
+ #include <process.h>
+ #endif
+#elif USE_POSIX_THREADS
+ #include <time.h>
+ #include <assert.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <sys/time.h>
+
+ #if defined(__FreeBSD__) || defined(__APPLE__)
+ #include <sys/types.h>
+ #include <sys/sysctl.h>
+ #elif defined(_GNU_SOURCE)
+ #include <sys/sysinfo.h>
+ #endif
+#endif
+
+
+// for setName
+#if defined(linux) || defined(__linux)
+ #include <sys/prctl.h>
+#elif defined(__FreeBSD__) || defined(__OpenBSD__)
+ #include <pthread_np.h>
+#elif defined(_MSC_VER)
+ struct THREADNAME_INFO {
+ DWORD dwType; // Must be 0x1000
+ LPCSTR szName; // Pointer to name (in user addr space)
+ DWORD dwThreadID; // Thread ID (-1=caller thread)
+ DWORD dwFlags; // Reserved for future use, must be zero
+ };
+#endif
+
+// for bindToProcessor
+#if __FreeBSD_version >= 702106
+ typedef cpuset_t cpu_set_t;
+#elif defined(__linux) || defined(linux)
+ #include <sched.h>
+#elif defined(__sun) || defined(sun)
+ #include <sys/types.h>
+ #include <sys/processor.h>
+ #include <sys/procset.h>
+#elif defined(_AIX)
+ #include <sys/processor.h>
+ #include <sys/thread.h>
+#elif defined(__APPLE__)
+ #include <mach/mach_init.h>
+ #include <mach/thread_act.h>
+#endif
+
+
+Thread::Thread(const std::string &name) :
+ m_name(name),
+ m_retval(NULL),
+ m_joinable(false),
+ m_request_stop(false),
+ m_running(false)
+{
+#ifdef _AIX
+ m_kernel_thread_id = -1;
+#endif
+}
+
+
+Thread::~Thread()
+{
+ kill();
+}
+
+
+bool Thread::start()
+{
+ MutexAutoLock lock(m_mutex);
+
+ if (m_running)
+ return false;
+
+ m_request_stop = false;
+
+#if USE_CPP11_THREADS
+
+ try {
+ m_thread_obj = new std::thread(threadProc, this);
+ } catch (const std::system_error &e) {
+ return false;
+ }
+
+#elif USE_WIN_THREADS
+
+ m_thread_handle = CreateThread(NULL, 0, threadProc, this, 0, &m_thread_id);
+ if (!m_thread_handle)
+ return false;
+
+#elif USE_POSIX_THREADS
+
+ int status = pthread_create(&m_thread_handle, NULL, threadProc, this);
+ if (status)
+ return false;
+
+#endif
+
+ while (!m_running)
+ sleep_ms(1);
+
+ m_joinable = true;
+
+ return true;
+}
+
+
+bool Thread::stop()
+{
+ m_request_stop = true;
+ return true;
+}
+
+
+bool Thread::wait()
+{
+ MutexAutoLock lock(m_mutex);
+
+ if (!m_joinable)
+ return false;
+
+#if USE_CPP11_THREADS
+
+ m_thread_obj->join();
+
+ delete m_thread_obj;
+ m_thread_obj = NULL;
+
+#elif USE_WIN_THREADS
+
+ int ret = WaitForSingleObject(m_thread_handle, INFINITE);
+ assert(ret == WAIT_OBJECT_0);
+ UNUSED(ret);
+
+ CloseHandle(m_thread_handle);
+ m_thread_handle = NULL;
+ m_thread_id = -1;
+
+#elif USE_POSIX_THREADS
+
+ int ret = pthread_join(m_thread_handle, NULL);
+ assert(ret == 0);
+ UNUSED(ret);
+
+#endif
+
+ assert(m_running == false);
+ m_joinable = false;
+ return true;
+}
+
+
+bool Thread::kill()
+{
+ if (!m_running) {
+ wait();
+ return false;
+ }
+
+ m_running = false;
+
+#ifdef _WIN32
+ TerminateThread(m_thread_handle, 0);
+ CloseHandle(m_thread_handle);
+#else
+ // We need to pthread_kill instead on Android since NDKv5's pthread
+ // implementation is incomplete.
+# ifdef __ANDROID__
+ pthread_kill(getThreadHandle(), SIGKILL);
+# else
+ pthread_cancel(getThreadHandle());
+# endif
+ wait();
+#endif
+
+ m_retval = NULL;
+ m_joinable = false;
+ m_request_stop = false;
+
+ return true;
+}
+
+
+bool Thread::getReturnValue(void **ret)
+{
+ if (m_running)
+ return false;
+
+ *ret = m_retval;
+ return true;
+}
+
+
+#if USE_CPP11_THREADS || USE_POSIX_THREADS
+void *Thread::threadProc(void *param)
+#elif defined(_WIN32_WCE)
+DWORD Thread::threadProc(LPVOID param)
+#elif defined(_WIN32)
+DWORD WINAPI Thread::threadProc(LPVOID param)
+#endif
+{
+ Thread *thr = (Thread *)param;
+
+#ifdef _AIX
+ m_kernel_thread_id = thread_self();
+#endif
+
+ thr->setName(thr->m_name);
+
+ g_logger.registerThread(thr->m_name);
+ thr->m_running = true;
+
+ thr->m_retval = thr->run();
+
+ thr->m_running = false;
+ g_logger.deregisterThread();
+
+ // 0 is returned here to avoid an unnecessary ifdef clause
+ return 0;
+}
+
+
+void Thread::setName(const std::string &name)
+{
+#if defined(linux) || defined(__linux)
+
+ // It would be cleaner to do this with pthread_setname_np,
+ // which was added to glibc in version 2.12, but some major
+ // distributions are still runing 2.11 and previous versions.
+ prctl(PR_SET_NAME, name.c_str());
+
+#elif defined(__FreeBSD__) || defined(__OpenBSD__)
+
+ pthread_set_name_np(pthread_self(), name.c_str());
+
+#elif defined(__NetBSD__)
+
+ pthread_setname_np(pthread_self(), name.c_str());
+
+#elif defined(__APPLE__)
+
+ pthread_setname_np(name.c_str());
+
+#elif defined(_MSC_VER)
+
+ // Windows itself doesn't support thread names,
+ // but the MSVC debugger does...
+ THREADNAME_INFO info;
+
+ info.dwType = 0x1000;
+ info.szName = name.c_str();
+ info.dwThreadID = -1;
+ info.dwFlags = 0;
+
+ __try {
+ RaiseException(0x406D1388, 0,
+ sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
+ } __except (EXCEPTION_CONTINUE_EXECUTION) {
+ }
+
+#elif defined(_WIN32) || defined(__GNU__)
+
+ // These platforms are known to not support thread names.
+ // Silently ignore the request.
+
+#else
+ #warning "Unrecognized platform, thread names will not be available."
+#endif
+}
+
+
+unsigned int Thread::getNumberOfProcessors()
+{
+#if __cplusplus >= 201103L
+
+ return std::thread::hardware_concurrency();
+
+#elif defined(_SC_NPROCESSORS_ONLN)
+
+ return sysconf(_SC_NPROCESSORS_ONLN);
+
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__DragonFly__) || defined(__APPLE__)
+
+ unsigned int num_cpus = 1;
+ size_t len = sizeof(num_cpus);
+
+ int mib[2];
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+
+ sysctl(mib, 2, &num_cpus, &len, NULL, 0);
+ return num_cpus;
+
+#elif defined(_GNU_SOURCE)
+
+ return get_nprocs();
+
+#elif defined(_WIN32)
+
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ return sysinfo.dwNumberOfProcessors;
+
+#elif defined(PTW32_VERSION) || defined(__hpux)
+
+ return pthread_num_processors_np();
+
+#else
+
+ return 1;
+
+#endif
+}
+
+
+bool Thread::bindToProcessor(unsigned int proc_number)
+{
+#if defined(__ANDROID__)
+
+ return false;
+
+#elif defined(_WIN32)
+
+ return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
+
+#elif __FreeBSD_version >= 702106 || defined(__linux) || defined(linux)
+
+ cpu_set_t cpuset;
+
+ CPU_ZERO(&cpuset);
+ CPU_SET(proc_number, &cpuset);
+
+ return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
+
+#elif defined(__sun) || defined(sun)
+
+ return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
+
+#elif defined(_AIX)
+
+ return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
+
+#elif defined(__hpux) || defined(hpux)
+
+ pthread_spu_t answer;
+
+ return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
+ &answer, proc_number, getThreadHandle()) == 0;
+
+#elif defined(__APPLE__)
+
+ struct thread_affinity_policy tapol;
+
+ thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
+ tapol.affinity_tag = proc_number + 1;
+ return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
+ (thread_policy_t)&tapol,
+ THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
+
+#else
+
+ return false;
+
+#endif
+}
+
+
+bool Thread::setPriority(int prio)
+{
+#if defined(_WIN32)
+
+ return SetThreadPriority(getThreadHandle(), prio);
+
+#else
+
+ struct sched_param sparam;
+ int policy;
+
+ if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
+ return false;
+
+ int min = sched_get_priority_min(policy);
+ int max = sched_get_priority_max(policy);
+
+ sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
+ return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;
+
+#endif
+}
+
diff --git a/src/threading/thread.h b/src/threading/thread.h
new file mode 100644
index 000000000..de800ecb7
--- /dev/null
+++ b/src/threading/thread.h
@@ -0,0 +1,183 @@
+/*
+This file is a part of the JThread package, which contains some object-
+oriented thread wrappers for different thread implementations.
+
+Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef THREADING_THREAD_H
+#define THREADING_THREAD_H
+
+#include "util/basic_macros.h"
+#include "threading/atomic.h"
+#include "threading/mutex.h"
+#include "threads.h"
+
+#include <string>
+#if USE_CPP11_THREADS
+ #include <thread> // for std::thread
+#endif
+#ifdef _AIX
+ #include <sys/thread.h> // for tid_t
+#endif
+
+/*
+ * On platforms using pthreads, these five priority classes correlate to
+ * even divisions between the minimum and maximum reported thread priority.
+ */
+#if !defined(_WIN32)
+ #define THREAD_PRIORITY_LOWEST 0
+ #define THREAD_PRIORITY_BELOW_NORMAL 1
+ #define THREAD_PRIORITY_NORMAL 2
+ #define THREAD_PRIORITY_ABOVE_NORMAL 3
+ #define THREAD_PRIORITY_HIGHEST 4
+#endif
+
+
+class Thread {
+public:
+ Thread(const std::string &name="");
+ virtual ~Thread();
+
+ /*
+ * Begins execution of a new thread at the pure virtual method Thread::run().
+ * Execution of the thread is guaranteed to have started after this function
+ * returns.
+ */
+ bool start();
+
+ /*
+ * Requests that the thread exit gracefully.
+ * Returns immediately; thread execution is guaranteed to be complete after
+ * a subsequent call to Thread::wait.
+ */
+ bool stop();
+
+ /*
+ * Immediately terminates the thread.
+ * This should be used with extreme caution, as the thread will not have
+ * any opportunity to release resources it may be holding (such as memory
+ * or locks).
+ */
+ bool kill();
+
+ /*
+ * Waits for thread to finish.
+ * Note: This does not stop a thread, you have to do this on your own.
+ * Returns false immediately if the thread is not started or has been waited
+ * on before.
+ */
+ bool wait();
+
+ /*
+ * Returns true if the calling thread is this Thread object.
+ */
+ bool isCurrentThread() { return thr_is_current_thread(getThreadId()); }
+
+ inline bool isRunning() { return m_running; }
+ inline bool stopRequested() { return m_request_stop; }
+
+#if USE_CPP11_THREADS
+ inline threadid_t getThreadId() { return m_thread_obj->get_id(); }
+ inline threadhandle_t getThreadHandle() { return m_thread_obj->native_handle(); }
+#else
+# if USE_WIN_THREADS
+ inline threadid_t getThreadId() { return m_thread_id; }
+# else
+ inline threadid_t getThreadId() { return m_thread_handle; }
+# endif
+ inline threadhandle_t getThreadHandle() { return m_thread_handle; }
+#endif
+
+ /*
+ * Gets the thread return value.
+ * Returns true if the thread has exited and the return value was available,
+ * or false if the thread has yet to finish.
+ */
+ bool getReturnValue(void **ret);
+
+ /*
+ * Binds (if possible, otherwise sets the affinity of) the thread to the
+ * specific processor specified by proc_number.
+ */
+ bool bindToProcessor(unsigned int proc_number);
+
+ /*
+ * Sets the thread priority to the specified priority.
+ *
+ * prio can be one of: THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,
+ * THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST.
+ * On Windows, any of the other priorites as defined by SetThreadPriority
+ * are supported as well.
+ *
+ * Note that it may be necessary to first set the threading policy or
+ * scheduling algorithm to one that supports thread priorities if not
+ * supported by default, otherwise this call will have no effect.
+ */
+ bool setPriority(int prio);
+
+ /*
+ * Sets the currently executing thread's name to where supported; useful
+ * for debugging.
+ */
+ static void setName(const std::string &name);
+
+ /*
+ * Returns the number of processors/cores configured and active on this machine.
+ */
+ static unsigned int getNumberOfProcessors();
+
+protected:
+ std::string m_name;
+
+ virtual void *run() = 0;
+
+private:
+ void *m_retval;
+ bool m_joinable;
+ Atomic<bool> m_request_stop;
+ Atomic<bool> m_running;
+ Mutex m_mutex;
+
+#ifndef USE_CPP11_THREADS
+ threadhandle_t m_thread_handle;
+# if _WIN32
+ threadid_t m_thread_id;
+# endif
+#endif
+
+ static ThreadStartFunc threadProc;
+
+#ifdef _AIX
+ // For AIX, there does not exist any mapping from pthread_t to tid_t
+ // available to us, so we maintain one ourselves. This is set on thread start.
+ tid_t m_kernel_thread_id;
+#endif
+
+#if USE_CPP11_THREADS
+ std::thread *m_thread_obj;
+#endif
+
+ DISABLE_CLASS_COPY(Thread);
+};
+
+#endif
+