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
26AWS_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
36typedef size_t aws_atomic_impl_int_t;
37
38static 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 */
59AWS_STATIC_IMPL
60void 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 */
68AWS_STATIC_IMPL
69void 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 */
76AWS_STATIC_IMPL
77size_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 */
84AWS_STATIC_IMPL
85void *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 */
92AWS_STATIC_IMPL
93void 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 */
100AWS_STATIC_IMPL
101void 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 */
109AWS_STATIC_IMPL
110size_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 */
121AWS_STATIC_IMPL
122void *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 */
134AWS_STATIC_IMPL
135bool 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 */
155AWS_STATIC_IMPL
156bool 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 */
174AWS_STATIC_IMPL
175size_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 */
182AWS_STATIC_IMPL
183size_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 */
190AWS_STATIC_IMPL
191size_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 */
198AWS_STATIC_IMPL
199size_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 */
206AWS_STATIC_IMPL
207size_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 */
215AWS_STATIC_IMPL
216void 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
227AWS_EXTERN_C_END
228#endif /* AWS_COMMON_ATOMICS_GNU_INL */
229