You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
6.6 KiB

  1. /*
  2. Copyright 2005-2014 Intel Corporation. All Rights Reserved.
  3. This file is part of Threading Building Blocks.
  4. Threading Building Blocks is free software; you can redistribute it
  5. and/or modify it under the terms of the GNU General Public License
  6. version 2 as published by the Free Software Foundation.
  7. Threading Building Blocks is distributed in the hope that it will be
  8. useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  9. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with Threading Building Blocks; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  14. As a special exception, you may use this file as part of a free software
  15. library without restriction. Specifically, if other files instantiate
  16. templates or use macros or inline functions from this file, or you compile
  17. this file and link it with other files to produce an executable, this
  18. file does not by itself cause the resulting executable to be covered by
  19. the GNU General Public License. This exception does not however
  20. invalidate any other reasons why the executable file might be covered by
  21. the GNU General Public License.
  22. */
  23. #ifndef __TBB_mutex_H
  24. #define __TBB_mutex_H
  25. #if _WIN32||_WIN64
  26. #include "machine/windows_api.h"
  27. #else
  28. #include <pthread.h>
  29. #endif /* _WIN32||_WIN64 */
  30. #include <new>
  31. #include "aligned_space.h"
  32. #include "tbb_stddef.h"
  33. #include "tbb_profiling.h"
  34. namespace tbb {
  35. //! Wrapper around the platform's native reader-writer lock.
  36. /** For testing purposes only.
  37. @ingroup synchronization */
  38. class mutex {
  39. public:
  40. //! Construct unacquired mutex.
  41. mutex() {
  42. #if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS
  43. internal_construct();
  44. #else
  45. #if _WIN32||_WIN64
  46. InitializeCriticalSectionEx(&impl, 4000, 0);
  47. #else
  48. int error_code = pthread_mutex_init(&impl,NULL);
  49. if( error_code )
  50. tbb::internal::handle_perror(error_code,"mutex: pthread_mutex_init failed");
  51. #endif /* _WIN32||_WIN64*/
  52. #endif /* TBB_USE_ASSERT */
  53. };
  54. ~mutex() {
  55. #if TBB_USE_ASSERT
  56. internal_destroy();
  57. #else
  58. #if _WIN32||_WIN64
  59. DeleteCriticalSection(&impl);
  60. #else
  61. pthread_mutex_destroy(&impl);
  62. #endif /* _WIN32||_WIN64 */
  63. #endif /* TBB_USE_ASSERT */
  64. };
  65. class scoped_lock;
  66. friend class scoped_lock;
  67. //! The scoped locking pattern
  68. /** It helps to avoid the common problem of forgetting to release lock.
  69. It also nicely provides the "node" for queuing locks. */
  70. class scoped_lock : internal::no_copy {
  71. public:
  72. //! Construct lock that has not acquired a mutex.
  73. scoped_lock() : my_mutex(NULL) {};
  74. //! Acquire lock on given mutex.
  75. scoped_lock( mutex& mutex ) {
  76. acquire( mutex );
  77. }
  78. //! Release lock (if lock is held).
  79. ~scoped_lock() {
  80. if( my_mutex )
  81. release();
  82. }
  83. //! Acquire lock on given mutex.
  84. void acquire( mutex& mutex ) {
  85. #if TBB_USE_ASSERT
  86. internal_acquire(mutex);
  87. #else
  88. mutex.lock();
  89. my_mutex = &mutex;
  90. #endif /* TBB_USE_ASSERT */
  91. }
  92. //! Try acquire lock on given mutex.
  93. bool try_acquire( mutex& mutex ) {
  94. #if TBB_USE_ASSERT
  95. return internal_try_acquire (mutex);
  96. #else
  97. bool result = mutex.try_lock();
  98. if( result )
  99. my_mutex = &mutex;
  100. return result;
  101. #endif /* TBB_USE_ASSERT */
  102. }
  103. //! Release lock
  104. void release() {
  105. #if TBB_USE_ASSERT
  106. internal_release ();
  107. #else
  108. my_mutex->unlock();
  109. my_mutex = NULL;
  110. #endif /* TBB_USE_ASSERT */
  111. }
  112. private:
  113. //! The pointer to the current mutex to work
  114. mutex* my_mutex;
  115. //! All checks from acquire using mutex.state were moved here
  116. void __TBB_EXPORTED_METHOD internal_acquire( mutex& m );
  117. //! All checks from try_acquire using mutex.state were moved here
  118. bool __TBB_EXPORTED_METHOD internal_try_acquire( mutex& m );
  119. //! All checks from release using mutex.state were moved here
  120. void __TBB_EXPORTED_METHOD internal_release();
  121. friend class mutex;
  122. };
  123. // Mutex traits
  124. static const bool is_rw_mutex = false;
  125. static const bool is_recursive_mutex = false;
  126. static const bool is_fair_mutex = false;
  127. // ISO C++0x compatibility methods
  128. //! Acquire lock
  129. void lock() {
  130. #if TBB_USE_ASSERT
  131. aligned_space<scoped_lock,1> tmp;
  132. new(tmp.begin()) scoped_lock(*this);
  133. #else
  134. #if _WIN32||_WIN64
  135. EnterCriticalSection(&impl);
  136. #else
  137. pthread_mutex_lock(&impl);
  138. #endif /* _WIN32||_WIN64 */
  139. #endif /* TBB_USE_ASSERT */
  140. }
  141. //! Try acquiring lock (non-blocking)
  142. /** Return true if lock acquired; false otherwise. */
  143. bool try_lock() {
  144. #if TBB_USE_ASSERT
  145. aligned_space<scoped_lock,1> tmp;
  146. scoped_lock& s = *tmp.begin();
  147. s.my_mutex = NULL;
  148. return s.internal_try_acquire(*this);
  149. #else
  150. #if _WIN32||_WIN64
  151. return TryEnterCriticalSection(&impl)!=0;
  152. #else
  153. return pthread_mutex_trylock(&impl)==0;
  154. #endif /* _WIN32||_WIN64 */
  155. #endif /* TBB_USE_ASSERT */
  156. }
  157. //! Release lock
  158. void unlock() {
  159. #if TBB_USE_ASSERT
  160. aligned_space<scoped_lock,1> tmp;
  161. scoped_lock& s = *tmp.begin();
  162. s.my_mutex = this;
  163. s.internal_release();
  164. #else
  165. #if _WIN32||_WIN64
  166. LeaveCriticalSection(&impl);
  167. #else
  168. pthread_mutex_unlock(&impl);
  169. #endif /* _WIN32||_WIN64 */
  170. #endif /* TBB_USE_ASSERT */
  171. }
  172. //! Return native_handle
  173. #if _WIN32||_WIN64
  174. typedef LPCRITICAL_SECTION native_handle_type;
  175. #else
  176. typedef pthread_mutex_t* native_handle_type;
  177. #endif
  178. native_handle_type native_handle() { return (native_handle_type) &impl; }
  179. enum state_t {
  180. INITIALIZED=0x1234,
  181. DESTROYED=0x789A,
  182. HELD=0x56CD
  183. };
  184. private:
  185. #if _WIN32||_WIN64
  186. CRITICAL_SECTION impl;
  187. enum state_t state;
  188. #else
  189. pthread_mutex_t impl;
  190. #endif /* _WIN32||_WIN64 */
  191. //! All checks from mutex constructor using mutex.state were moved here
  192. void __TBB_EXPORTED_METHOD internal_construct();
  193. //! All checks from mutex destructor using mutex.state were moved here
  194. void __TBB_EXPORTED_METHOD internal_destroy();
  195. #if _WIN32||_WIN64
  196. public:
  197. //! Set the internal state
  198. void set_state( state_t to ) { state = to; }
  199. #endif
  200. };
  201. __TBB_DEFINE_PROFILING_SET_NAME(mutex)
  202. } // namespace tbb
  203. #endif /* __TBB_mutex_H */