Atomic.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /*
  2. Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
  3. Redistribution and use in source and binary forms, with or without
  4. modification, are permitted provided that the following conditions are met:
  5. * Redistributions of source code must retain the above copyright notice,
  6. this list of conditions and the following disclaimer.
  7. * Redistributions in binary form must reproduce the above copyright notice,
  8. this list of conditions and the following disclaimer in the documentation
  9. and/or other materials provided with the distribution.
  10. * Neither the name of LibCat nor the names of its contributors may be used
  11. to endorse or promote products derived from this software without
  12. specific prior written permission.
  13. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  14. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  17. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  23. POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #ifndef CAT_ATOMIC_HPP
  26. #define CAT_ATOMIC_HPP
  27. #include <cat/Platform.hpp>
  28. #if defined(CAT_OS_WINDOWS)
  29. # include <cat/port/WindowsInclude.hpp>
  30. #endif
  31. namespace cat {
  32. namespace Atomic {
  33. // Compare-and-Swap 2x word size (CAS2)
  34. // On 32-bit architectures, the arguments point to 64-bit values, and must be aligned to 8 byte boundary
  35. // On 64-bit architectures, the arguments point to 128-bit values, and must be aligned to 16 byte boundary
  36. // Returns true if the old value was equal to the expected value
  37. CAT_INLINE bool CAS2(volatile void *x, const void *expected_old_value, const void *new_value);
  38. // Will define CAT_NO_ATOMIC_CAS2 if the platform/compiler does not support atomic CAS2
  39. // Add y to x, returning the previous state of x
  40. CAT_INLINE u32 Add(volatile u32 *x, s32 y);
  41. // Will define CAT_NO_ATOMIC_ADD if the platform/compiler does not support atomic add
  42. // Set x to new value, returning the previous state of x
  43. CAT_INLINE u32 Set(volatile u32 *x, u32 new_value);
  44. // Will define CAT_NO_ATOMIC_SET if the platform/compiler does not support atomic set
  45. // Bit Test and Set (BTS)
  46. // Returns true if the bit was 1 and is still 1, otherwise false
  47. CAT_INLINE bool BTS(volatile u32 *x, int bit);
  48. // Will define CAT_NO_ATOMIC_BTS if the platform/compiler does not support atomic bts
  49. // Bit Test and Reset (BTR)
  50. // Returns true if the bit was 1 and is now 0, otherwise false
  51. CAT_INLINE bool BTR(volatile u32 *x, int bit);
  52. // Will define CAT_NO_ATOMIC_BTR if the platform/compiler does not support atomic btr
  53. } // namespace Atomic
  54. //// Compare-and-Swap
  55. #if defined(CAT_WORD_64)
  56. bool Atomic::CAS2(volatile void *x, const void *expected_old_value, const void *new_value)
  57. {
  58. CAT_FENCE_COMPILER
  59. #if defined(CAT_COMPILER_MSVC) && (_MSC_VER > 1400) // MSVC 2008+
  60. __int64 ComparandResult[2] = { ((u64*)expected_old_value)[0],
  61. ((u64*)expected_old_value)[1] };
  62. // Requires MSVC 2008 or newer
  63. bool success = 1 == _InterlockedCompareExchange128((s64*)x, ((u64*)new_value)[1],
  64. ((u64*)new_value)[0], ComparandResult);
  65. CAT_FENCE_COMPILER
  66. return success;
  67. #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
  68. u128 *target = (u128*)x;
  69. u64 *replace = (u64*)new_value;
  70. u128 *expected = (u128*)expected_old_value;
  71. bool retval;
  72. CAT_ASM_BEGIN
  73. "lock; CMPXCHG16B %0\n\t"
  74. "sete %%al"
  75. : "=m" (*target), "=a" (retval)
  76. : "m" (*target), "b" (replace[0]), "c" (replace[1]), "A" (*expected)
  77. : "memory", "cc"
  78. CAT_ASM_END
  79. CAT_FENCE_COMPILER
  80. return retval;
  81. #else
  82. #define CAT_NO_ATOMIC_CAS2 /* Platform/compiler does not support CAS2 */
  83. (void) x; // avoid unused parameter warning
  84. (void) expected_old_value;
  85. (void) new_value;
  86. return true;
  87. #endif
  88. }
  89. #else // 32-bit version:
  90. bool Atomic::CAS2(volatile void *x, const void *expected_old_value, const void *new_value)
  91. {
  92. CAT_FENCE_COMPILER
  93. #if defined(CAT_COMPILER_MSVC)
  94. s64 old_value = ((s64*)expected_old_value)[0];
  95. bool success = (old_value == _InterlockedCompareExchange64((s64*)x, ((s64*)new_value)[0], old_value));
  96. CAT_FENCE_COMPILER
  97. return success;
  98. #elif defined(CAT_ASM_INTEL) && defined(CAT_ISA_X86)
  99. CAT_ASM_BEGIN
  100. push ebx
  101. mov eax, new_value
  102. push esi
  103. mov ebx, dword ptr[eax]
  104. mov ecx, dword ptr[eax+4]
  105. mov edx, expected_old_value
  106. mov esi, x
  107. mov eax, dword ptr[edx]
  108. mov edx, dword ptr[edx+4]
  109. lock CMPXCHG8B qword ptr[esi]
  110. pop ebx
  111. mov eax, 0
  112. pop esi
  113. setz al
  114. CAT_ASM_END
  115. CAT_FENCE_COMPILER
  116. #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
  117. u64 *target = (u64*)x;
  118. u32 *replace = (u32*)new_value;
  119. u64 *expected = (u64*)expected_old_value;
  120. bool retval;
  121. CAT_ASM_BEGIN
  122. "lock; CMPXCHG8B %0\n\t"
  123. "sete %%al"
  124. : "=m" (*target), "=a" (retval)
  125. : "m" (*target), "b" (replace[0]), "c" (replace[1]), "A" (*expected)
  126. : "memory", "cc"
  127. CAT_ASM_END
  128. CAT_FENCE_COMPILER
  129. return retval;
  130. #else
  131. #define CAT_NO_ATOMIC_CAS2 /* Platform/compiler does not support atomic CAS2 */
  132. (void) x; // avoid unused parameter warning
  133. (void) expected_old_value;
  134. (void) new_value;
  135. return true;
  136. #endif
  137. }
  138. #endif // defined(CAT_WORD_64)
  139. //// Add y to x, returning the previous state of x
  140. u32 Atomic::Add(volatile u32 *x, s32 y)
  141. {
  142. CAT_FENCE_COMPILER
  143. #if defined(CAT_COMPILER_MSVC) && defined(CAT_WORD_64)
  144. u32 result = _InterlockedAdd((volatile LONG*)x, y) - y;
  145. CAT_FENCE_COMPILER
  146. return result;
  147. #elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
  148. CAT_ASM_BEGIN
  149. mov edx,x
  150. mov eax,y
  151. lock XADD [edx],eax
  152. CAT_ASM_END
  153. CAT_FENCE_COMPILER
  154. #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
  155. u32 retval;
  156. CAT_ASM_BEGIN
  157. "lock; XADDl %%eax, %0\n\t"
  158. : "=m" (*x), "=a" (retval)
  159. : "m" (*x), "a" (y)
  160. : "memory", "cc"
  161. CAT_ASM_END
  162. CAT_FENCE_COMPILER
  163. return retval;
  164. #else
  165. #define CAT_NO_ATOMIC_ADD /* Platform/compiler does not support atomic add */
  166. u32 old_x = *x;
  167. *x = old_x + y;
  168. CAT_FENCE_COMPILER
  169. return old_x;
  170. #endif
  171. }
  172. //// Set x to new value, returning the previous state of x
  173. u32 Atomic::Set(volatile u32 *x, u32 new_value)
  174. {
  175. CAT_FENCE_COMPILER
  176. #if defined(CAT_COMPILER_MSVC)
  177. #if (_MSC_VER <= 1400) // MSVC 2005
  178. u32 result = _InterlockedExchange((long*)x, new_value);
  179. #else // MSVC 2008+
  180. u32 result = _InterlockedExchange((volatile LONG*)x, new_value);
  181. #endif
  182. CAT_FENCE_COMPILER
  183. return result;
  184. #elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
  185. CAT_ASM_BEGIN
  186. mov edx,x
  187. mov eax,new_value
  188. lock XCHG [edx],eax
  189. CAT_ASM_END
  190. CAT_FENCE_COMPILER
  191. #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
  192. u32 retval;
  193. CAT_ASM_BEGIN
  194. "lock; XCHGl %%eax, %0\n\t"
  195. : "=m" (*x), "=a" (retval)
  196. : "m" (*x), "a" (new_value)
  197. : "memory", "cc"
  198. CAT_ASM_END
  199. CAT_FENCE_COMPILER
  200. return retval;
  201. #else
  202. #define CAT_NO_ATOMIC_SET /* Platform/compiler does not support atomic set */
  203. u32 old_x = *x;
  204. *x = new_value;
  205. CAT_FENCE_COMPILER
  206. return old_x;
  207. #endif
  208. }
  209. //// Bit Test and Set (BTS)
  210. bool Atomic::BTS(volatile u32 *x, int bit)
  211. {
  212. CAT_FENCE_COMPILER
  213. #if defined(CAT_COMPILER_MSVC)
  214. #if (_MSC_VER <= 1400) // MSVC 2005
  215. bool success = !!_interlockedbittestandset((long*)x, bit);
  216. #else // MSVC 2008+
  217. bool success = !!_interlockedbittestandset((volatile LONG*)x, bit);
  218. #endif
  219. CAT_FENCE_COMPILER
  220. return success;
  221. #elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
  222. CAT_ASM_BEGIN
  223. mov edx,x
  224. mov ecx,bit
  225. lock BTS [edx],ecx
  226. mov eax,0
  227. setc al
  228. CAT_ASM_END
  229. CAT_FENCE_COMPILER
  230. #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
  231. bool retval;
  232. CAT_ASM_BEGIN
  233. "lock; BTSl %2, %0\n\t"
  234. "setc %%al"
  235. : "=m" (*x), "=a" (retval)
  236. : "Ir" (bit)
  237. : "memory", "cc"
  238. CAT_ASM_END
  239. CAT_FENCE_COMPILER
  240. return retval;
  241. #else
  242. #define CAT_NO_ATOMIC_BTS /* Platform/compiler does not support atomic bts */
  243. u32 mask = 1 << bit;
  244. u32 old_x = *x;
  245. *x = old_x | mask;
  246. CAT_FENCE_COMPILER
  247. return (old_x & mask) ? true : false;
  248. #endif
  249. }
  250. //// Bit Test and Reset (BTR)
  251. bool Atomic::BTR(volatile u32 *x, int bit)
  252. {
  253. CAT_FENCE_COMPILER
  254. #if defined(CAT_COMPILER_MSVC)
  255. #if (_MSC_VER <= 1400) // MSVC 2005
  256. bool success = !!_interlockedbittestandreset((long*)x, bit);
  257. #else // MSVC 2008+
  258. bool success = !!_interlockedbittestandreset((volatile LONG*)x, bit);
  259. #endif
  260. CAT_FENCE_COMPILER
  261. return success;
  262. #elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
  263. CAT_ASM_BEGIN
  264. mov edx,x
  265. mov ecx,bit
  266. lock BTR [edx],ecx
  267. mov eax,0
  268. setc al
  269. CAT_ASM_END
  270. CAT_FENCE_COMPILER
  271. #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
  272. bool retval;
  273. CAT_ASM_BEGIN
  274. "lock; BTRl %2, %0\n\t"
  275. "setc %%al"
  276. : "=m" (*x), "=a" (retval)
  277. : "Ir" (bit)
  278. : "memory", "cc"
  279. CAT_ASM_END
  280. CAT_FENCE_COMPILER
  281. return retval;
  282. #else
  283. #define CAT_NO_ATOMIC_BTR /* Platform/compiler does not support atomic btr */
  284. u32 mask = 1 << bit;
  285. u32 old_x = *x;
  286. *x = old_x & ~mask;
  287. CAT_FENCE_COMPILER
  288. return (old_x & mask) ? true : false;
  289. #endif
  290. }
  291. } // namespace cat
  292. #endif // CAT_ATOMIC_HPP
粤ICP备19079148号