From 0a16e53b40d347db7dcd04cb694d0f8f2ed1a5a7 Mon Sep 17 00:00:00 2001
From: sfan5 <sfan5@live.de>
Date: Thu, 6 Oct 2016 21:13:04 +0200
Subject: [PATCH] Fix C++11 Windows build of threading code

	The initial problem was that mutex_auto_lock.h tries to use std::unique_lock<std::mutex>
	despite mutex.h not using C++11's std::mutex on Windows. The problem here is the mismatch
	between C++11 usage conditions of the two headers. This commit moves the decision logic
	to threads.h and makes sure mutex.h, mutex_auto_lock.h and event.h all use the same features.
---
 src/threading/event.cpp         | 16 ++++++++--------
 src/threading/event.h           | 17 ++++++-----------
 src/threading/mutex.cpp         | 19 +++++++++----------
 src/threading/mutex.h           | 15 ++++++++-------
 src/threading/mutex_auto_lock.h |  4 +++-
 src/threading/thread.cpp        | 20 ++++++++++----------
 src/threading/thread.h          | 13 ++++---------
 src/threads.h                   | 18 +++++++++++++++++-
 8 files changed, 65 insertions(+), 57 deletions(-)

diff --git a/src/threading/event.cpp b/src/threading/event.cpp
index 165f9d83f..0d5928f10 100644
--- a/src/threading/event.cpp
+++ b/src/threading/event.cpp
@@ -27,8 +27,8 @@ DEALINGS IN THE SOFTWARE.
 
 Event::Event()
 {
-#if __cplusplus < 201103L
-#	ifdef _WIN32
+#ifndef USE_CPP11_MUTEX
+#	if USE_WIN_MUTEX
 	event = CreateEvent(NULL, false, false, NULL);
 #	else
 	pthread_cond_init(&cv, NULL);
@@ -38,10 +38,10 @@ Event::Event()
 #endif
 }
 
