1 /* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
2 Copyright (c) 2010-2012 Marcus Geelnard
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11 
12     1. The origin of this software must not be misrepresented; you must not
13     claim that you wrote the original software. If you use this software
14     in a product, an acknowledgment in the product documentation would be
15     appreciated but is not required.
16 
17     2. Altered source versions must be plainly marked as such, and must not be
18     misrepresented as being the original software.
19 
20     3. This notice may not be removed or altered from any source
21     distribution.
22 */
23 
24 #ifndef _TINYTHREAD_H_
25 #define _TINYTHREAD_H_
26 
27 /// @file
28 /// @mainpage TinyThread++ API Reference
29 ///
30 /// @section intro_sec Introduction
31 /// TinyThread++ is a minimal, portable implementation of basic threading
32 /// classes for C++.
33 ///
34 /// They closely mimic the functionality and naming of the C++11 standard, and
35 /// should be easily replaceable with the corresponding std:: variants.
36 ///
37 /// @section port_sec Portability
38 /// The Win32 variant uses the native Win32 API for implementing the thread
39 /// classes, while for other systems, the POSIX threads API (pthread) is used.
40 ///
41 /// @section class_sec Classes
42 /// In order to mimic the threading API of the C++11 standard, subsets of
43 /// several classes are provided. The fundamental classes are:
44 /// @li tthread::thread
45 /// @li tthread::mutex
46 /// @li tthread::recursive_mutex
47 /// @li tthread::condition_variable
48 /// @li tthread::lock_guard
49 /// @li tthread::fast_mutex
50 /// @li tthread::atomic
51 /// @li tthread::atomic_flag
52 ///
53 /// @section misc_sec Miscellaneous
54 /// The following special keywords are available: #thread_local.
55 ///
56 /// For more detailed information (including additional classes), browse the
57 /// different sections of this documentation. A good place to start is:
58 /// tinythread.h.
59 
60 // Which platform are we on?
61 #if !defined(_TTHREAD_PLATFORM_DEFINED_)
62   #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
63     #define _TTHREAD_WIN32_
64   #else
65     #define _TTHREAD_POSIX_
66   #endif
67   #define _TTHREAD_PLATFORM_DEFINED_
68 #endif
69 
70 // Platform specific includes
71 #if defined(_TTHREAD_WIN32_)
72   #ifndef WIN32_LEAN_AND_MEAN
73     #define WIN32_LEAN_AND_MEAN
74     #define __UNDEF_LEAN_AND_MEAN
75   #endif
76   #include <windows.h>
77   #ifdef __UNDEF_LEAN_AND_MEAN
78     #undef WIN32_LEAN_AND_MEAN
79     #undef __UNDEF_LEAN_AND_MEAN
80   #endif
81 #else
82   #include <pthread.h>
83   #include <signal.h>
84   #include <sched.h>
85   #include <unistd.h>
86 #endif
87 
88 // Generic includes
89 #include <ostream>
90 
91 /// TinyThread++ version (major number).
92 #define TINYTHREAD_VERSION_MAJOR 1
93 /// TinyThread++ version (minor number).
94 #define TINYTHREAD_VERSION_MINOR 2
95 /// TinyThread++ version (full version).
96 #define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR)
97 
98 // Do we have a fully featured C++11 compiler?
99 #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
100   #define _TTHREAD_CPP11_
101 #endif
102 
103 // ...at least partial C++11?
104 #if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
105   #define _TTHREAD_CPP11_PARTIAL_
106 #endif
107 
108 // Do we have atomic builtins?
109 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
110   #define _TTHREAD_HAS_ATOMIC_BUILTINS_
111 #endif
112 
113 // Check if we can support the assembly language atomic operations?
114 // Note: on MSVC, inline assembly is not supported on the ARM and x64 processors
115 // (see https://docs.microsoft.com/en-us/cpp/assembler/inline/inline-assembler)
116 #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \
117     (defined(_MSC_VER) && (defined(_M_IX86))) || \
118     (defined(__GNUC__) && (defined(__ppc__)))
119   #define _TTHREAD_HAS_ASM_ATOMICS_
120 #endif
121 
122 // Macro for disabling assignments of objects.
123 #ifdef _TTHREAD_CPP11_PARTIAL_
124   #define _TTHREAD_DISABLE_ASSIGNMENT(name) \
125       name(const name&) = delete; \
126       name& operator=(const name&) = delete;
127 #else
128   #define _TTHREAD_DISABLE_ASSIGNMENT(name) \
129       name(const name&); \
130       name& operator=(const name&);
131 #endif
132 
133 /// @def thread_local
134 /// Thread local storage keyword.
135 /// A variable that is declared with the @c thread_local keyword makes the
136 /// value of the variable local to each thread (known as thread-local storage,
137 /// or TLS). Example usage:
138 /// @code
139 /// // This variable is local to each thread.
140 /// thread_local int variable;
141 /// @endcode
142 /// @note The @c thread_local keyword is a macro that maps to the corresponding
143 /// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard
144 /// allows for non-trivial types (e.g. classes with constructors and
145 /// destructors) to be declared with the @c thread_local keyword, most pre-C++11
146 /// compilers only allow for trivial types (e.g. @c int). So, to guarantee
147 /// portable code, only use trivial types for thread local storage.
148 /// @note This directive is currently not supported on Mac OS X (it will give
149 /// a compiler error), since compile-time TLS is not supported in the Mac OS X
150 /// executable format. Also, some older versions of MinGW (before GCC 4.x) do
151 /// not support this directive.
152 /// @hideinitializer
153 
154 #if !defined(_TTHREAD_CPP11_) && !defined(thread_local)
155  #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
156   #define thread_local __thread
157  #else
158   #define thread_local __declspec(thread)
159  #endif
160 #endif
161 
162 
163 /// Main name space for TinyThread++.
164 /// This namespace is more or less equivalent to the @c std namespace for the
165 /// C++11 thread classes. For instance, the tthread::mutex class corresponds to
166 /// the std::mutex class.
167 namespace tthread {
168 
169 /// Mutex class.
170 /// This is a mutual exclusion object for synchronizing access to shared
171 /// memory areas for several threads. The mutex is non-recursive (i.e. a
172 /// program may deadlock if the thread that owns a mutex object calls lock()
173 /// on that object).
174 /// @see recursive_mutex
175 class mutex {
176   public:
177     /// Constructor.
mutex()178     mutex()
179 #if defined(_TTHREAD_WIN32_)
180       : mAlreadyLocked(false)
181 #endif
182     {
183 #if defined(_TTHREAD_WIN32_)
184       InitializeCriticalSection(&mHandle);
185 #else
186       pthread_mutex_init(&mHandle, NULL);
187 #endif
188     }
189 
190     /// Destructor.
~mutex()191     ~mutex()
192     {
193 #if defined(_TTHREAD_WIN32_)
194       DeleteCriticalSection(&mHandle);
195 #else
196       pthread_mutex_destroy(&mHandle);
197 #endif
198     }
199 
200     /// Lock the mutex.
201     /// The method will block the calling thread until a lock on the mutex can
202     /// be obtained. The mutex remains locked until @c unlock() is called.
203     /// @see lock_guard
lock()204     inline void lock()
205     {
206 #if defined(_TTHREAD_WIN32_)
207       EnterCriticalSection(&mHandle);
208       while(mAlreadyLocked) Sleep(1000); // Simulate deadlock...
209       mAlreadyLocked = true;
210 #else
211       pthread_mutex_lock(&mHandle);
212 #endif
213     }
214 
215     /// Try to lock the mutex.
216     /// The method will try to lock the mutex. If it fails, the function will
217     /// return immediately (non-blocking).
218     /// @return @c true if the lock was acquired, or @c false if the lock could
219     /// not be acquired.
try_lock()220     inline bool try_lock()
221     {
222 #if defined(_TTHREAD_WIN32_)
223       bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
224       if(ret && mAlreadyLocked)
225       {
226         LeaveCriticalSection(&mHandle);
227         ret = false;
228       }
229       return ret;
230 #else
231       return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
232 #endif
233     }
234 
235     /// Unlock the mutex.
236     /// If any threads are waiting for the lock on this mutex, one of them will
237     /// be unblocked.
unlock()238     inline void unlock()
239     {
240 #if defined(_TTHREAD_WIN32_)
241       mAlreadyLocked = false;
242       LeaveCriticalSection(&mHandle);
243 #else
244       pthread_mutex_unlock(&mHandle);
245 #endif
246     }
247 
248     _TTHREAD_DISABLE_ASSIGNMENT(mutex)
249 
250   private:
251 #if defined(_TTHREAD_WIN32_)
252     CRITICAL_SECTION mHandle;
253     bool mAlreadyLocked;
254 #else
255     pthread_mutex_t mHandle;
256 #endif
257 
258     friend class condition_variable;
259 };
260 
261 /// Recursive mutex class.
262 /// This is a mutual exclusion object for synchronizing access to shared
263 /// memory areas for several threads. The mutex is recursive (i.e. a thread
264 /// may lock the mutex several times, as long as it unlocks the mutex the same
265 /// number of times).
266 /// @see mutex
267 class recursive_mutex {
268   public:
269     /// Constructor.
recursive_mutex()270     recursive_mutex()
271     {
272 #if defined(_TTHREAD_WIN32_)
273       InitializeCriticalSection(&mHandle);
274 #else
275       pthread_mutexattr_t attr;
276       pthread_mutexattr_init(&attr);
277       pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
278       pthread_mutex_init(&mHandle, &attr);
279 #endif
280     }
281 
282     /// Destructor.
~recursive_mutex()283     ~recursive_mutex()
284     {
285 #if defined(_TTHREAD_WIN32_)
286       DeleteCriticalSection(&mHandle);
287 #else
288       pthread_mutex_destroy(&mHandle);
289 #endif
290     }
291 
292     /// Lock the mutex.
293     /// The method will block the calling thread until a lock on the mutex can
294     /// be obtained. The mutex remains locked until @c unlock() is called.
295     /// @see lock_guard
lock()296     inline void lock()
297     {
298 #if defined(_TTHREAD_WIN32_)
299       EnterCriticalSection(&mHandle);
300 #else
301       pthread_mutex_lock(&mHandle);
302 #endif
303     }
304 
305     /// Try to lock the mutex.
306     /// The method will try to lock the mutex. If it fails, the function will
307     /// return immediately (non-blocking).
308     /// @return @c true if the lock was acquired, or @c false if the lock could
309     /// not be acquired.
try_lock()310     inline bool try_lock()
311     {
312 #if defined(_TTHREAD_WIN32_)
313       return TryEnterCriticalSection(&mHandle) ? true : false;
314 #else
315       return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
316 #endif
317     }
318 
319     /// Unlock the mutex.
320     /// If any threads are waiting for the lock on this mutex, one of them will
321     /// be unblocked.
unlock()322     inline void unlock()
323     {
324 #if defined(_TTHREAD_WIN32_)
325       LeaveCriticalSection(&mHandle);
326 #else
327       pthread_mutex_unlock(&mHandle);
328 #endif
329     }
330 
331     _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex)
332 
333   private:
334 #if defined(_TTHREAD_WIN32_)
335     CRITICAL_SECTION mHandle;
336 #else
337     pthread_mutex_t mHandle;
338 #endif
339 
340     friend class condition_variable;
341 };
342 
343 /// Lock guard class.
344 /// The constructor locks the mutex, and the destructor unlocks the mutex, so
345 /// the mutex will automatically be unlocked when the lock guard goes out of
346 /// scope. Example usage:
347 /// @code
348 /// mutex m;
349 /// int counter;
350 ///
351 /// void increment()
352 /// {
353 ///   lock_guard<mutex> guard(m);
354 ///   ++ counter;
355 /// }
356 /// @endcode
357 
358 template <class T>
359 class lock_guard {
360   public:
361     typedef T mutex_type;
362 
lock_guard()363     lock_guard() : mMutex(0) {}
364 
365     /// The constructor locks the mutex.
lock_guard(mutex_type & aMutex)366     explicit lock_guard(mutex_type &aMutex)
367     {
368       mMutex = &aMutex;
369       mMutex->lock();
370     }
371 
372     /// The destructor unlocks the mutex.
~lock_guard()373     ~lock_guard()
374     {
375       if(mMutex)
376         mMutex->unlock();
377     }
378 
379   private:
380     mutex_type * mMutex;
381 };
382 
383 /// Condition variable class.
384 /// This is a signalling object for synchronizing the execution flow for
385 /// several threads. Example usage:
386 /// @code
387 /// // Shared data and associated mutex and condition variable objects
388 /// int count;
389 /// mutex m;
390 /// condition_variable cond;
391 ///
392 /// // Wait for the counter to reach a certain number
393 /// void wait_counter(int targetCount)
394 /// {
395 ///   lock_guard<mutex> guard(m);
396 ///   while(count < targetCount)
397 ///     cond.wait(m);
398 /// }
399 ///
400 /// // Increment the counter, and notify waiting threads
401 /// void increment()
402 /// {
403 ///   lock_guard<mutex> guard(m);
404 ///   ++ count;
405 ///   cond.notify_all();
406 /// }
407 /// @endcode
408 class condition_variable {
409   public:
410     /// Constructor.
411 #if defined(_TTHREAD_WIN32_)
412     condition_variable();
413 #else
414     condition_variable()
415     {
416       pthread_cond_init(&mHandle, NULL);
417     }
418 #endif
419 
420     /// Destructor.
421 #if defined(_TTHREAD_WIN32_)
422     ~condition_variable();
423 #else
~condition_variable()424     ~condition_variable()
425     {
426       pthread_cond_destroy(&mHandle);
427     }
428 #endif
429 
430     /// Wait for the condition.
431     /// The function will block the calling thread until the condition variable
432     /// is woken by @c notify_one(), @c notify_all() or a spurious wake up.
433     /// @param[in] aMutex A mutex that will be unlocked when the wait operation
434     ///   starts, an locked again as soon as the wait operation is finished.
435     template <class _mutexT>
wait(_mutexT & aMutex)436     inline void wait(_mutexT &aMutex)
437     {
438 #if defined(_TTHREAD_WIN32_)
439       // Increment number of waiters
440       EnterCriticalSection(&mWaitersCountLock);
441       ++ mWaitersCount;
442       LeaveCriticalSection(&mWaitersCountLock);
443 
444       // Release the mutex while waiting for the condition (will decrease
445       // the number of waiters when done)...
446       aMutex.unlock();
447       _wait();
448       aMutex.lock();
449 #else
450       pthread_cond_wait(&mHandle, &aMutex.mHandle);
451 #endif
452     }
453 
454     /// Notify one thread that is waiting for the condition.
455     /// If at least one thread is blocked waiting for this condition variable,
456     /// one will be woken up.
457     /// @note Only threads that started waiting prior to this call will be
458     /// woken up.
459 #if defined(_TTHREAD_WIN32_)
460     void notify_one();
461 #else
notify_one()462     inline void notify_one()
463     {
464       pthread_cond_signal(&mHandle);
465     }
466 #endif
467 
468     /// Notify all threads that are waiting for the condition.
469     /// All threads that are blocked waiting for this condition variable will
470     /// be woken up.
471     /// @note Only threads that started waiting prior to this call will be
472     /// woken up.
473 #if defined(_TTHREAD_WIN32_)
474     void notify_all();
475 #else
notify_all()476     inline void notify_all()
477     {
478       pthread_cond_broadcast(&mHandle);
479     }
480 #endif
481 
482     _TTHREAD_DISABLE_ASSIGNMENT(condition_variable)
483 
484   private:
485 #if defined(_TTHREAD_WIN32_)
486     void _wait();
487     HANDLE mEvents[2];                  ///< Signal and broadcast event HANDLEs.
488     unsigned int mWaitersCount;         ///< Count of the number of waiters.
489     CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
490 #else
491     pthread_cond_t mHandle;
492 #endif
493 };
494 
495 /// Memory access order.
496 /// Specifies how non-atomic memory accesses are to be ordered around an atomic
497 /// operation.
498 enum memory_order {
499   memory_order_relaxed, ///< Relaxed ordering: there are no constraints on
500                         ///  reordering of memory accesses around the atomic
501                         ///  variable.
502   memory_order_consume, ///< Consume operation: no reads in the current thread
503                         ///  dependent on the value currently loaded can be
504                         ///  reordered before this load. This ensures that
505                         ///  writes to dependent variables in other threads
506                         ///  that release the same atomic variable are visible
507                         ///  in the current thread. On most platforms, this
508                         ///  affects compiler optimization only.
509   memory_order_acquire, ///< Acquire operation: no reads in the current thread
510                         ///  can be reordered before this load. This ensures
511                         ///  that all writes in other threads that release the
512                         ///  same atomic variable are visible in the current
513                         ///  thread.
514   memory_order_release, ///< Release operation: no writes in the current thread
515                         ///  can be reordered after this store. This ensures
516                         ///  that all writes in the current thread are visible
517                         ///  in other threads that acquire the same atomic
518                         ///  variable.
519   memory_order_acq_rel, ///< Acquire-release operation: no reads in the current
520                         ///  thread can be reordered before this load as well
521                         ///  as no writes in the current thread can be
522                         ///  reordered after this store. The operation is
523                         ///  read-modify-write operation. It is ensured that
524                         ///  all writes in another threads that release the
525                         ///  same atomic variable are visible before the
526                         ///  modification and the modification is visible in
527                         ///  other threads that acquire the same atomic
528                         ///  variable.
529   memory_order_seq_cst  ///< Sequential ordering: The operation has the same
530                         ///  semantics as acquire-release operation, and
531                         ///  additionally has sequentially-consistent operation
532                         ///  ordering.
533 };
534 
535 /// Expression which can be used to initialize atomic_flag to clear state.
536 /// Example usage:
537 /// \code{.cpp}
538 /// tthread::atomic_flag myFlag(ATOMIC_FLAG_INIT);
539 /// \endcode
540 #define ATOMIC_FLAG_INIT 0
541 
542 /// Atomic flag class.
543 /// This is an atomic boolean object that provides methods for atmically
544 /// testing, setting and clearing the state of the object. It can be used
545 /// for implementing user space spin-locks, for instance.
546 class atomic_flag {
547   public:
atomic_flag()548     atomic_flag() : mFlag(0)
549     {
550     }
551 
atomic_flag(int value)552     atomic_flag(int value) : mFlag(value)
553     {
554     }
555 
556     /// Atomically test and set the value.
557     /// @param order The memory sycnhronization ordering for this operation.
558     /// @return The value held before this operation.
559     inline bool test_and_set(memory_order order = memory_order_seq_cst)
560     {
561       (void)order;
562 #if defined(_TTHREAD_HAS_ATOMIC_BUILTINS_)
563       return static_cast<bool>(__sync_lock_test_and_set(&mFlag, 1));
564 #elif defined(_TTHREAD_HAS_ASM_ATOMICS_)
565       int result;
566   #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
567       asm volatile (
568         "movl $1,%%eax\n\t"
569         "xchg %%eax,%0\n\t"
570         "movl %%eax,%1\n\t"
571         : "=m" (mFlag), "=m" (result)
572         :
573         : "%eax", "memory"
574       );
575   #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
576       int *ptrFlag = &mFlag;
577       __asm {
578         mov eax,1
579         mov ecx,ptrFlag
580         xchg eax,[ecx]
581         mov result,eax
582       }
583   #elif defined(__GNUC__) && (defined(__ppc__))
584       int newFlag = 1;
585       asm volatile (
586         "\n1:\n\t"
587         "lwarx  %0,0,%1\n\t"
588         "cmpwi  0,%0,0\n\t"
589         "bne-   2f\n\t"
590         "stwcx. %2,0,%1\n\t"
591         "bne-   1b\n\t"
592         "isync\n"
593         "2:\n\t"
594         : "=&r" (result)
595         : "r" (&mFlag), "r" (newFlag)
596         : "cr0", "memory"
597       );
598   #endif
599       return static_cast<bool>(result);
600 #else
601       lock_guard<mutex> guard(mLock);
602       int result = mFlag;
603       mFlag = 1;
604       return static_cast<bool>(result);
605 #endif
606     }
607 
608     /// Atomically changes the state to cleared (false).
609     /// @param order The memory sycnhronization ordering for this operation.
610     inline void clear(memory_order order = memory_order_seq_cst)
611     {
612       (void)order;
613 #if defined(_TTHREAD_HAS_ATOMIC_BUILTINS_)
614       __sync_lock_release(&mFlag);
615 #elif defined(_TTHREAD_HAS_ASM_ATOMICS_)
616   #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
617       asm volatile (
618         "movl $0,%%eax\n\t"
619         "xchg %%eax,%0\n\t"
620         : "=m" (mFlag)
621         :
622         : "%eax", "memory"
623       );
624   #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
625       int *ptrFlag = &mFlag;
626       __asm {
627         mov eax,0
628         mov ecx,ptrFlag
629         xchg eax,[ecx]
630       }
631   #elif defined(__GNUC__) && (defined(__ppc__))
632       asm volatile (
633         "sync\n\t"  // Replace with lwsync where possible?
634         : : : "memory"
635       );
636       mFlag = 0;
637   #endif
638 #else
639       lock_guard<mutex> guard(mLock);
640       mFlag = 0;
641 #endif
642     }
643 
644     _TTHREAD_DISABLE_ASSIGNMENT(atomic_flag)
645 
646   private:
647 #if !(defined(_TTHREAD_HAS_ATOMIC_BUILTINS_) || defined(_TTHREAD_HAS_ASM_ATOMICS_))
648     mutex mLock;
649 #endif // !(_TTHREAD_HAS_ATOMIC_BUILTINS_ || _TTHREAD_HAS_ASM_ATOMICS_)
650     volatile int mFlag;
651 };
652 
653 
654 /// Atomic template class.
655 /// An atomic object provides atomic access to an underlying data element of
656 /// the template type T.
657 template<class T>
658 struct atomic {
659   public:
atomicatomic660     atomic() : mValue(0)
661     {
662     }
663 
atomicatomic664     atomic(T desired) : mValue(desired)
665     {
666     }
667 
668     /// Checks whether the atomic operations on the object are lock-free.
is_lock_freeatomic669     inline bool is_lock_free() const
670     {
671 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_
672       return true;
673 #else
674       return false;
675 #endif
676     }
677 
678     /// Atomically replaces the current value.
679     /// @param desired The new value.
680     /// @param order The memory sycnhronization ordering for this operation.
681     inline void store(T desired, memory_order order = memory_order_seq_cst)
682     {
683       (void)order;
684 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_
685       // FIXME: Use something more suitable here
686       __sync_lock_test_and_set(&mValue, desired);
687 #else
688       lock_guard<mutex> guard(mLock);
689       mValue = desired;
690 #endif
691     }
692 
693     /// Atomically loads the current value.
694     /// @param order The memory sycnhronization ordering for this operation.
695     inline T load(memory_order order = memory_order_seq_cst) const
696     {
697       (void)order;
698 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_
699       // FIXME: Use something more suitable here
700       return __sync_add_and_fetch((volatile T*)&mValue, 0);
701 #else
702       lock_guard<mutex> guard(mLock);
703       return mValue;
704 #endif
705     }
706 
707     /// Atomically increments the current value.
708     /// Atomically replaces the current value with the result of arithmetic
709     /// addition of the value and arg. The operation is a read-modify-write
710     /// operation.
711     /// @param arg The value to be added to the current value.
712     /// @param order The memory sycnhronization ordering for this operation.
713     inline T fetch_add(T arg, memory_order order = memory_order_seq_cst)
714     {
715       (void)order;
716 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_
717       return __sync_fetch_and_add(&mValue, arg);
718 #else
719       lock_guard<mutex> guard(mLock);
720       T result = mValue;
721       mValue += arg;
722       return result;
723 #endif
724     }
725 
726     /// Atomically decrements the current value.
727     /// Atomically replaces the current value with the result of arithmetic
728     /// subtraction of the value and arg. The operation is a read-modify-write
729     /// operation.
730     /// @param arg The value to be subtracted from the current value.
731     /// @param order The memory sycnhronization ordering for this operation.
732     inline T fetch_sub(T arg, memory_order order = memory_order_seq_cst)
733     {
734       (void)order;
735 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_
736       return __sync_fetch_and_sub(&mValue, arg);
737 #else
738       lock_guard<mutex> guard(mLock);
739       T result = mValue;
740       mValue -= arg;
741       return result;
742 #endif
743     }
744 
745     /// Atomically replaces the current value.
746     /// Equivalent to store(desired).
747     /// @param desired The new value.
748     /// @return The new value.
749     inline T operator=(T desired)
750     {
751       store(desired);
752       return desired;
753     }
754 
755     /// Atomically loads the current value.
756     /// Equivalent to load().
757     /// @return The current value.
Tatomic758     inline operator T() const
759     {
760       return load();
761     }
762 
763     /// Atomic post-increment.
764     /// Equivalent to fetch_add(1) + 1.
765     /// @return The value after the increment operation.
766     inline T operator++()
767     {
768       return fetch_add(1) + 1;
769     }
770 
771     /// Atomic pre-increment.
772     /// Equivalent to fetch_add(1).
773     /// @return The value before the increment operation.
774     inline T operator++(int)
775     {
776       return fetch_add(1);
777     }
778 
779     /// Atomic post-decrement.
780     /// Equivalent to fetch_sub(1) - 1.
781     /// @return The value a the decrement operation.
782     inline T operator--()
783     {
784       return fetch_sub(1) - 1;
785     }
786 
787     /// Atomic pre-decrement.
788     /// Equivalent to fetch_sub(1).
789     /// @return The value before the decrement operation.
790     inline T operator--(int)
791     {
792       return fetch_sub(1);
793     }
794 
795     _TTHREAD_DISABLE_ASSIGNMENT(atomic<T>)
796 
797   private:
798 #ifndef _TTHREAD_HAS_ATOMIC_BUILTINS_
799     mutable mutex mLock;
800 #endif // _TTHREAD_HAS_ATOMIC_BUILTINS_
801     volatile T mValue;
802 };
803 
804 typedef atomic<char>               atomic_char;   ///< Specialized atomic for type char.
805 typedef atomic<signed char>        atomic_schar;  ///< Specialized atomic for type signed char.
806 typedef atomic<unsigned char>      atomic_uchar;  ///< Specialized atomic for type unsigned char.
807 typedef atomic<short>              atomic_short;  ///< Specialized atomic for type short.
808 typedef atomic<unsigned short>     atomic_ushort; ///< Specialized atomic for type unsigned short.
809 typedef atomic<int>                atomic_int;    ///< Specialized atomic for type int.
810 typedef atomic<unsigned int>       atomic_uint;   ///< Specialized atomic for type unsigned int.
811 typedef atomic<long>               atomic_long;   ///< Specialized atomic for type long.
812 typedef atomic<unsigned long>      atomic_ulong;  ///< Specialized atomic for type unsigned long.
813 typedef atomic<long long>          atomic_llong;  ///< Specialized atomic for type long long.
814 typedef atomic<unsigned long long> atomic_ullong; ///< Specialized atomic for type unsigned long long.
815 
816 /// Thread class.
817 class thread {
818   public:
819 #if defined(_TTHREAD_WIN32_)
820     typedef HANDLE native_handle_type;
821 #else
822     typedef pthread_t native_handle_type;
823 #endif
824 
825     class id;
826 
827     /// Default constructor.
828     /// Construct a @c thread object without an associated thread of execution
829     /// (i.e. non-joinable).
thread()830     thread() : mHandle(0), mWrapper(0)
831 #if defined(_TTHREAD_WIN32_)
832     , mWin32ThreadID(0)
833 #endif
834     {}
835 
836     /// Thread starting constructor.
837     /// Construct a @c thread object with a new thread of execution.
838     /// @param[in] aFunction A function pointer to a function of type:
839     ///          <tt>void fun(void * arg)</tt>
840     /// @param[in] aArg Argument to the thread function.
841     /// @note This constructor is not fully compatible with the standard C++
842     /// thread class. It is more similar to the pthread_create() (POSIX) and
843     /// CreateThread() (Windows) functions.
844     thread(void (*aFunction)(void *), void * aArg);
845 
846     /// Destructor.
847     /// @note If the thread is joinable upon destruction, @c std::terminate()
848     /// will be called, which terminates the process. It is always wise to do
849     /// @c join() before deleting a thread object.
850     ~thread();
851 
852     /// Wait for the thread to finish (join execution flows).
853     /// After calling @c join(), the thread object is no longer associated with
854     /// a thread of execution (i.e. it is not joinable, and you may not join
855     /// with it nor detach from it).
856     void join();
857 
858     /// Check if the thread is joinable.
859     /// A thread object is joinable if it has an associated thread of execution.
860     bool joinable() const;
861 
862     /// Detach from the thread.
863     /// After calling @c detach(), the thread object is no longer assicated with
864     /// a thread of execution (i.e. it is not joinable). The thread continues
865     /// execution without the calling thread blocking, and when the thread
866     /// ends execution, any owned resources are released.
867     void detach();
868 
869     /// Return the thread ID of a thread object.
870     id get_id() const;
871 
872     /// Get the native handle for this thread.
873     /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this
874     /// is a @c pthread_t.
native_handle()875     inline native_handle_type native_handle()
876     {
877       return mHandle;
878     }
879 
880     /// Determine the number of threads which can possibly execute concurrently.
881     /// This function is useful for determining the optimal number of threads to
882     /// use for a task.
883     /// @return The number of hardware thread contexts in the system.
884     /// @note If this value is not defined, the function returns zero (0).
885     static unsigned hardware_concurrency();
886 
887     _TTHREAD_DISABLE_ASSIGNMENT(thread)
888 
889   private:
890     native_handle_type mHandle;   ///< Thread handle.
891     void * mWrapper;              ///< Thread wrapper info.
892 #if defined(_TTHREAD_WIN32_)
893     unsigned int mWin32ThreadID;  ///< Unique thread ID (filled out by _beginthreadex).
894 #endif
895 
896     // This is the internal thread wrapper function.
897 #if defined(_TTHREAD_WIN32_)
898     static unsigned WINAPI wrapper_function(void * aArg);
899 #else
900     static void * wrapper_function(void * aArg);
901 #endif
902 };
903 
904 /// Thread ID.
905 /// The thread ID is a unique identifier for each thread.
906 /// @see thread::get_id()
907 class thread::id {
908   public:
909     /// Default constructor.
910     /// The default constructed ID is that of thread without a thread of
911     /// execution.
id()912     id() : mId(0) {};
913 
id(unsigned long int aId)914     id(unsigned long int aId) : mId(aId) {};
915 
id(const id & aId)916     id(const id& aId) : mId(aId.mId) {};
917 
918     inline id & operator=(const id &aId)
919     {
920       mId = aId.mId;
921       return *this;
922     }
923 
924     inline friend bool operator==(const id &aId1, const id &aId2)
925     {
926       return (aId1.mId == aId2.mId);
927     }
928 
929     inline friend bool operator!=(const id &aId1, const id &aId2)
930     {
931       return (aId1.mId != aId2.mId);
932     }
933 
934     inline friend bool operator<=(const id &aId1, const id &aId2)
935     {
936       return (aId1.mId <= aId2.mId);
937     }
938 
939     inline friend bool operator<(const id &aId1, const id &aId2)
940     {
941       return (aId1.mId < aId2.mId);
942     }
943 
944     inline friend bool operator>=(const id &aId1, const id &aId2)
945     {
946       return (aId1.mId >= aId2.mId);
947     }
948 
949     inline friend bool operator>(const id &aId1, const id &aId2)
950     {
951       return (aId1.mId > aId2.mId);
952     }
953 
954     inline friend std::ostream& operator <<(std::ostream &os, const id &obj)
955     {
956       os << obj.mId;
957       return os;
958     }
959 
960   private:
961     unsigned long int mId;
962 };
963 
964 
965 // Related to <ratio> - minimal to be able to support chrono.
966 typedef long long __intmax_t;
967 
968 /// Minimal implementation of the @c ratio class. This class provides enough
969 /// functionality to implement some basic @c chrono classes.
970 template <__intmax_t N, __intmax_t D = 1> class ratio {
971   public:
_as_double()972     static double _as_double() { return double(N) / double(D); }
973 };
974 
975 /// Minimal implementation of the @c chrono namespace.
976 /// The @c chrono namespace provides types for specifying time intervals.
977 namespace chrono {
978   /// Duration template class. This class provides enough functionality to
979   /// implement @c this_thread::sleep_for().
980   template <class _Rep, class _Period = ratio<1> > class duration {
981     private:
982       _Rep rep_;
983     public:
984       typedef _Rep rep;
985       typedef _Period period;
986 
987       /// Construct a duration object with the given duration.
988       template <class _Rep2>
duration(const _Rep2 & r)989         explicit duration(const _Rep2& r) : rep_(r) {};
990 
991       /// Return the value of the duration object.
count()992       rep count() const
993       {
994         return rep_;
995       }
996   };
997 
998   // Standard duration types.
999   typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds.
1000   typedef duration<__intmax_t, ratio<1, 1000000> > microseconds;   ///< Duration with the unit microseconds.
1001   typedef duration<__intmax_t, ratio<1, 1000> > milliseconds;      ///< Duration with the unit milliseconds.
1002   typedef duration<__intmax_t> seconds;                            ///< Duration with the unit seconds.
1003   typedef duration<__intmax_t, ratio<60> > minutes;                ///< Duration with the unit minutes.
1004   typedef duration<__intmax_t, ratio<3600> > hours;                ///< Duration with the unit hours.
1005 }
1006 
1007 /// The namespace @c this_thread provides methods for dealing with the
1008 /// calling thread.
1009 namespace this_thread {
1010   /// Return the thread ID of the calling thread.
1011   thread::id get_id();
1012 
1013   /// Yield execution to another thread.
1014   /// Offers the operating system the opportunity to schedule another thread
1015   /// that is ready to run on the current processor.
yield()1016   inline void yield()
1017   {
1018 #if defined(_TTHREAD_WIN32_)
1019     Sleep(0);
1020 #else
1021     sched_yield();
1022 #endif
1023   }
1024 
1025   /// Blocks the calling thread for a period of time.
1026   /// @param[in] aTime Minimum time to put the thread to sleep.
1027   /// Example usage:
1028   /// @code
1029   /// // Sleep for 100 milliseconds
1030   /// this_thread::sleep_for(chrono::milliseconds(100));
1031   /// @endcode
1032   /// @note Supported duration types are: nanoseconds, microseconds,
1033   /// milliseconds, seconds, minutes and hours.
sleep_for(const chrono::duration<_Rep,_Period> & aTime)1034   template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime)
1035   {
1036 #if defined(_TTHREAD_WIN32_)
1037     Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5));
1038 #else
1039     usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5));
1040 #endif
1041   }
1042 }
1043 
1044 }
1045 
1046 // Define/macro cleanup
1047 #undef _TTHREAD_DISABLE_ASSIGNMENT
1048 
1049 #endif // _TINYTHREAD_H_
1050