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