Atomic.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #pragma once
  2. #include <stdint.h>
  3. #include "utils/NonCopyable.h"
  4. #include "c-api/Atomic-c-api.h"
  5. namespace il2cpp
  6. {
  7. namespace os
  8. {
  9. class Atomic : public il2cpp::utils::NonCopyable
  10. {
  11. public:
  12. // All 32bit atomics must be performed on 4-byte aligned addresses. All 64bit atomics must be
  13. // performed on 8-byte aligned addresses.
  14. // Add and Add64 return the *result* of the addition, not the old value! (i.e. they work like
  15. // InterlockedAdd and __sync_add_and_fetch).
  16. static inline void FullMemoryBarrier();
  17. static inline int32_t Add(volatile int32_t* location1, int32_t value)
  18. {
  19. return UnityPalAdd(location1, value);
  20. }
  21. static inline uint32_t Add(volatile uint32_t* location1, uint32_t value)
  22. {
  23. return (uint32_t)Add((volatile int32_t*)location1, (int32_t)value);
  24. }
  25. static inline int64_t Add64(volatile int64_t* location1, int64_t value)
  26. {
  27. return UnityPalAdd64(location1, value);
  28. }
  29. template<typename T>
  30. static inline T* CompareExchangePointer(T* volatile* dest, T* newValue, T* oldValue)
  31. {
  32. return static_cast<T*>(UnityPalCompareExchangePointer((void*volatile*)dest, newValue, oldValue));
  33. }
  34. template<typename T>
  35. static inline T* ExchangePointer(T* volatile* dest, T* newValue)
  36. {
  37. return static_cast<T*>(UnityPalExchangePointer((void*volatile*)dest, newValue));
  38. }
  39. static inline int64_t Read64(volatile int64_t* addr)
  40. {
  41. return UnityPalRead64(addr);
  42. }
  43. static inline uint64_t Read64(volatile uint64_t* addr)
  44. {
  45. return (uint64_t)Read64((volatile int64_t*)addr);
  46. }
  47. template<typename T>
  48. static inline T* ReadPointer(T* volatile* pointer)
  49. {
  50. #if IL2CPP_SIZEOF_VOID_P == 4
  51. return reinterpret_cast<T*>(Add(reinterpret_cast<volatile int32_t*>(pointer), 0));
  52. #else
  53. return reinterpret_cast<T*>(Add64(reinterpret_cast<volatile int64_t*>(pointer), 0));
  54. #endif
  55. }
  56. static inline int32_t Increment(volatile int32_t* value)
  57. {
  58. return UnityPalIncrement(value);
  59. }
  60. static inline uint32_t Increment(volatile uint32_t* value)
  61. {
  62. return (uint32_t)Increment((volatile int32_t*)value);
  63. }
  64. static inline int64_t Increment64(volatile int64_t* value)
  65. {
  66. return UnityPalIncrement64(value);
  67. }
  68. static inline uint64_t Increment64(volatile uint64_t* value)
  69. {
  70. return (uint64_t)Increment64((volatile int64_t*)value);
  71. }
  72. static inline int32_t Decrement(volatile int32_t* value)
  73. {
  74. return UnityPalDecrement(value);
  75. }
  76. static inline uint32_t Decrement(volatile uint32_t* value)
  77. {
  78. return (uint32_t)Decrement((volatile int32_t*)value);
  79. }
  80. static inline int64_t Decrement64(volatile int64_t* value)
  81. {
  82. return UnityPalDecrement64(value);
  83. }
  84. static inline uint64_t Decrement64(volatile uint64_t* value)
  85. {
  86. return (uint64_t)Decrement64((volatile int64_t*)value);
  87. }
  88. static inline int32_t CompareExchange(volatile int32_t* dest, int32_t exchange, int32_t comparand)
  89. {
  90. return UnityPalCompareExchange(dest, exchange, comparand);
  91. }
  92. static inline uint32_t CompareExchange(volatile uint32_t* value, uint32_t newValue, uint32_t oldValue)
  93. {
  94. return (uint32_t)CompareExchange((volatile int32_t*)value, newValue, oldValue);
  95. }
  96. static inline int64_t CompareExchange64(volatile int64_t* dest, int64_t exchange, int64_t comparand)
  97. {
  98. return UnityPalCompareExchange64(dest, exchange, comparand);
  99. }
  100. static inline uint64_t CompareExchange64(volatile uint64_t* value, uint64_t newValue, uint64_t oldValue)
  101. {
  102. return (uint64_t)CompareExchange64((volatile int64_t*)value, newValue, oldValue);
  103. }
  104. static inline int32_t Exchange(volatile int32_t* dest, int32_t exchange)
  105. {
  106. return UnityPalExchange(dest, exchange);
  107. }
  108. static inline uint32_t Exchange(volatile uint32_t* value, uint32_t newValue)
  109. {
  110. return (uint32_t)Exchange((volatile int32_t*)value, newValue);
  111. }
  112. static inline int64_t Exchange64(volatile int64_t* dest, int64_t exchange)
  113. {
  114. return UnityPalExchange64(dest, exchange);
  115. }
  116. static inline uint64_t Exchange64(volatile uint64_t* value, uint64_t newValue)
  117. {
  118. return (uint64_t)Exchange64((volatile int64_t*)value, newValue);
  119. }
  120. };
  121. }
  122. }
  123. #if !IL2CPP_SUPPORT_THREADS
  124. namespace il2cpp
  125. {
  126. namespace os
  127. {
  128. inline void Atomic::FullMemoryBarrier()
  129. {
  130. // Do nothing.
  131. }
  132. }
  133. }
  134. #elif IL2CPP_TARGET_WINDOWS
  135. #include "os/Win32/AtomicImpl.h"
  136. #elif IL2CPP_TARGET_PS4
  137. #include "os/AtomicImpl.h" // has to come earlier than posix
  138. #elif IL2CPP_TARGET_PSP2
  139. #include "os/PSP2/AtomicImpl.h"
  140. #elif IL2CPP_TARGET_POSIX
  141. #include "os/Posix/AtomicImpl.h"
  142. #else
  143. #include "os/AtomicImpl.h"
  144. #endif