threading-windows.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * Copyright (c) 2015 Hugh Bailey <[email protected]>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #pragma once
  17. #include <intrin.h>
  18. #include <string.h>
  19. #if !defined(_M_IX86) && !defined(_M_X64) && !defined(_M_ARM) && \
  20. !defined(_M_ARM64)
  21. #error Processor not supported
  22. #endif
  23. static inline long os_atomic_inc_long(volatile long *val)
  24. {
  25. return _InterlockedIncrement(val);
  26. }
  27. static inline long os_atomic_dec_long(volatile long *val)
  28. {
  29. return _InterlockedDecrement(val);
  30. }
  31. static inline void os_atomic_store_long(volatile long *ptr, long val)
  32. {
  33. #if defined(_M_ARM64)
  34. __stlr32((volatile unsigned *)ptr, val);
  35. #elif defined(_M_ARM)
  36. __dmb(_ARM_BARRIER_ISH);
  37. __iso_volatile_store32((volatile __int32 *)ptr, val);
  38. __dmb(_ARM_BARRIER_ISH);
  39. #else
  40. _InterlockedExchange(ptr, val);
  41. #endif
  42. }
  43. static inline long os_atomic_set_long(volatile long *ptr, long val)
  44. {
  45. return _InterlockedExchange(ptr, val);
  46. }
  47. static inline long os_atomic_exchange_long(volatile long *ptr, long val)
  48. {
  49. return os_atomic_set_long(ptr, val);
  50. }
  51. static inline long os_atomic_load_long(const volatile long *ptr)
  52. {
  53. #if defined(_M_ARM64)
  54. return __ldar32((volatile unsigned *)ptr);
  55. #else
  56. const long val = __iso_volatile_load32((const volatile __int32 *)ptr);
  57. #if defined(_M_ARM)
  58. __dmb(_ARM_BARRIER_ISH);
  59. #else
  60. _ReadWriteBarrier();
  61. #endif
  62. return val;
  63. #endif
  64. }
  65. static inline bool os_atomic_compare_swap_long(volatile long *val, long old_val,
  66. long new_val)
  67. {
  68. return _InterlockedCompareExchange(val, new_val, old_val) == old_val;
  69. }
  70. static inline bool os_atomic_compare_exchange_long(volatile long *val,
  71. long *old_ptr, long new_val)
  72. {
  73. const long old_val = *old_ptr;
  74. const long previous =
  75. _InterlockedCompareExchange(val, new_val, old_val);
  76. *old_ptr = previous;
  77. return previous == old_val;
  78. }
  79. static inline void os_atomic_store_bool(volatile bool *ptr, bool val)
  80. {
  81. #if defined(_M_ARM64)
  82. __stlr8((volatile unsigned char *)ptr, val);
  83. #elif defined(_M_ARM)
  84. __dmb(_ARM_BARRIER_ISH);
  85. __iso_volatile_store8((volatile char *)ptr, val);
  86. __dmb(_ARM_BARRIER_ISH);
  87. #else
  88. _InterlockedExchange8((volatile char *)ptr, (char)val);
  89. #endif
  90. }
  91. static inline bool os_atomic_set_bool(volatile bool *ptr, bool val)
  92. {
  93. const char c = _InterlockedExchange8((volatile char *)ptr, (char)val);
  94. bool b;
  95. /* Avoid unnecesary char to bool conversion. Value known 0 or 1. */
  96. memcpy(&b, &c, sizeof(b));
  97. return b;
  98. }
  99. static inline bool os_atomic_exchange_bool(volatile bool *ptr, bool val)
  100. {
  101. return os_atomic_set_bool(ptr, val);
  102. }
  103. static inline bool os_atomic_load_bool(const volatile bool *ptr)
  104. {
  105. bool b;
  106. #if defined(_M_ARM64)
  107. const unsigned char c = __ldar8((volatile unsigned char *)ptr);
  108. #else
  109. const char c = __iso_volatile_load8((const volatile char *)ptr);
  110. #if defined(_M_ARM)
  111. __dmb(_ARM_BARRIER_ISH);
  112. #else
  113. _ReadWriteBarrier();
  114. #endif
  115. #endif
  116. /* Avoid unnecesary char to bool conversion. Value known 0 or 1. */
  117. memcpy(&b, &c, sizeof(b));
  118. return b;
  119. }