1 /************************************************************************** 2 * 3 * Copyright 2011-2012 Jose Fonseca 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 * 24 **************************************************************************/ 25 26 /* 27 * OS native thread abstraction. 28 * 29 * Mimics/leverages C++11 threads. 30 */ 31 32 #pragma once 33 34 35 /* XXX: We still use our own implementation: 36 * 37 * - MSVC's C++11 threads implementation are hardcoded to use C++ exceptions 38 * 39 * - MinGW's C++11 threads implementation is often either missing or relies on 40 * winpthreads 41 */ 42 43 #if !defined(_WIN32) 44 #define HAVE_CXX11_THREADS 45 #endif 46 47 48 #ifdef HAVE_CXX11_THREADS 49 50 #include <thread> 51 #include <mutex> 52 #include <condition_variable> 53 54 namespace os { 55 56 using std::mutex; 57 using std::recursive_mutex; 58 using std::unique_lock; 59 using std::condition_variable; 60 using std::thread; 61 62 } /* namespace os */ 63 64 65 #else /* !HAVE_CXX11_THREADS */ 66 67 68 #include <assert.h> 69 #ifdef _WIN32 70 # include <process.h> 71 # include <windows.h> 72 # if _WIN32_WINNT >= 0x0600 73 # define HAVE_WIN32_CONDITION_VARIABLES 74 # endif 75 #else 76 # include <pthread.h> 77 # include <unistd.h> 78 #endif 79 80 #include <functional> 81 82 83 namespace os { 84 85 86 /** 87 * Base class for mutex and recursive_mutex. 88 */ 89 class _base_mutex 90 { 91 public: 92 #ifdef _WIN32 93 typedef CRITICAL_SECTION native_handle_type; 94 #else 95 typedef pthread_mutex_t native_handle_type; 96 #endif 97 98 protected: _base_mutex(void)99 _base_mutex(void) { 100 } 101 102 public: ~_base_mutex()103 ~_base_mutex() { 104 #ifdef _WIN32 105 DeleteCriticalSection(&_native_handle); 106 #else 107 pthread_mutex_destroy(&_native_handle); 108 #endif 109 } 110 111 inline void lock(void)112 lock(void) { 113 #ifdef _WIN32 114 EnterCriticalSection(&_native_handle); 115 #else 116 pthread_mutex_lock(&_native_handle); 117 #endif 118 } 119 120 inline void unlock(void)121 unlock(void) { 122 #ifdef _WIN32 123 LeaveCriticalSection(&_native_handle); 124 #else 125 pthread_mutex_unlock(&_native_handle); 126 #endif 127 } 128 native_handle()129 native_handle_type & native_handle() { 130 return _native_handle; 131 } 132 133 protected: 134 native_handle_type _native_handle; 135 }; 136 137 138 /** 139 * Same interface as std::mutex. 140 */ 141 class mutex : public _base_mutex 142 { 143 public: 144 inline mutex(void)145 mutex(void) { 146 #ifdef _WIN32 147 InitializeCriticalSection(&_native_handle); 148 #else 149 pthread_mutex_init(&_native_handle, NULL); 150 #endif 151 } 152 }; 153 154 155 /** 156 * Same interface as std::recursive_mutex. 157 */ 158 class recursive_mutex : public _base_mutex 159 { 160 public: 161 inline recursive_mutex(void)162 recursive_mutex(void) { 163 #ifdef _WIN32 164 InitializeCriticalSection(&_native_handle); 165 #else 166 pthread_mutexattr_t attr; 167 pthread_mutexattr_init(&attr); 168 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 169 pthread_mutex_init(&_native_handle, &attr); 170 pthread_mutexattr_destroy(&attr); 171 #endif 172 } 173 }; 174 175 176 /** 177 * Same interface as std::unique_lock; 178 */ 179 template< class Mutex > 180 class unique_lock 181 { 182 public: 183 typedef Mutex mutex_type; 184 185 inline explicit unique_lock(mutex_type & m)186 unique_lock(mutex_type &m) : 187 _mutex(m) 188 { 189 _mutex.lock(); 190 } 191 192 inline ~unique_lock()193 ~unique_lock() { 194 _mutex.unlock(); 195 } 196 197 inline void lock()198 lock() { 199 _mutex.lock(); 200 } 201 202 inline void unlock()203 unlock() { 204 _mutex.unlock(); 205 } 206 207 mutex_type * mutex() const208 mutex() const { 209 return &_mutex; 210 } 211 212 protected: 213 mutex_type &_mutex; 214 }; 215 216 217 /** 218 * Same interface as std::condition_variable 219 */ 220 class condition_variable 221 { 222 private: 223 #ifdef _WIN32 224 # ifdef HAVE_WIN32_CONDITION_VARIABLES 225 // Only supported on Vista an higher. Not yet supported by WINE. 226 typedef CONDITION_VARIABLE native_handle_type; 227 native_handle_type _native_handle; 228 #else 229 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html 230 LONG cWaiters; 231 enum { 232 EVENT_ONE = 0, 233 EVENT_ALL, 234 EVENT_COUNT 235 }; 236 HANDLE hEvents[EVENT_COUNT]; 237 #endif 238 #else 239 typedef pthread_cond_t native_handle_type; 240 native_handle_type _native_handle; 241 #endif 242 243 public: condition_variable()244 condition_variable() { 245 #ifdef _WIN32 246 # ifdef HAVE_WIN32_CONDITION_VARIABLES 247 InitializeConditionVariable(&_native_handle); 248 # else 249 cWaiters = 0; 250 hEvents[EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); 251 hEvents[EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); 252 # endif 253 #else 254 pthread_cond_init(&_native_handle, NULL); 255 #endif 256 } 257 ~condition_variable()258 ~condition_variable() { 259 #ifdef _WIN32 260 # ifdef HAVE_WIN32_CONDITION_VARIABLES 261 /* No-op */ 262 # else 263 CloseHandle(hEvents[EVENT_ALL]); 264 CloseHandle(hEvents[EVENT_ONE]); 265 # endif 266 #else 267 pthread_cond_destroy(&_native_handle); 268 #endif 269 } 270 271 inline void notify_one(void)272 notify_one(void) { 273 #ifdef _WIN32 274 # ifdef HAVE_WIN32_CONDITION_VARIABLES 275 WakeConditionVariable(&_native_handle); 276 # else 277 if (cWaiters) { 278 SetEvent(hEvents[EVENT_ONE]); 279 } 280 # endif 281 #else 282 pthread_cond_signal(&_native_handle); 283 #endif 284 } 285 286 inline void notify_all(void)287 notify_all(void) { 288 #ifdef _WIN32 289 # ifdef HAVE_WIN32_CONDITION_VARIABLES 290 WakeAllConditionVariable(&_native_handle); 291 # else 292 if (cWaiters) { 293 SetEvent(hEvents[EVENT_ALL]); 294 } 295 # endif 296 #else 297 pthread_cond_broadcast(&_native_handle); 298 #endif 299 } 300 301 inline void wait(unique_lock<mutex> & lock)302 wait(unique_lock<mutex> & lock) { 303 mutex::native_handle_type & mutex_native_handle = lock.mutex()->native_handle(); 304 #ifdef _WIN32 305 # ifdef HAVE_WIN32_CONDITION_VARIABLES 306 SleepConditionVariableCS(&_native_handle, &mutex_native_handle, INFINITE); 307 # else 308 InterlockedIncrement(&cWaiters); 309 LeaveCriticalSection(&mutex_native_handle); 310 DWORD dwResult; 311 dwResult = WaitForMultipleObjects(EVENT_COUNT, hEvents, FALSE, INFINITE); 312 EnterCriticalSection(&mutex_native_handle); 313 if (InterlockedDecrement(&cWaiters) == 0 && 314 dwResult == WAIT_OBJECT_0 + EVENT_ALL) { 315 ResetEvent(hEvents[EVENT_ALL]); 316 } 317 # endif 318 #else 319 pthread_cond_wait(&_native_handle, &mutex_native_handle); 320 #endif 321 } 322 323 inline void wait(unique_lock<mutex> & lock,std::function<bool ()> pred)324 wait(unique_lock<mutex> & lock, std::function<bool()> pred) { 325 while (!pred) { 326 wait(lock); 327 } 328 } 329 }; 330 331 332 /** 333 * Same interface as std::thread 334 */ 335 class thread { 336 public: 337 #ifdef _WIN32 338 typedef HANDLE native_handle_type; 339 #else 340 typedef pthread_t native_handle_type; 341 #endif 342 343 inline thread()344 thread() : 345 _native_handle(0) 346 { 347 } 348 349 inline thread(thread && other)350 thread(thread &&other) : 351 _native_handle(other._native_handle) 352 { 353 other._native_handle = 0; 354 } 355 356 thread(const thread &other) = delete; 357 358 inline ~thread()359 ~thread() { 360 } 361 362 static unsigned hardware_concurrency(void)363 hardware_concurrency(void) { 364 #ifdef _WIN32 365 SYSTEM_INFO si; 366 GetSystemInfo(&si); 367 return si.dwNumberOfProcessors; 368 #else 369 return sysconf(_SC_NPROCESSORS_ONLN); 370 #endif 371 } 372 373 template< class Function, class... Args > thread(Function && f,Args &&...args)374 explicit thread(Function &&f, Args&&... args) { 375 auto bound = std::bind(std::forward<Function>(f), std::forward<Args>(args)...); 376 auto data = new decltype(bound) (std::move(bound)); 377 _native_handle = _create(data); 378 } 379 380 inline thread & operator =(thread && other)381 operator =(thread &&other) { 382 assert(_native_handle == 0); 383 _native_handle = other._native_handle; 384 other._native_handle = 0; 385 return *this; 386 } 387 388 inline bool joinable(void) const389 joinable(void) const { 390 return _native_handle != 0; 391 } 392 393 inline void join()394 join() { 395 #ifdef _WIN32 396 WaitForSingleObject(_native_handle, INFINITE); 397 #else 398 pthread_join(_native_handle, NULL); 399 #endif 400 } 401 402 private: 403 native_handle_type _native_handle; 404 405 template< typename Param > 406 static 407 #ifdef _WIN32 408 unsigned __stdcall 409 #else 410 void * 411 #endif _callback(void * lpParameter)412 _callback(void *lpParameter) { 413 Param *pParam = static_cast<Param *>(lpParameter); 414 (*pParam)(); 415 delete pParam; 416 return 0; 417 } 418 419 template< typename Param > 420 static inline native_handle_type _create(Param * function)421 _create(Param *function) { 422 #ifdef _WIN32 423 uintptr_t handle =_beginthreadex(NULL, 0, &_callback<Param>, function, 0, NULL); 424 return reinterpret_cast<HANDLE>(handle); 425 #else 426 pthread_t t; 427 pthread_create(&t, NULL, &_callback<Param>, function); 428 return t; 429 #endif 430 } 431 }; 432 433 } /* namespace os */ 434 435 436 #endif /* !HAVE_CXX11_THREADS */ 437 438 439 /** 440 * Compiler TLS. 441 * 442 * It's not portable to use for DLLs on Windows XP, or non-POD types. 443 * 444 * See also: 445 * - http://gcc.gnu.org/onlinedocs/gcc-4.6.3/gcc/Thread_002dLocal.html 446 * - http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx 447 * - https://msdn.microsoft.com/en-us/library/y5f6w579.aspx 448 */ 449 #if defined(__GNUC__) 450 # define OS_THREAD_LOCAL __thread 451 #elif defined(_MSC_VER) 452 # define OS_THREAD_LOCAL __declspec(thread) 453 #else 454 # error Unsupported C++ compiler 455 #endif 456