1/**
2 * hdr_atomic.h
3 * Written by Philip Orwig and released to the public domain,
4 * as explained at http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7#ifndef HDR_ATOMIC_H__
8#define HDR_ATOMIC_H__
9
10
11#if defined(_MSC_VER)
12
13#include <stdint.h>
14#include <intrin.h>
15#include <stdbool.h>
16
17static void __inline * hdr_atomic_load_pointer(void** pointer)
18{
19 _ReadBarrier();
20 return *pointer;
21}
22
23static void hdr_atomic_store_pointer(void** pointer, void* value)
24{
25 _WriteBarrier();
26 *pointer = value;
27}
28
29static int64_t __inline hdr_atomic_load_64(int64_t* field)
30{
31 _ReadBarrier();
32 return *field;
33}
34
35static void __inline hdr_atomic_store_64(int64_t* field, int64_t value)
36{
37 _WriteBarrier();
38 *field = value;
39}
40
41static int64_t __inline hdr_atomic_exchange_64(volatile int64_t* field, int64_t value)
42{
43#if defined(_WIN64)
44 return _InterlockedExchange64(field, value);
45#else
46 int64_t comparand;
47 int64_t initial_value = *field;
48 do
49 {
50 comparand = initial_value;
51 initial_value = _InterlockedCompareExchange64(field, value, comparand);
52 }
53 while (comparand != initial_value);
54
55 return initial_value;
56#endif
57}
58
59static int64_t __inline hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
60{
61#if defined(_WIN64)
62 return _InterlockedExchangeAdd64(field, value) + value;
63#else
64 int64_t comparand;
65 int64_t initial_value = *field;
66 do
67 {
68 comparand = initial_value;
69 initial_value = _InterlockedCompareExchange64(field, comparand + value, comparand);
70 }
71 while (comparand != initial_value);
72
73 return initial_value + value;
74#endif
75}
76
77static bool __inline hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired)
78{
79 return *expected == _InterlockedCompareExchange64(field, desired, *expected);
80}
81
82#elif defined(__ATOMIC_SEQ_CST)
83
84#define hdr_atomic_load_pointer(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
85#define hdr_atomic_store_pointer(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST)
86#define hdr_atomic_load_64(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
87#define hdr_atomic_store_64(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST)
88#define hdr_atomic_exchange_64(f,i) __atomic_exchange_n(f,i, __ATOMIC_SEQ_CST)
89#define hdr_atomic_add_fetch_64(field, value) __atomic_add_fetch(field, value, __ATOMIC_SEQ_CST)
90#define hdr_atomic_compare_exchange_64(field, expected, desired) __atomic_compare_exchange_n(field, expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
91
92#elif defined(__x86_64__)
93
94#include <stdint.h>
95#include <stdbool.h>
96
97static inline void* hdr_atomic_load_pointer(void** pointer)
98{
99 void* p = *pointer;
100 asm volatile ("" ::: "memory");
101 return p;
102}
103
104static inline void hdr_atomic_store_pointer(void** pointer, void* value)
105{
106 asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*pointer));
107}
108
109static inline int64_t hdr_atomic_load_64(int64_t* field)
110{
111 int64_t i = *field;
112 asm volatile ("" ::: "memory");
113 return i;
114}
115
116static inline void hdr_atomic_store_64(int64_t* field, int64_t value)
117{
118 asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*field));
119}
120
121static inline int64_t hdr_atomic_exchange_64(volatile int64_t* field, int64_t value)
122{
123 int64_t result = 0;
124 asm volatile ("lock; xchgq %1, %2" : "=r" (result), "+q" (value), "+m" (*field));
125 return result;
126}
127
128static inline int64_t hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
129{
130 return __sync_add_and_fetch(field, value);
131}
132
133static inline bool hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired)
134{
135 int64_t original;
136 asm volatile( "lock; cmpxchgq %2, %1" : "=a"(original), "+m"(*field) : "q"(desired), "0"(*expected));
137 return original == *expected;
138}
139
140#else
141
142#error "Unable to determine atomic operations for your platform"
143
144#endif
145
146#endif /* HDR_ATOMIC_H__ */
147