-#if __cplusplus < 201103L
+#ifndef USE_CPP11_MUTEX
 Event::~Event()
 {
-#ifdef _WIN32
+#if USE_WIN_MUTEX
 	CloseHandle(event);
 #else
 	pthread_cond_destroy(&cv);
@@ -53,13 +53,13 @@ Event::~Event()
 
 void Event::wait()
 {
-#if __cplusplus >= 201103L
+#if USE_CPP11_MUTEX
 	MutexAutoLock lock(mutex);
 	while (!notified) {
 		cv.wait(lock);
 	}
 	notified = false;
-#elif defined(_WIN32)
+#elif USE_WIN_MUTEX
 	WaitForSingleObject(event, INFINITE);
 #else
 	pthread_mutex_lock(&mutex);
@@ -74,11 +74,11 @@ void Event::wait()
 
 void Event::signal()
 {
-#if __cplusplus >= 201103L
+#if USE_CPP11_MUTEX
 	MutexAutoLock lock(mutex);
 	notified = true;
 	cv.notify_one();
-#elif defined(_WIN32)
+#elif USE_WIN_MUTEX
 	SetEvent(event);
 #else
 	pthread_mutex_lock(&mutex);
diff --git a/src/threading/event.h b/src/threading/event.h
index dd5164576..26cb8997a 100644
--- a/src/threading/event.h
+++ b/src/threading/event.h
@@ -26,17 +26,12 @@ DEALINGS IN THE SOFTWARE.
 #ifndef THREADING_EVENT_H
 #define THREADING_EVENT_H
 
-#if __cplusplus >= 201103L
+#include "threads.h"
+
+#if USE_CPP11_MUTEX
 	#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
 
 
@@ -49,18 +44,18 @@ DEALINGS IN THE SOFTWARE.
 class Event {
 public:
 	Event();
-#if __cplusplus < 201103L
+#ifndef USE_CPP11_MUTEX
 	~Event();
 #endif
 	void wait();
 	void signal();
 
 private:
-#if __cplusplus >= 201103L
+#if USE_CPP11_MUTEX
 	std::condition_variable cv;
 	Mutex mutex;
 	bool notified;
-#elif defined(_WIN32)
+#elif USE_WIN_MUTEX
 	HANDLE event;
 #else
 	pthread_cond_t cv;
diff --git a/src/threading/mutex.cpp b/src/threading/mutex.cpp
index f2b07bec3..0908b5d37 100644
--- a/src/threading/mutex.cpp
+++ b/src/threading/mutex.cpp
@@ -23,14 +23,13 @@ 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 "threads.h"
+
+#ifndef USE_CPP11_MUTEX
 
 #include "threading/mutex.h"
 
-#ifndef _WIN32
-	#include <cassert>
-#endif
+#include <cassert>
 
 #define UNUSED(expr) do { (void)(expr); } while (0)
 
@@ -47,7 +46,7 @@ Mutex::Mutex(bool recursive)
 
 void Mutex::init_mutex(bool recursive)
 {
-#ifdef _WIN32
+#if USE_WIN_MUTEX
 	// Windows critical sections are recursive by default
 	UNUSED(recursive);
 
@@ -69,7 +68,7 @@ void Mutex::init_mutex(bool recursive)
 
 Mutex::~Mutex()
 {
-#ifdef _WIN32
+#if USE_WIN_MUTEX
 	DeleteCriticalSection(&mutex);
 #else
 	int ret = pthread_mutex_destroy(&mutex);
@@ -80,7 +79,7 @@ Mutex::~Mutex()
 
 void Mutex::lock()
 {
-#ifdef _WIN32
+#if USE_WIN_MUTEX
 	EnterCriticalSection(&mutex);
 #else
 	int ret = pthread_mutex_lock(&mutex);
@@ -91,7 +90,7 @@ void Mutex::lock()
 
 void Mutex::unlock()
 {
-#ifdef _WIN32
+#if USE_WIN_MUTEX
 	LeaveCriticalSection(&mutex);
 #else
 	int ret = pthread_mutex_unlock(&mutex);
@@ -104,5 +103,5 @@ RecursiveMutex::RecursiveMutex()
 	: Mutex(true)
 {}
 
-#endif
+#endif // C++11
 
diff --git a/src/threading/mutex.h b/src/threading/mutex.h
index dadbd050c..fb5c029fc 100644
--- a/src/threading/mutex.h
+++ b/src/threading/mutex.h
@@ -26,14 +26,15 @@ 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 "threads.h"
+
+#if USE_CPP11_MUTEX
 	#include <mutex>
 	using Mutex = std::mutex;
 	using RecursiveMutex = std::recursive_mutex;
 #else
 
-#ifdef _WIN32
+#if USE_WIN_MUTEX
 	#ifndef _WIN32_WINNT
 		#define _WIN32_WINNT 0x0501
 	#endif
@@ -41,7 +42,7 @@ DEALINGS IN THE SOFTWARE.
 		#define WIN32_LEAN_AND_MEAN
 	#endif
 	#include <windows.h>
-#else // pthread
+#else
 	#include <pthread.h>
 #endif
 
@@ -59,9 +60,9 @@ class Mutex
 	Mutex(bool recursive);
 	void init_mutex(bool recursive);
 private:
-#ifdef _WIN32
+#if USE_WIN_MUTEX
 	CRITICAL_SECTION mutex;
-#else // pthread
+#else
 	pthread_mutex_t mutex;
 #endif
 
@@ -76,6 +77,6 @@ class RecursiveMutex : public Mutex
 	DISABLE_CLASS_COPY(RecursiveMutex);
 };
 
-#endif  // C++11
+#endif // C++11
 
 #endif
diff --git a/src/threading/mutex_auto_lock.h b/src/threading/mutex_auto_lock.h
index 25caf7e14..d79c68a93 100644
--- a/src/threading/mutex_auto_lock.h
+++ b/src/threading/mutex_auto_lock.h
@@ -26,7 +26,9 @@ DEALINGS IN THE SOFTWARE.
 #ifndef THREADING_MUTEX_AUTO_LOCK_H
 #define THREADING_MUTEX_AUTO_LOCK_H
 
-#if __cplusplus >= 201103L
+#include "threads.h"
+
+#if USE_CPP11_MUTEX
 	#include <mutex>
 	using MutexAutoLock = std::unique_lock<std::mutex>;
 	using RecursiveMutexAutoLock = std::unique_lock<std::recursive_mutex>;
diff --git a/src/threading/thread.cpp b/src/threading/thread.cpp
index 0cd536795..fbe4ba1f3 100644
--- a/src/threading/thread.cpp
+++ b/src/threading/thread.cpp
@@ -198,7 +198,7 @@ bool Thread::kill()
 
 	m_running = false;
 
-#ifdef _WIN32
+#if USE_WIN_THREADS
 	TerminateThread(m_thread_handle, 0);
 	CloseHandle(m_thread_handle);
 #else
@@ -310,10 +310,16 @@ void Thread::setName(const std::string &name)
 
 unsigned int Thread::getNumberOfProcessors()
 {
-#if __cplusplus >= 201103L
+#if USE_CPP11_THREADS
 
 	return std::thread::hardware_concurrency();
 
+#elif USE_WIN_THREADS
+
+	SYSTEM_INFO sysinfo;
+	GetSystemInfo(&sysinfo);
+	return sysinfo.dwNumberOfProcessors;
+
 #elif defined(_SC_NPROCESSORS_ONLN)
 
 	return sysconf(_SC_NPROCESSORS_ONLN);
@@ -335,12 +341,6 @@ unsigned int Thread::getNumberOfProcessors()
 
 	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();
@@ -359,7 +359,7 @@ bool Thread::bindToProcessor(unsigned int proc_number)
 
 	return false;
 
-#elif defined(_WIN32)
+#elif USE_WIN_THREADS
 
 	return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
 
@@ -407,7 +407,7 @@ bool Thread::bindToProcessor(unsigned int proc_number)
 
 bool Thread::setPriority(int prio)
 {
-#if defined(_WIN32)
+#if USE_WIN_THREADS
 
 	return SetThreadPriority(getThreadHandle(), prio);
 
diff --git a/src/threading/thread.h b/src/threading/thread.h
index de800ecb7..14a0e13ab 100644
--- a/src/threading/thread.h
+++ b/src/threading/thread.h
@@ -32,9 +32,6 @@ DEALINGS IN THE SOFTWARE.
 #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
@@ -157,9 +154,11 @@ class Thread {
 	Atomic<bool> m_running;
 	Mutex m_mutex;
 
-#ifndef USE_CPP11_THREADS
+#if USE_CPP11_THREADS
+	std::thread *m_thread_obj;
+#else
 	threadhandle_t m_thread_handle;
-#   if _WIN32
+#   if USE_WIN_THREADS
         threadid_t m_thread_id;
 #   endif
 #endif
@@ -172,10 +171,6 @@ class Thread {
 	tid_t m_kernel_thread_id;
 #endif
 
-#if USE_CPP11_THREADS
-	std::thread *m_thread_obj;
-#endif
-
 	DISABLE_CLASS_COPY(Thread);
 };
 
diff --git a/src/threads.h b/src/threads.h
index d4306f631..ce98593cd 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define THREADS_HEADER
 
 //
-// Determine which threading API we will use
+// Determine which threading APIs we will use
 //
 #if __cplusplus >= 201103L
 	#define USE_CPP11_THREADS 1
@@ -31,11 +31,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 	#define USE_POSIX_THREADS 1
 #endif
 
+#if defined(_WIN32)
+	// Prefer critical section API because std::mutex is much slower on Windows
+	#define USE_WIN_MUTEX 1
+#elif __cplusplus >= 201103L
+	#define USE_CPP11_MUTEX 1
+#else
+	#define USE_POSIX_MUTEX 1
+#endif
+
 ///////////////
 
 
 #if USE_CPP11_THREADS
 	#include <thread>
+#elif USE_POSIX_THREADS
+	#include <pthread.h>
+#else
+	#ifndef WIN32_LEAN_AND_MEAN
+		#define WIN32_LEAN_AND_MEAN
+	#endif
+	#include <windows.h>
 #endif
 
 #include "threading/mutex.h"
-- 
GitLab