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.

483 lines
15 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: unixstl/synch/atomic_functions.h
  3. *
  4. * Purpose: UNIXSTL atomic functions.
  5. *
  6. * Created: 23rd October 1997
  7. * Updated: 29th April 2010
  8. *
  9. * Thanks: To Brad Cox, for helping out in testing and fixing the
  10. * implementation for MAC OSX (Intel).
  11. *
  12. * Home: http://stlsoft.org/
  13. *
  14. * Copyright (c) 1997-2010, Matthew Wilson and Synesis Software
  15. * All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions are met:
  19. *
  20. * - Redistributions of source code must retain the above copyright notice, this
  21. * list of conditions and the following disclaimer.
  22. * - Redistributions in binary form must reproduce the above copyright notice,
  23. * this list of conditions and the following disclaimer in the documentation
  24. * and/or other materials provided with the distribution.
  25. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  26. * any contributors may be used to endorse or promote products derived from
  27. * this software without specific prior written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  30. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  33. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  34. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  35. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  36. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  37. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  38. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  39. * POSSIBILITY OF SUCH DAMAGE.
  40. *
  41. * ////////////////////////////////////////////////////////////////////// */
  42. /** \file unixstl/synch/atomic_functions.h
  43. *
  44. * \brief [C++ only] Definition of the atomic functions
  45. * (\ref group__library__synch "Synchronisation" Library).
  46. */
  47. #ifndef UNIXSTL_INCL_UNIXSTL_SYNCH_H_ATOMIC_FUNCTIONS
  48. #define UNIXSTL_INCL_UNIXSTL_SYNCH_H_ATOMIC_FUNCTIONS
  49. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  50. # define UNIXSTL_VER_UNIXSTL_SYNCH_H_ATOMIC_FUNCTIONS_MAJOR 6
  51. # define UNIXSTL_VER_UNIXSTL_SYNCH_H_ATOMIC_FUNCTIONS_MINOR 1
  52. # define UNIXSTL_VER_UNIXSTL_SYNCH_H_ATOMIC_FUNCTIONS_REVISION 1
  53. # define UNIXSTL_VER_UNIXSTL_SYNCH_H_ATOMIC_FUNCTIONS_EDIT 201
  54. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  55. /* /////////////////////////////////////////////////////////////////////////
  56. * Includes
  57. */
  58. #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
  59. # include <unixstl/unixstl.h>
  60. #endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */
  61. #ifndef UNIXSTL_INCL_UNIXSTL_SYNCH_UTIL_H_FEATURES
  62. # include <unixstl/synch/util/features.h>
  63. #endif /* !UNIXSTL_INCL_UNIXSTL_SYNCH_UTIL_H_FEATURES */
  64. #ifndef UNIXSTL_INCL_UNIXSTL_SYNCH_H_ATOMIC_TYPES
  65. # include <unixstl/synch/atomic_types.h>
  66. #endif /* !UNIXSTL_INCL_UNIXSTL_SYNCH_H_ATOMIC_TYPES */
  67. #if defined(UNIXSTL_FORCE_ATOMIC_INTEGER_OPERATIONS)
  68. /* Nothing to include here; UNIXSTL_FORCED_ATOMIC_INTEGER_IMPLEMENTATIONS will be included inside unixstl namespace */
  69. #elif defined(UNIXSTL_ATOMIC_INTEGER_OPERATIONS_VIA_GCC_BUILTINS)
  70. /* Nothing to include, since using built-ins */
  71. #elif defined(UNIXSTL_ATOMIC_INTEGER_OPERATIONS_VIA_MACOSX)
  72. # include <libkern/OSAtomic.h>
  73. #elif defined(UNIXSTL_ATOMIC_INTEGER_OPERATIONS_VIA_WINDOWS_INTERLOCKED)
  74. # include <windows.h>
  75. #else
  76. # error Atomic integer operations not supported: see unixstl/synch/util/features.h for details
  77. #endif /* ? */
  78. /* /////////////////////////////////////////////////////////////////////////
  79. * Namespace
  80. */
  81. #ifndef _UNIXSTL_NO_NAMESPACE
  82. # if defined(_STLSOFT_NO_NAMESPACE) || \
  83. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  84. /* There is no stlsoft namespace, so must define ::unixstl */
  85. namespace unixstl
  86. {
  87. # else
  88. /* Define stlsoft::unixstl_project */
  89. namespace stlsoft
  90. {
  91. namespace unixstl_project
  92. {
  93. # endif /* _STLSOFT_NO_NAMESPACE */
  94. #endif /* !_UNIXSTL_NO_NAMESPACE */
  95. /* /////////////////////////////////////////////////////////////////////////
  96. * Features
  97. */
  98. #ifdef UNIXSTL_HAS_ATOMIC_PREINCREMENT
  99. # undef UNIXSTL_HAS_ATOMIC_PREINCREMENT
  100. #endif /* UNIXSTL_HAS_ATOMIC_PREINCREMENT */
  101. #ifdef UNIXSTL_HAS_ATOMIC_PREDECREMENT
  102. # undef UNIXSTL_HAS_ATOMIC_PREDECREMENT
  103. #endif /* UNIXSTL_HAS_ATOMIC_PREDECREMENT */
  104. #ifdef UNIXSTL_HAS_ATOMIC_POSTINCREMENT
  105. # undef UNIXSTL_HAS_ATOMIC_POSTINCREMENT
  106. #endif /* UNIXSTL_HAS_ATOMIC_POSTINCREMENT */
  107. #ifdef UNIXSTL_HAS_ATOMIC_POSTDECREMENT
  108. # undef UNIXSTL_HAS_ATOMIC_POSTDECREMENT
  109. #endif /* UNIXSTL_HAS_ATOMIC_POSTDECREMENT */
  110. #ifdef UNIXSTL_HAS_ATOMIC_INCREMENT
  111. # undef UNIXSTL_HAS_ATOMIC_INCREMENT
  112. #endif /* UNIXSTL_HAS_ATOMIC_INCREMENT */
  113. #ifdef UNIXSTL_HAS_ATOMIC_DECREMENT
  114. # undef UNIXSTL_HAS_ATOMIC_DECREMENT
  115. #endif /* UNIXSTL_HAS_ATOMIC_DECREMENT */
  116. #ifdef UNIXSTL_HAS_ATOMIC_READ
  117. # undef UNIXSTL_HAS_ATOMIC_READ
  118. #endif /* UNIXSTL_HAS_ATOMIC_READ */
  119. #ifdef UNIXSTL_HAS_ATOMIC_WRITE
  120. # undef UNIXSTL_HAS_ATOMIC_WRITE
  121. #endif /* UNIXSTL_HAS_ATOMIC_WRITE */
  122. #ifdef UNIXSTL_HAS_ATOMIC_PREADD
  123. # undef UNIXSTL_HAS_ATOMIC_PREADD
  124. #endif /* UNIXSTL_HAS_ATOMIC_PREADD */
  125. #ifdef UNIXSTL_HAS_ATOMIC_POSTADD
  126. # undef UNIXSTL_HAS_ATOMIC_POSTADD
  127. #endif /* UNIXSTL_HAS_ATOMIC_POSTADD */
  128. /* /////////////////////////////////////////////////////////////////////////
  129. * Functions
  130. */
  131. #if defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  132. /** \brief Indicates whether the atomic_preincrement function is defined
  133. * for the current compiler/operating-system/architecture
  134. */
  135. # define UNIXSTL_HAS_ATOMIC_PREINCREMENT
  136. /** \brief Indicates whether the atomic_predecrement function is defined
  137. * for the current compiler/operating-system/architecture
  138. */
  139. # define UNIXSTL_HAS_ATOMIC_PREDECREMENT
  140. /** \brief Indicates whether the atomic_postincrement function is defined
  141. * for the current compiler/operating-system/architecture
  142. */
  143. # define UNIXSTL_HAS_ATOMIC_POSTINCREMENT
  144. /** \brief Indicates whether the atomic_postdecrement function is defined
  145. * for the current compiler/operating-system/architecture
  146. */
  147. # define UNIXSTL_HAS_ATOMIC_POSTDECREMENT
  148. /** \brief Indicates whether the atomic_increment function is defined for
  149. * the current compiler/operating-system/architecture
  150. */
  151. # define UNIXSTL_HAS_ATOMIC_INCREMENT
  152. /** \brief Indicates whether the atomic_decrement function is defined for
  153. * the current compiler/operating-system/architecture
  154. */
  155. # define UNIXSTL_HAS_ATOMIC_DECREMENT
  156. /** \brief Indicates whether the atomic_read function is defined for the
  157. * current compiler/operating-system/architecture
  158. */
  159. # define UNIXSTL_HAS_ATOMIC_READ
  160. /** \brief Indicates whether the atomic_write function is defined for the
  161. * current compiler/operating-system/architecture
  162. */
  163. # define UNIXSTL_HAS_ATOMIC_WRITE
  164. /** \brief Indicates whether the atomic_preadd function is defined for the
  165. * current compiler/operating-system/architecture
  166. */
  167. # define UNIXSTL_HAS_ATOMIC_PREADD
  168. /** \brief Indicates whether the atomic_postadd function is defined for the
  169. * current compiler/operating-system/architecture
  170. */
  171. # define UNIXSTL_HAS_ATOMIC_POSTADD
  172. #elif defined(UNIXSTL_HAS_ATOMIC_INTEGER_OPERATIONS)
  173. # if defined(UNIXSTL_FORCE_ATOMIC_INTEGER_OPERATIONS)
  174. /* ************************************
  175. * Forced
  176. */
  177. # ifndef UNIXSTL_FORCED_ATOMIC_INTEGER_IMPLEMENTATIONS
  178. # error If you are forcing atomic integer support (by defining UNIXSTL_FORCE_ATOMIC_INTEGER_OPERATIONS) you must also define UNIXSTL_FORCED_ATOMIC_INTEGER_IMPLEMENTATIONS as the header containing the atomic integer operations, which will be included
  179. # endif /* UNIXSTL_FORCED_ATOMIC_INTEGER_IMPLEMENTATIONS */
  180. # include UNIXSTL_FORCED_ATOMIC_INTEGER_IMPLEMENTATIONS
  181. # elif defined(UNIXSTL_ATOMIC_INTEGER_OPERATIONS_VIA_GCC_BUILTINS)
  182. /* ************************************
  183. * GCC builtins
  184. */
  185. # error This feature is not yet supported, and you should not be seeing this compilation path unless unixstl/synch/util/features.h is out of synch with this file; contact Synesis Software
  186. # elif defined(UNIXSTL_ATOMIC_INTEGER_OPERATIONS_VIA_WINDOWS_INTERLOCKED)
  187. /* ************************************
  188. * Windows Interlocked
  189. */
  190. # if !defined(UNIXSTL_NO_WIN32_NATIVE_ATOMIC_FUNCTIONS)
  191. STLSOFT_INLINE atomic_int_t atomic_preincrement(atomic_int_t volatile* pl)
  192. {
  193. return STLSOFT_NS_GLOBAL(InterlockedIncrement)((LPLONG)pl);
  194. }
  195. # define UNIXSTL_HAS_ATOMIC_PREINCREMENT
  196. STLSOFT_INLINE atomic_int_t atomic_predecrement(atomic_int_t volatile* pl)
  197. {
  198. return STLSOFT_NS_GLOBAL(InterlockedDecrement)((LPLONG)pl);
  199. }
  200. # define UNIXSTL_HAS_ATOMIC_PREDECREMENT
  201. STLSOFT_INLINE atomic_int_t atomic_postincrement(atomic_int_t volatile* pl)
  202. {
  203. atomic_int_t pre = *pl;
  204. STLSOFT_NS_GLOBAL(InterlockedIncrement)((LPLONG)pl);
  205. return pre;
  206. }
  207. # define UNIXSTL_HAS_ATOMIC_POSTINCREMENT
  208. STLSOFT_INLINE atomic_int_t atomic_postdecrement(atomic_int_t volatile* pl)
  209. {
  210. atomic_int_t pre = *pl;
  211. STLSOFT_NS_GLOBAL(InterlockedDecrement)((LPLONG)pl);
  212. return pre;
  213. }
  214. # define UNIXSTL_HAS_ATOMIC_POSTDECREMENT
  215. STLSOFT_INLINE void atomic_increment(atomic_int_t volatile* pl)
  216. {
  217. STLSOFT_NS_GLOBAL(InterlockedIncrement)((LPLONG)pl);
  218. }
  219. # define UNIXSTL_HAS_ATOMIC_INCREMENT
  220. STLSOFT_INLINE void atomic_decrement(atomic_int_t volatile* pl)
  221. {
  222. STLSOFT_NS_GLOBAL(InterlockedDecrement)((LPLONG)pl);
  223. }
  224. # define UNIXSTL_HAS_ATOMIC_DECREMENT
  225. # endif /* !UNIXSTL_NO_WIN32_NATIVE_ATOMIC_FUNCTIONS */
  226. /* NOTE: We allow atomic_write(), since on almost all platforms this'll be fine */
  227. STLSOFT_INLINE atomic_int_t atomic_write(atomic_int_t volatile* pv, atomic_int_t n)
  228. {
  229. return stlsoft_static_cast(atomic_int_t, STLSOFT_NS_GLOBAL(InterlockedExchange)(stlsoft_c_cast(LPLONG, pv), n));
  230. }
  231. # define UNIXSTL_HAS_ATOMIC_WRITE
  232. # if !defined(UNIXSTL_NO_WIN32_NATIVE_ATOMIC_FUNCTIONS)
  233. STLSOFT_INLINE atomic_int_t atomic_read(atomic_int_t volatile* pv)
  234. {
  235. return *pv;
  236. }
  237. # define UNIXSTL_HAS_ATOMIC_READ
  238. /* STLSOFT_INLINE */ atomic_int_t atomic_preadd(atomic_int_t volatile* pl, atomic_int_t n);
  239. STLSOFT_INLINE atomic_int_t atomic_postadd(atomic_int_t volatile* pl, atomic_int_t n)
  240. {
  241. return (atomic_int_t)STLSOFT_NS_GLOBAL(InterlockedExchangeAdd)((LPLONG)pl, n);
  242. }
  243. # define UNIXSTL_HAS_ATOMIC_POSTADD
  244. # endif /* !UNIXSTL_NO_WIN32_NATIVE_ATOMIC_FUNCTIONS */
  245. # elif defined(UNIXSTL_ATOMIC_INTEGER_OPERATIONS_VIA_MACOSX)
  246. /* ************************************
  247. * Mac OS-X
  248. */
  249. /** \brief
  250. *
  251. * \ingroup group__library__synch
  252. */
  253. STLSOFT_INLINE atomic_int_t atomic_preincrement(atomic_int_t volatile* pl)
  254. {
  255. return STLSOFT_NS_GLOBAL(OSAtomicIncrement32Barrier)(stlsoft_const_cast(atomic_int_t*, pl));
  256. }
  257. # define UNIXSTL_HAS_ATOMIC_PREINCREMENT
  258. /** \brief
  259. *
  260. * \ingroup group__library__synch
  261. */
  262. STLSOFT_INLINE atomic_int_t atomic_predecrement(atomic_int_t volatile* pl)
  263. {
  264. return STLSOFT_NS_GLOBAL(OSAtomicDecrement32Barrier)(stlsoft_const_cast(atomic_int_t*, pl));
  265. }
  266. # define UNIXSTL_HAS_ATOMIC_PREDECREMENT
  267. /** \brief
  268. *
  269. * \ingroup group__library__synch
  270. */
  271. STLSOFT_INLINE atomic_int_t atomic_postincrement(atomic_int_t volatile* pl)
  272. {
  273. return STLSOFT_NS_GLOBAL(OSAtomicIncrement32Barrier)(stlsoft_const_cast(atomic_int_t*, pl)) - 1;
  274. }
  275. # define UNIXSTL_HAS_ATOMIC_POSTINCREMENT
  276. /** \brief
  277. *
  278. * \ingroup group__library__synch
  279. */
  280. STLSOFT_INLINE atomic_int_t atomic_postdecrement(atomic_int_t volatile* pl)
  281. {
  282. return STLSOFT_NS_GLOBAL(OSAtomicDecrement32Barrier)(stlsoft_const_cast(atomic_int_t*, pl)) + 1;
  283. }
  284. # define UNIXSTL_HAS_ATOMIC_POSTDECREMENT
  285. /** \brief
  286. *
  287. * \ingroup group__library__synch
  288. */
  289. STLSOFT_INLINE void atomic_increment(atomic_int_t volatile* pl)
  290. {
  291. STLSOFT_NS_GLOBAL(OSAtomicIncrement32Barrier)(stlsoft_const_cast(atomic_int_t*, pl));
  292. }
  293. # define UNIXSTL_HAS_ATOMIC_INCREMENT
  294. /** \brief
  295. *
  296. * \ingroup group__library__synch
  297. */
  298. STLSOFT_INLINE void atomic_decrement(atomic_int_t volatile* pl)
  299. {
  300. STLSOFT_NS_GLOBAL(OSAtomicDecrement32Barrier)(stlsoft_const_cast(atomic_int_t*, pl));
  301. }
  302. # define UNIXSTL_HAS_ATOMIC_DECREMENT
  303. /** \brief
  304. *
  305. * \ingroup group__library__synch
  306. */
  307. /** \brief Note: atomic_write() for PowerPC is not yet defined. If you wish to suggest an
  308. * implementation, it will be most welcome.
  309. *
  310. * \ingroup group__library__synch
  311. */
  312. /* STLSOFT_INLINE */ atomic_int_t atomic_write(atomic_int_t volatile* pv, atomic_int_t n);
  313. /** \brief
  314. *
  315. * \ingroup group__library__synch
  316. */
  317. STLSOFT_INLINE atomic_int_t atomic_read(atomic_int_t volatile* pv)
  318. {
  319. STLSOFT_NS_GLOBAL(OSMemoryBarrier)();
  320. return *pv;
  321. }
  322. # define UNIXSTL_HAS_ATOMIC_READ
  323. /** \brief
  324. *
  325. * \ingroup group__library__synch
  326. */
  327. STLSOFT_INLINE atomic_int_t atomic_preadd(atomic_int_t volatile* pl, atomic_int_t n)
  328. {
  329. return STLSOFT_NS_GLOBAL(OSAtomicAdd32Barrier)(n, stlsoft_const_cast(atomic_int_t*, pl));
  330. }
  331. # define UNIXSTL_HAS_ATOMIC_PREADD
  332. /** \brief
  333. *
  334. * \ingroup group__library__synch
  335. */
  336. STLSOFT_INLINE atomic_int_t atomic_postadd(atomic_int_t volatile* pl, atomic_int_t n)
  337. {
  338. return STLSOFT_NS_GLOBAL(OSAtomicAdd32Barrier)(n, stlsoft_const_cast(atomic_int_t*, pl)) - n;
  339. }
  340. # define UNIXSTL_HAS_ATOMIC_POSTADD
  341. # else
  342. # error Atomic integer operations not supported: see unixstl/synch/util/features.h for details
  343. # endif /* ? */
  344. /* ////////////////////////////////////////////////////////////////////// */
  345. # if 0
  346. STLSOFT_INLINE atomic_int_t atomic_read(atomic_int_t volatile* pv);
  347. /* # define UNIXSTL_HAS_ATOMIC_READ */
  348. STLSOFT_INLINE atomic_int_t atomic_write(atomic_int_t volatile* pv, atomic_int_t n)
  349. {
  350. atomic_int_t oldval;
  351. /* Note: the "xchg" instruction does not need a "lock" prefix */
  352. # ifdef STLSOFT_COMPILER_IS_GCC
  353. __asm__ __volatile__( "xchgl %0, %1" /* long (32-bit) xchg, from */
  354. : "=r"(oldval), "=m"(*(pv))
  355. : "0"(n), "m"(*(pv))
  356. : "memory");
  357. # else /* ? compiler */
  358. _asm
  359. {
  360. mov ecx, dword ptr [pv]
  361. mov eax, n
  362. xchg dword ptr [ecx], eax
  363. mov oldval, eax
  364. }
  365. # endif /* compiler */
  366. return oldval;
  367. }
  368. #endif
  369. /* ////////////////////////////////////////////////////////////////////// */
  370. #endif /* UNIXSTL_HAS_ATOMIC_INTEGER_OPERATIONS */
  371. /* /////////////////////////////////////////////////////////////////////////
  372. * Unit-testing
  373. */
  374. #ifdef STLSOFT_UNITTEST
  375. # include "./unittest/atomic_functions_unittest_.h"
  376. #endif /* STLSOFT_UNITTEST */
  377. /* ////////////////////////////////////////////////////////////////////// */
  378. #ifndef _UNIXSTL_NO_NAMESPACE
  379. # if defined(_STLSOFT_NO_NAMESPACE) || \
  380. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  381. } /* namespace unixstl */
  382. # else
  383. } /* namespace unixstl_project */
  384. } /* namespace stlsoft */
  385. # endif /* _STLSOFT_NO_NAMESPACE */
  386. #endif /* !_UNIXSTL_NO_NAMESPACE */
  387. /* ////////////////////////////////////////////////////////////////////// */
  388. #endif /* !UNIXSTL_INCL_UNIXSTL_SYNCH_H_ATOMIC_FUNCTIONS */
  389. /* ///////////////////////////// end of file //////////////////////////// */