1 | #ifndef AWS_COMMON_ATOMICS_GNU_INL |
2 | #define AWS_COMMON_ATOMICS_GNU_INL |
3 | |
4 | /* |
5 | * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"). |
8 | * You may not use this file except in compliance with the License. |
9 | * A copy of the License is located at |
10 | * |
11 | * http://aws.amazon.com/apache2.0 |
12 | * |
13 | * or in the "license" file accompanying this file. This file is distributed |
14 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
15 | * express or implied. See the License for the specific language governing |
16 | * permissions and limitations under the License. |
17 | */ |
18 | |
19 | /* These are implicitly included, but help with editor highlighting */ |
20 | #include <aws/common/atomics.h> |
21 | #include <aws/common/common.h> |
22 | |
23 | #include <stdint.h> |
24 | #include <stdlib.h> |
25 | |
26 | AWS_EXTERN_C_BEGIN |
27 | |
28 | #ifdef __clang__ |
29 | # pragma clang diagnostic push |
30 | # pragma clang diagnostic ignored "-Wc11-extensions" |
31 | #else |
32 | # pragma GCC diagnostic push |
33 | # pragma GCC diagnostic ignored "-Wpedantic" |
34 | #endif |
35 | |
36 | typedef size_t aws_atomic_impl_int_t; |
37 | |
38 | static inline int aws_atomic_priv_xlate_order(enum aws_memory_order order) { |
39 | switch (order) { |
40 | case aws_memory_order_relaxed: |
41 | return __ATOMIC_RELAXED; |
42 | case aws_memory_order_acquire: |
43 | return __ATOMIC_ACQUIRE; |
44 | case aws_memory_order_release: |
45 | return __ATOMIC_RELEASE; |
46 | case aws_memory_order_acq_rel: |
47 | return __ATOMIC_ACQ_REL; |
48 | case aws_memory_order_seq_cst: |
49 | return __ATOMIC_SEQ_CST; |
50 | default: /* Unknown memory order */ |
51 | abort(); |
52 | } |
53 | } |
54 | |
55 | /** |
56 | * Initializes an atomic variable with an integer value. This operation should be done before any |
57 | * other operations on this atomic variable, and must be done before attempting any parallel operations. |
58 | */ |
59 | AWS_STATIC_IMPL |
60 | void aws_atomic_init_int(volatile struct aws_atomic_var *var, size_t n) { |
61 | AWS_ATOMIC_VAR_INTVAL(var) = n; |
62 | } |
63 | |
64 | /** |
65 | * Initializes an atomic variable with a pointer value. This operation should be done before any |
66 | * other operations on this atomic variable, and must be done before attempting any parallel operations. |
67 | */ |
68 | AWS_STATIC_IMPL |
69 | void aws_atomic_init_ptr(volatile struct aws_atomic_var *var, void *p) { |
70 | AWS_ATOMIC_VAR_PTRVAL(var) = p; |
71 | } |
72 | |
73 | /** |
74 | * Reads an atomic var as an integer, using the specified ordering, and returns the result. |
75 | */ |
76 | AWS_STATIC_IMPL |
77 | size_t aws_atomic_load_int_explicit(volatile const struct aws_atomic_var *var, enum aws_memory_order memory_order) { |
78 | return __atomic_load_n(&AWS_ATOMIC_VAR_INTVAL(var), aws_atomic_priv_xlate_order(memory_order)); |
79 | } |
80 | |
81 | /** |
82 | * Reads an atomic var as an pointer, using the specified ordering, and returns the result. |
83 | */ |
84 | AWS_STATIC_IMPL |
85 | void *aws_atomic_load_ptr_explicit(volatile const struct aws_atomic_var *var, enum aws_memory_order memory_order) { |
86 | return __atomic_load_n(&AWS_ATOMIC_VAR_PTRVAL(var), aws_atomic_priv_xlate_order(memory_order)); |
87 | } |
88 | |
89 | /** |
90 | * Stores an integer into an atomic var, using the specified ordering. |
91 | */ |
92 | AWS_STATIC_IMPL |
93 | void aws_atomic_store_int_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order memory_order) { |
94 | __atomic_store_n(&AWS_ATOMIC_VAR_INTVAL(var), n, aws_atomic_priv_xlate_order(memory_order)); |
95 | } |
96 | |
97 | /** |
98 | * Stores an pointer into an atomic var, using the specified ordering. |
99 | */ |
100 | AWS_STATIC_IMPL |
101 | void aws_atomic_store_ptr_explicit(volatile struct aws_atomic_var *var, void *p, enum aws_memory_order memory_order) { |
102 | __atomic_store_n(&AWS_ATOMIC_VAR_PTRVAL(var), p, aws_atomic_priv_xlate_order(memory_order)); |
103 | } |
104 | |
105 | /** |
106 | * Exchanges an integer with the value in an atomic_var, using the specified ordering. |
107 | * Returns the value that was previously in the atomic_var. |
108 | */ |
109 | AWS_STATIC_IMPL |
110 | size_t aws_atomic_exchange_int_explicit( |
111 | volatile struct aws_atomic_var *var, |
112 | size_t n, |
113 | enum aws_memory_order memory_order) { |
114 | return __atomic_exchange_n(&AWS_ATOMIC_VAR_INTVAL(var), n, aws_atomic_priv_xlate_order(memory_order)); |
115 | } |
116 | |
117 | /** |
118 | * Exchanges a pointer with the value in an atomic_var, using the specified ordering. |
119 | * Returns the value that was previously in the atomic_var. |
120 | */ |
121 | AWS_STATIC_IMPL |
122 | void *aws_atomic_exchange_ptr_explicit( |
123 | volatile struct aws_atomic_var *var, |
124 | void *p, |
125 | enum aws_memory_order memory_order) { |
126 | return __atomic_exchange_n(&AWS_ATOMIC_VAR_PTRVAL(var), p, aws_atomic_priv_xlate_order(memory_order)); |
127 | } |
128 | |
129 | /** |
130 | * Atomically compares *var to *expected; if they are equal, atomically sets *var = desired. Otherwise, *expected is set |
131 | * to the value in *var. On success, the memory ordering used was order_success; otherwise, it was order_failure. |
132 | * order_failure must be no stronger than order_success, and must not be release or acq_rel. |
133 | */ |
134 | AWS_STATIC_IMPL |
135 | bool aws_atomic_compare_exchange_int_explicit( |
136 | volatile struct aws_atomic_var *var, |
137 | size_t *expected, |
138 | size_t desired, |
139 | enum aws_memory_order order_success, |
140 | enum aws_memory_order order_failure) { |
141 | return __atomic_compare_exchange_n( |
142 | &AWS_ATOMIC_VAR_INTVAL(var), |
143 | expected, |
144 | desired, |
145 | false, |
146 | aws_atomic_priv_xlate_order(order_success), |
147 | aws_atomic_priv_xlate_order(order_failure)); |
148 | } |
149 | |
150 | /** |
151 | * Atomically compares *var to *expected; if they are equal, atomically sets *var = desired. Otherwise, *expected is set |
152 | * to the value in *var. On success, the memory ordering used was order_success; otherwise, it was order_failure. |
153 | * order_failure must be no stronger than order_success, and must not be release or acq_rel. |
154 | */ |
155 | AWS_STATIC_IMPL |
156 | bool aws_atomic_compare_exchange_ptr_explicit( |
157 | volatile struct aws_atomic_var *var, |
158 | void **expected, |
159 | void *desired, |
160 | enum aws_memory_order order_success, |
161 | enum aws_memory_order order_failure) { |
162 | return __atomic_compare_exchange_n( |
163 | &AWS_ATOMIC_VAR_PTRVAL(var), |
164 | expected, |
165 | desired, |
166 | false, |
167 | aws_atomic_priv_xlate_order(order_success), |
168 | aws_atomic_priv_xlate_order(order_failure)); |
169 | } |
170 | |
171 | /** |
172 | * Atomically adds n to *var, and returns the previous value of *var. |
173 | */ |
174 | AWS_STATIC_IMPL |
175 | size_t aws_atomic_fetch_add_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) { |
176 | return __atomic_fetch_add(&AWS_ATOMIC_VAR_INTVAL(var), n, aws_atomic_priv_xlate_order(order)); |
177 | } |
178 | |
179 | /** |
180 | * Atomically subtracts n from *var, and returns the previous value of *var. |
181 | */ |
182 | AWS_STATIC_IMPL |
183 | size_t aws_atomic_fetch_sub_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) { |
184 | return __atomic_fetch_sub(&AWS_ATOMIC_VAR_INTVAL(var), n, aws_atomic_priv_xlate_order(order)); |
185 | } |
186 | |
187 | /** |
188 | * Atomically ORs n with *var, and returns the previous value of *var. |
189 | */ |
190 | AWS_STATIC_IMPL |
191 | size_t aws_atomic_fetch_or_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) { |
192 | return __atomic_fetch_or(&AWS_ATOMIC_VAR_INTVAL(var), n, aws_atomic_priv_xlate_order(order)); |
193 | } |
194 | |
195 | /** |
196 | * Atomically ANDs n with *var, and returns the previous value of *var. |
197 | */ |
198 | AWS_STATIC_IMPL |
199 | size_t aws_atomic_fetch_and_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) { |
200 | return __atomic_fetch_and(&AWS_ATOMIC_VAR_INTVAL(var), n, aws_atomic_priv_xlate_order(order)); |
201 | } |
202 | |
203 | /** |
204 | * Atomically XORs n with *var, and returns the previous value of *var. |
205 | */ |
206 | AWS_STATIC_IMPL |
207 | size_t aws_atomic_fetch_xor_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) { |
208 | return __atomic_fetch_xor(&AWS_ATOMIC_VAR_INTVAL(var), n, aws_atomic_priv_xlate_order(order)); |
209 | } |
210 | |
211 | /** |
212 | * Provides the same reordering guarantees as an atomic operation with the specified memory order, without |
213 | * needing to actually perform an atomic operation. |
214 | */ |
215 | AWS_STATIC_IMPL |
216 | void aws_atomic_thread_fence(enum aws_memory_order order) { |
217 | __atomic_thread_fence(order); |
218 | } |
219 | |
220 | #ifdef __clang__ |
221 | # pragma clang diagnostic pop |
222 | #else |
223 | # pragma GCC diagnostic pop |
224 | #endif |
225 | |
226 | #define AWS_ATOMICS_HAVE_THREAD_FENCE |
227 | AWS_EXTERN_C_END |
228 | #endif /* AWS_COMMON_ATOMICS_GNU_INL */ |
229 | |