fast_mutex.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  2. // vim:tabstop=4:shiftwidth=4:expandtab:
  3. /*
  4. * Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
  5. *
  6. * This software is provided 'as-is', without any express or implied
  7. * warranty. In no event will the authors be held liable for any
  8. * damages arising from the use of this software.
  9. *
  10. * Permission is granted to anyone to use this software for any purpose,
  11. * including commercial applications, and to alter it and redistribute
  12. * it freely, subject to the following restrictions:
  13. *
  14. * 1. The origin of this software must not be misrepresented; you must
  15. * not claim that you wrote the original software. If you use this
  16. * software in a product, an acknowledgement in the product
  17. * documentation would be appreciated but is not required.
  18. * 2. Altered source versions must be plainly marked as such, and must
  19. * not be misrepresented as being the original software.
  20. * 3. This notice may not be removed or altered from any source
  21. * distribution.
  22. *
  23. * This file is part of Stones of Nvwa:
  24. * http://sourceforge.net/projects/nvwa
  25. *
  26. */
  27. /*!
  28. * \file fast_mutex.h
  29. * \ingroup QxMemLeak
  30. *
  31. * A fast mutex implementation for POSIX and Win32.
  32. *
  33. * \version 1.18, 2005/05/06
  34. * \author Wu Yongwei
  35. *
  36. */
  37. #ifndef QT_NO_DEBUG
  38. #ifndef _QX_MODE_RELEASE
  39. #if _QX_USE_MEM_LEAK_DETECTION
  40. #ifndef _FAST_MUTEX_H
  41. #define _FAST_MUTEX_H
  42. #ifdef _MSC_VER
  43. #pragma once
  44. #endif
  45. # if !defined(_NOTHREADS)
  46. # if !defined(_WIN32THREADS) && \
  47. (defined(_WIN32) && defined(_MT))
  48. // Automatically use _WIN32THREADS when specifying -MT/-MD in MSVC,
  49. // or -mthreads in MinGW GCC.
  50. # define _WIN32THREADS
  51. # elif !defined(_PTHREADS) && \
  52. defined(_REENTRANT)
  53. // Automatically use _PTHREADS when specifying -pthread in GCC.
  54. // N.B. I do not detect on _PTHREAD_H since libstdc++-v3 under
  55. // Linux will silently include <pthread.h> anyway.
  56. # define _PTHREADS
  57. # endif
  58. # endif
  59. # if !defined(_PTHREADS) && !defined(_WIN32THREADS) && !defined(_NOTHREADS)
  60. # define _NOTHREADS
  61. # endif
  62. # if defined(_NOTHREADS)
  63. # if defined(_PTHREADS) || defined(_WIN32THREADS)
  64. # undef _NOTHREADS
  65. # error "Cannot define multi-threaded mode with -D_NOTHREADS"
  66. # if defined(__MINGW32__) && defined(_WIN32THREADS) && !defined(_MT)
  67. # error "Be sure to specify -mthreads with -D_WIN32THREADS"
  68. # endif
  69. # endif
  70. # endif
  71. # ifndef _FAST_MUTEX_CHECK_INITIALIZATION
  72. /**
  73. * Macro to control whether to check for initialization status for each
  74. * lock/unlock operation. Defining it to a non-zero value will enable
  75. * the check, so that the construction/destruction of a static object
  76. * using a static fast_mutex not yet constructed or already destroyed
  77. * will work (with lock/unlock operations ignored). Defining it to zero
  78. * will disable to check.
  79. */
  80. # define _FAST_MUTEX_CHECK_INITIALIZATION 1
  81. # endif
  82. # if defined(_PTHREADS) && defined(_WIN32THREADS)
  83. // Some C++ libraries have _PTHREADS defined even on Win32 platforms.
  84. // Thus this hack.
  85. # undef _PTHREADS
  86. # endif
  87. #ifndef _QX_MODE_RELEASE
  88. #ifndef QT_NO_DEBUG
  89. # include <stdio.h>
  90. # include <stdlib.h>
  91. /** Macro for fast_mutex assertions. Real version (for debug mode). */
  92. # define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
  93. if (!(_Expr)) { \
  94. fprintf(stderr, "fast_mutex::%s\n", _Msg); \
  95. abort(); \
  96. }
  97. #else
  98. /** Macro for fast_mutex assertions. Fake version (for release mode). */
  99. # define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
  100. ((void)0)
  101. #endif // QT_NO_DEBUG
  102. #endif // _QX_MODE_RELEASE
  103. # ifdef _PTHREADS
  104. # include <pthread.h>
  105. /**
  106. * Macro alias to `volatile' semantics. Here it is truly volatile since
  107. * it is in a multi-threaded (POSIX threads) environment.
  108. */
  109. # define __VOLATILE volatile
  110. /**
  111. * Class for non-reentrant fast mutexes. This is the implementation
  112. * for POSIX threads.
  113. */
  114. namespace qx {
  115. namespace memory {
  116. class fast_mutex
  117. {
  118. pthread_mutex_t _M_mtx_impl;
  119. # if _FAST_MUTEX_CHECK_INITIALIZATION
  120. bool _M_initialized;
  121. # endif
  122. #ifndef _QX_MODE_RELEASE
  123. #ifndef QT_NO_DEBUG
  124. bool _M_locked;
  125. #endif // QT_NO_DEBUG
  126. #endif // _QX_MODE_RELEASE
  127. public:
  128. fast_mutex()
  129. #ifndef _QX_MODE_RELEASE
  130. #ifndef QT_NO_DEBUG
  131. : _M_locked(false)
  132. #endif // QT_NO_DEBUG
  133. #endif // _QX_MODE_RELEASE
  134. {
  135. ::pthread_mutex_init(&_M_mtx_impl, NULL);
  136. # if _FAST_MUTEX_CHECK_INITIALIZATION
  137. _M_initialized = true;
  138. # endif
  139. }
  140. ~fast_mutex()
  141. {
  142. _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
  143. # if _FAST_MUTEX_CHECK_INITIALIZATION
  144. _M_initialized = false;
  145. # endif
  146. ::pthread_mutex_destroy(&_M_mtx_impl);
  147. }
  148. void lock()
  149. {
  150. # if _FAST_MUTEX_CHECK_INITIALIZATION
  151. if (!_M_initialized)
  152. return;
  153. # endif
  154. ::pthread_mutex_lock(&_M_mtx_impl);
  155. #ifndef _QX_MODE_RELEASE
  156. #ifndef QT_NO_DEBUG
  157. // The following assertion should _always_ be true for a
  158. // real `fast' pthread_mutex. However, this assertion can
  159. // help sometimes, when people forget to use `-lpthread' and
  160. // glibc provides an empty implementation. Having this
  161. // assertion is also more consistent.
  162. _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
  163. _M_locked = true;
  164. #endif // QT_NO_DEBUG
  165. #endif // _QX_MODE_RELEASE
  166. }
  167. void unlock()
  168. {
  169. # if _FAST_MUTEX_CHECK_INITIALIZATION
  170. if (!_M_initialized)
  171. return;
  172. # endif
  173. #ifndef _QX_MODE_RELEASE
  174. #ifndef QT_NO_DEBUG
  175. _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
  176. _M_locked = false;
  177. #endif // QT_NO_DEBUG
  178. #endif // _QX_MODE_RELEASE
  179. ::pthread_mutex_unlock(&_M_mtx_impl);
  180. }
  181. private:
  182. fast_mutex(const fast_mutex&);
  183. fast_mutex& operator=(const fast_mutex&);
  184. };
  185. } // namespace memory
  186. } // namespace qx
  187. # endif // _PTHREADS
  188. # ifdef _WIN32THREADS
  189. # include <windows.h>
  190. /**
  191. * Macro alias to `volatile' semantics. Here it is truly volatile since
  192. * it is in a multi-threaded (Win32 threads) environment.
  193. */
  194. # define __VOLATILE volatile
  195. /**
  196. * Class for non-reentrant fast mutexes. This is the implementation
  197. * for Win32 threads.
  198. */
  199. namespace qx {
  200. namespace memory {
  201. class fast_mutex
  202. {
  203. CRITICAL_SECTION _M_mtx_impl;
  204. # if _FAST_MUTEX_CHECK_INITIALIZATION
  205. bool _M_initialized;
  206. # endif
  207. #ifndef _QX_MODE_RELEASE
  208. #ifndef QT_NO_DEBUG
  209. bool _M_locked;
  210. #endif // QT_NO_DEBUG
  211. #endif // _QX_MODE_RELEASE
  212. public:
  213. fast_mutex()
  214. #ifndef _QX_MODE_RELEASE
  215. #ifndef QT_NO_DEBUG
  216. : _M_locked(false)
  217. #endif // QT_NO_DEBUG
  218. #endif // _QX_MODE_RELEASE
  219. {
  220. ::InitializeCriticalSection(&_M_mtx_impl);
  221. # if _FAST_MUTEX_CHECK_INITIALIZATION
  222. _M_initialized = true;
  223. # endif
  224. }
  225. ~fast_mutex()
  226. {
  227. _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
  228. # if _FAST_MUTEX_CHECK_INITIALIZATION
  229. _M_initialized = false;
  230. # endif
  231. ::DeleteCriticalSection(&_M_mtx_impl);
  232. }
  233. void lock()
  234. {
  235. # if _FAST_MUTEX_CHECK_INITIALIZATION
  236. if (!_M_initialized)
  237. return;
  238. # endif
  239. ::EnterCriticalSection(&_M_mtx_impl);
  240. #ifndef _QX_MODE_RELEASE
  241. #ifndef QT_NO_DEBUG
  242. _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
  243. _M_locked = true;
  244. #endif // QT_NO_DEBUG
  245. #endif // _QX_MODE_RELEASE
  246. }
  247. void unlock()
  248. {
  249. # if _FAST_MUTEX_CHECK_INITIALIZATION
  250. if (!_M_initialized)
  251. return;
  252. # endif
  253. #ifndef _QX_MODE_RELEASE
  254. #ifndef QT_NO_DEBUG
  255. _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
  256. _M_locked = false;
  257. #endif // QT_NO_DEBUG
  258. #endif // _QX_MODE_RELEASE
  259. ::LeaveCriticalSection(&_M_mtx_impl);
  260. }
  261. private:
  262. fast_mutex(const fast_mutex&);
  263. fast_mutex& operator=(const fast_mutex&);
  264. };
  265. } // namespace memory
  266. } // namespace qx
  267. # endif // _WIN32THREADS
  268. # ifdef _NOTHREADS
  269. /**
  270. * Macro alias to `volatile' semantics. Here it is not truly volatile
  271. * since it is in a single-threaded environment.
  272. */
  273. # define __VOLATILE
  274. /**
  275. * Class for non-reentrant fast mutexes. This is the null
  276. * implementation for single-threaded environments.
  277. */
  278. namespace qx {
  279. namespace memory {
  280. class fast_mutex
  281. {
  282. #ifndef _QX_MODE_RELEASE
  283. #ifndef QT_NO_DEBUG
  284. bool _M_locked;
  285. #endif // QT_NO_DEBUG
  286. #endif // _QX_MODE_RELEASE
  287. public:
  288. fast_mutex()
  289. #ifndef _QX_MODE_RELEASE
  290. #ifndef QT_NO_DEBUG
  291. : _M_locked(false)
  292. #endif // QT_NO_DEBUG
  293. #endif // _QX_MODE_RELEASE
  294. {
  295. }
  296. ~fast_mutex()
  297. {
  298. _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
  299. }
  300. void lock()
  301. {
  302. #ifndef _QX_MODE_RELEASE
  303. #ifndef QT_NO_DEBUG
  304. _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
  305. _M_locked = true;
  306. #endif // QT_NO_DEBUG
  307. #endif // _QX_MODE_RELEASE
  308. }
  309. void unlock()
  310. {
  311. #ifndef _QX_MODE_RELEASE
  312. #ifndef QT_NO_DEBUG
  313. _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
  314. _M_locked = false;
  315. #endif // QT_NO_DEBUG
  316. #endif // _QX_MODE_RELEASE
  317. }
  318. private:
  319. fast_mutex(const fast_mutex&);
  320. fast_mutex& operator=(const fast_mutex&);
  321. };
  322. } // namespace memory
  323. } // namespace qx
  324. # endif // _NOTHREADS
  325. namespace qx {
  326. namespace memory {
  327. /** An acquistion-on-initialization lock class based on fast_mutex. */
  328. class QX_DLL_EXPORT fast_mutex_autolock
  329. {
  330. fast_mutex& _M_mtx;
  331. public:
  332. explicit fast_mutex_autolock(fast_mutex& __mtx) : _M_mtx(__mtx)
  333. {
  334. _M_mtx.lock();
  335. }
  336. ~fast_mutex_autolock()
  337. {
  338. _M_mtx.unlock();
  339. }
  340. private:
  341. fast_mutex_autolock(const fast_mutex_autolock&);
  342. fast_mutex_autolock& operator=(const fast_mutex_autolock&);
  343. };
  344. } // namespace memory
  345. } // namespace qx
  346. #endif // _FAST_MUTEX_H
  347. #endif // _QX_USE_MEM_LEAK_DETECTION
  348. #endif // _QX_MODE_RELEASE
  349. #endif // QT_NO_DEBUG