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