generic.h 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /*-------------------------------------------------------------------------
  2. *
  3. * generic.h
  4. * Implement higher level operations based on some lower level atomic
  5. * operations.
  6. *
  7. * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  8. * Portions Copyright (c) 1994, Regents of the University of California
  9. *
  10. * src/include/port/atomics/generic.h
  11. *
  12. *-------------------------------------------------------------------------
  13. */
  14. /* intentionally no include guards, should only be included by atomics.h */
  15. #ifndef INSIDE_ATOMICS_H
  16. # error "should be included via atomics.h"
  17. #endif
  18. /*
  19. * If read or write barriers are undefined, we upgrade them to full memory
  20. * barriers.
  21. */
  22. #if !defined(pg_read_barrier_impl)
  23. # define pg_read_barrier_impl pg_memory_barrier_impl
  24. #endif
  25. #if !defined(pg_write_barrier_impl)
  26. # define pg_write_barrier_impl pg_memory_barrier_impl
  27. #endif
  28. #ifndef PG_HAVE_SPIN_DELAY
  29. #define PG_HAVE_SPIN_DELAY
  30. #define pg_spin_delay_impl() ((void)0)
  31. #endif
  32. /* provide fallback */
  33. #if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) && defined(PG_HAVE_ATOMIC_U32_SUPPORT)
  34. #define PG_HAVE_ATOMIC_FLAG_SUPPORT
  35. typedef pg_atomic_uint32 pg_atomic_flag;
  36. #endif
  37. #ifndef PG_HAVE_ATOMIC_READ_U32
  38. #define PG_HAVE_ATOMIC_READ_U32
  39. static inline uint32
  40. pg_atomic_read_u32_impl(volatile pg_atomic_uint32 *ptr)
  41. {
  42. return *(&ptr->value);
  43. }
  44. #endif
  45. #ifndef PG_HAVE_ATOMIC_WRITE_U32
  46. #define PG_HAVE_ATOMIC_WRITE_U32
  47. static inline void
  48. pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
  49. {
  50. ptr->value = val;
  51. }
  52. #endif
  53. #ifndef PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
  54. #define PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32
  55. static inline void
  56. pg_atomic_unlocked_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val)
  57. {
  58. ptr->value = val;
  59. }
  60. #endif
  61. /*
  62. * provide fallback for test_and_set using atomic_exchange if available
  63. */
  64. #if !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32)
  65. #define PG_HAVE_ATOMIC_INIT_FLAG
  66. static inline void
  67. pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
  68. {
  69. pg_atomic_write_u32_impl(ptr, 0);
  70. }
  71. #define PG_HAVE_ATOMIC_TEST_SET_FLAG
  72. static inline bool
  73. pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
  74. {
  75. return pg_atomic_exchange_u32_impl(ptr, &value, 1) == 0;
  76. }
  77. #define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
  78. static inline bool
  79. pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
  80. {
  81. return pg_atomic_read_u32_impl(ptr) == 0;
  82. }
  83. #define PG_HAVE_ATOMIC_CLEAR_FLAG
  84. static inline void
  85. pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
  86. {
  87. /* XXX: release semantics suffice? */
  88. pg_memory_barrier_impl();
  89. pg_atomic_write_u32_impl(ptr, 0);
  90. }
  91. /*
  92. * provide fallback for test_and_set using atomic_compare_exchange if
  93. * available.
  94. */
  95. #elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
  96. #define PG_HAVE_ATOMIC_INIT_FLAG
  97. static inline void
  98. pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
  99. {
  100. pg_atomic_write_u32_impl(ptr, 0);
  101. }
  102. #define PG_HAVE_ATOMIC_TEST_SET_FLAG
  103. static inline bool
  104. pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr)
  105. {
  106. uint32 value = 0;
  107. return pg_atomic_compare_exchange_u32_impl(ptr, &value, 1);
  108. }
  109. #define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG
  110. static inline bool
  111. pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
  112. {
  113. return pg_atomic_read_u32_impl(ptr) == 0;
  114. }
  115. #define PG_HAVE_ATOMIC_CLEAR_FLAG
  116. static inline void
  117. pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr)
  118. {
  119. /*
  120. * Use a memory barrier + plain write if we have a native memory
  121. * barrier. But don't do so if memory barriers use spinlocks - that'd lead
  122. * to circularity if flags are used to implement spinlocks.
  123. */
  124. #ifndef PG_HAVE_MEMORY_BARRIER_EMULATION
  125. /* XXX: release semantics suffice? */
  126. pg_memory_barrier_impl();
  127. pg_atomic_write_u32_impl(ptr, 0);
  128. #else
  129. uint32 value = 1;
  130. pg_atomic_compare_exchange_u32_impl(ptr, &value, 0);
  131. #endif
  132. }
  133. #elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG)
  134. # error "No pg_atomic_test_and_set provided"
  135. #endif /* !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) */
  136. #ifndef PG_HAVE_ATOMIC_INIT_U32
  137. #define PG_HAVE_ATOMIC_INIT_U32
  138. static inline void
  139. pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_)
  140. {
  141. pg_atomic_write_u32_impl(ptr, val_);
  142. }
  143. #endif
  144. #if !defined(PG_HAVE_ATOMIC_EXCHANGE_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
  145. #define PG_HAVE_ATOMIC_EXCHANGE_U32
  146. static inline uint32
  147. pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 xchg_)
  148. {
  149. uint32 old;
  150. while (true)
  151. {
  152. old = pg_atomic_read_u32_impl(ptr);
  153. if (pg_atomic_compare_exchange_u32_impl(ptr, &old, xchg_))
  154. break;
  155. }
  156. return old;
  157. }
  158. #endif
  159. #if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
  160. #define PG_HAVE_ATOMIC_FETCH_ADD_U32
  161. static inline uint32
  162. pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
  163. {
  164. uint32 old;
  165. while (true)
  166. {
  167. old = pg_atomic_read_u32_impl(ptr);
  168. if (pg_atomic_compare_exchange_u32_impl(ptr, &old, old + add_))
  169. break;
  170. }
  171. return old;
  172. }
  173. #endif
  174. #if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
  175. #define PG_HAVE_ATOMIC_FETCH_SUB_U32
  176. static inline uint32
  177. pg_atomic_fetch_sub_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
  178. {
  179. return pg_atomic_fetch_add_u32_impl(ptr, -sub_);
  180. }
  181. #endif
  182. #if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
  183. #define PG_HAVE_ATOMIC_FETCH_AND_U32
  184. static inline uint32
  185. pg_atomic_fetch_and_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 and_)
  186. {
  187. uint32 old;
  188. while (true)
  189. {
  190. old = pg_atomic_read_u32_impl(ptr);
  191. if (pg_atomic_compare_exchange_u32_impl(ptr, &old, old & and_))
  192. break;
  193. }
  194. return old;
  195. }
  196. #endif
  197. #if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32)
  198. #define PG_HAVE_ATOMIC_FETCH_OR_U32
  199. static inline uint32
  200. pg_atomic_fetch_or_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 or_)
  201. {
  202. uint32 old;
  203. while (true)
  204. {
  205. old = pg_atomic_read_u32_impl(ptr);
  206. if (pg_atomic_compare_exchange_u32_impl(ptr, &old, old | or_))
  207. break;
  208. }
  209. return old;
  210. }
  211. #endif
  212. #if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32)
  213. #define PG_HAVE_ATOMIC_ADD_FETCH_U32
  214. static inline uint32
  215. pg_atomic_add_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
  216. {
  217. return pg_atomic_fetch_add_u32_impl(ptr, add_) + add_;
  218. }
  219. #endif
  220. #if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U32)
  221. #define PG_HAVE_ATOMIC_SUB_FETCH_U32
  222. static inline uint32
  223. pg_atomic_sub_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_)
  224. {
  225. return pg_atomic_fetch_sub_u32_impl(ptr, sub_) - sub_;
  226. }
  227. #endif
  228. #ifdef PG_HAVE_ATOMIC_U64_SUPPORT
  229. #if !defined(PG_HAVE_ATOMIC_EXCHANGE_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
  230. #define PG_HAVE_ATOMIC_EXCHANGE_U64
  231. static inline uint64
  232. pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 xchg_)
  233. {
  234. uint64 old;
  235. while (true)
  236. {
  237. old = ptr->value;
  238. if (pg_atomic_compare_exchange_u64_impl(ptr, &old, xchg_))
  239. break;
  240. }
  241. return old;
  242. }
  243. #endif
  244. #ifndef PG_HAVE_ATOMIC_WRITE_U64
  245. #define PG_HAVE_ATOMIC_WRITE_U64
  246. static inline void
  247. pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val)
  248. {
  249. /*
  250. * 64 bit writes aren't safe on all platforms. In the generic
  251. * implementation implement them as an atomic exchange.
  252. */
  253. pg_atomic_exchange_u64_impl(ptr, val);
  254. }
  255. #endif
  256. #ifndef PG_HAVE_ATOMIC_READ_U64
  257. #define PG_HAVE_ATOMIC_READ_U64
  258. static inline uint64
  259. pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr)
  260. {
  261. uint64 old = 0;
  262. /*
  263. * 64 bit reads aren't safe on all platforms. In the generic
  264. * implementation implement them as a compare/exchange with 0. That'll
  265. * fail or succeed, but always return the old value. Possible might store
  266. * a 0, but only if the prev. value also was a 0 - i.e. harmless.
  267. */
  268. pg_atomic_compare_exchange_u64_impl(ptr, &old, 0);
  269. return old;
  270. }
  271. #endif
  272. #ifndef PG_HAVE_ATOMIC_INIT_U64
  273. #define PG_HAVE_ATOMIC_INIT_U64
  274. static inline void
  275. pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_)
  276. {
  277. pg_atomic_write_u64_impl(ptr, val_);
  278. }
  279. #endif
  280. #if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
  281. #define PG_HAVE_ATOMIC_FETCH_ADD_U64
  282. static inline uint64
  283. pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
  284. {
  285. uint64 old;
  286. while (true)
  287. {
  288. old = pg_atomic_read_u64_impl(ptr);
  289. if (pg_atomic_compare_exchange_u64_impl(ptr, &old, old + add_))
  290. break;
  291. }
  292. return old;
  293. }
  294. #endif
  295. #if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
  296. #define PG_HAVE_ATOMIC_FETCH_SUB_U64
  297. static inline uint64
  298. pg_atomic_fetch_sub_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
  299. {
  300. return pg_atomic_fetch_add_u64_impl(ptr, -sub_);
  301. }
  302. #endif
  303. #if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
  304. #define PG_HAVE_ATOMIC_FETCH_AND_U64
  305. static inline uint64
  306. pg_atomic_fetch_and_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 and_)
  307. {
  308. uint64 old;
  309. while (true)
  310. {
  311. old = pg_atomic_read_u64_impl(ptr);
  312. if (pg_atomic_compare_exchange_u64_impl(ptr, &old, old & and_))
  313. break;
  314. }
  315. return old;
  316. }
  317. #endif
  318. #if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64)
  319. #define PG_HAVE_ATOMIC_FETCH_OR_U64
  320. static inline uint64
  321. pg_atomic_fetch_or_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 or_)
  322. {
  323. uint64 old;
  324. while (true)
  325. {
  326. old = pg_atomic_read_u64_impl(ptr);
  327. if (pg_atomic_compare_exchange_u64_impl(ptr, &old, old | or_))
  328. break;
  329. }
  330. return old;
  331. }
  332. #endif
  333. #if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64)
  334. #define PG_HAVE_ATOMIC_ADD_FETCH_U64
  335. static inline uint64
  336. pg_atomic_add_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
  337. {
  338. return pg_atomic_fetch_add_u64_impl(ptr, add_) + add_;
  339. }
  340. #endif
  341. #if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U64)
  342. #define PG_HAVE_ATOMIC_SUB_FETCH_U64
  343. static inline uint64
  344. pg_atomic_sub_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_)
  345. {
  346. return pg_atomic_fetch_sub_u64_impl(ptr, sub_) - sub_;
  347. }
  348. #endif
  349. #endif /* PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 */