ua_util.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
  4. #ifndef UA_UTIL_H_
  5. #define UA_UTIL_H_
  6. #include "ua_config.h"
  7. /* Assert */
  8. #include <assert.h>
  9. #define UA_assert(ignore) assert(ignore)
  10. /* BSD Queue Macros */
  11. #include "queue.h"
  12. /* container_of */
  13. #define container_of(ptr, type, member) \
  14. (type *)((uintptr_t)ptr - offsetof(type,member))
  15. /* Thread-Local Storage
  16. * --------------------
  17. * Thread-local variables are always enabled. Also when the library is built
  18. * with ``UA_ENABLE_MULTITHREADING`` disabled. Otherwise, if multiple clients
  19. * run in separate threads, race conditions may occur via global variables in
  20. * the encoding layer. */
  21. #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
  22. # define UA_THREAD_LOCAL _Thread_local /* C11 */
  23. #elif defined(__GNUC__)
  24. # define UA_THREAD_LOCAL __thread /* GNU extension */
  25. #elif defined(_MSC_VER)
  26. # define UA_THREAD_LOCAL __declspec(thread) /* MSVC extension */
  27. #else
  28. # warning The compiler does not support thread-local variables
  29. # define UA_THREAD_LOCAL
  30. #endif
  31. /* Atomic Operations
  32. * -----------------
  33. * Atomic operations that synchronize across processor cores (for
  34. * multithreading). Only the inline-functions defined next are used. Replace
  35. * with architecture-specific operations if necessary. */
  36. #ifndef UA_ENABLE_MULTITHREADING
  37. # define UA_atomic_sync()
  38. #else
  39. # ifdef _MSC_VER /* Visual Studio */
  40. # define UA_atomic_sync() _ReadWriteBarrier()
  41. # else /* GCC/Clang */
  42. # define UA_atomic_sync() __sync_synchronize()
  43. # endif
  44. #endif
  45. static UA_INLINE void *
  46. UA_atomic_xchg(void * volatile * addr, void *newptr) {
  47. #ifndef UA_ENABLE_MULTITHREADING
  48. void *old = *addr;
  49. *addr = newptr;
  50. return old;
  51. #else
  52. # ifdef _MSC_VER /* Visual Studio */
  53. return _InterlockedExchangePointer(addr, newptr);
  54. # else /* GCC/Clang */
  55. return __sync_lock_test_and_set(addr, newptr);
  56. # endif
  57. #endif
  58. }
  59. static UA_INLINE void *
  60. UA_atomic_cmpxchg(void * volatile * addr, void *expected, void *newptr) {
  61. #ifndef UA_ENABLE_MULTITHREADING
  62. void *old = *addr;
  63. if(old == expected) {
  64. *addr = newptr;
  65. }
  66. return old;
  67. #else
  68. # ifdef _MSC_VER /* Visual Studio */
  69. return _InterlockedCompareExchangePointer(addr, expected, newptr);
  70. # else /* GCC/Clang */
  71. return __sync_val_compare_and_swap(addr, expected, newptr);
  72. # endif
  73. #endif
  74. }
  75. static UA_INLINE uint32_t
  76. UA_atomic_add(volatile uint32_t *addr, uint32_t increase) {
  77. #ifndef UA_ENABLE_MULTITHREADING
  78. *addr += increase;
  79. return *addr;
  80. #else
  81. # ifdef _MSC_VER /* Visual Studio */
  82. return _InterlockedExchangeAdd(addr, increase) + increase;
  83. # else /* GCC/Clang */
  84. return __sync_add_and_fetch(addr, increase);
  85. # endif
  86. #endif
  87. }
  88. #endif /* UA_UTIL_H_ */