#ifndef AWS_COMMON_ATOMICS_MSVC_INL
#define AWS_COMMON_ATOMICS_MSVC_INL
#include <aws/common/atomics.h>
#include <aws/common/common.h>
#include <intrin.h>
#include <stdint.h>
#include <stdlib.h>
AWS_EXTERN_C_BEGIN
#if !(defined(_M_IX86) || defined(_M_X64))
# error Atomics are not currently supported for non-x86 MSVC platforms
#endif
#ifdef _M_IX86
# define AWS_INTERLOCKED_INT(x) _Interlocked##x
typedef long aws_atomic_impl_int_t;
#else
# define AWS_INTERLOCKED_INT(x) _Interlocked##x##64
typedef long long aws_atomic_impl_int_t;
#endif
static inline void aws_atomic_priv_check_order(enum aws_memory_order order) {
#ifndef NDEBUG
switch (order) {
case aws_memory_order_relaxed:
return;
case aws_memory_order_acquire:
return;
case aws_memory_order_release:
return;
case aws_memory_order_acq_rel:
return;
case aws_memory_order_seq_cst:
return;
default:
abort();
}
#endif
(void)order;
}
enum aws_atomic_mode_priv { aws_atomic_priv_load, aws_atomic_priv_store };
static inline void aws_atomic_priv_barrier_before(enum aws_memory_order order, enum aws_atomic_mode_priv mode) {
aws_atomic_priv_check_order(order);
AWS_ASSERT(mode != aws_atomic_priv_load || order != aws_memory_order_release);
if (order == aws_memory_order_relaxed) {
return;
}
if (order == aws_memory_order_acquire || mode == aws_atomic_priv_load) {
return;
}
_ReadWriteBarrier();
}
static inline void aws_atomic_priv_barrier_after(enum aws_memory_order order, enum aws_atomic_mode_priv mode) {
aws_atomic_priv_check_order(order);
AWS_ASSERT(mode != aws_atomic_priv_store || order != aws_memory_order_acquire);
if (order == aws_memory_order_relaxed) {
return;
}
if (order == aws_memory_order_release || mode == aws_atomic_priv_store) {
return;
}
_ReadWriteBarrier();
}
AWS_STATIC_IMPL
void aws_atomic_init_int(volatile struct aws_atomic_var *var, size_t n) {
AWS_ATOMIC_VAR_INTVAL(var) = n;
}
AWS_STATIC_IMPL
void aws_atomic_init_ptr(volatile struct aws_atomic_var *var, void *p) {
AWS_ATOMIC_VAR_PTRVAL(var) = p;
}
AWS_STATIC_IMPL
size_t aws_atomic_load_int_explicit(volatile const struct aws_atomic_var *var, enum aws_memory_order memory_order) {
aws_atomic_priv_barrier_before(memory_order, aws_atomic_priv_load);
size_t result = AWS_ATOMIC_VAR_INTVAL(var);
aws_atomic_priv_barrier_after(memory_order, aws_atomic_priv_load);
return result;
}
AWS_STATIC_IMPL
void *aws_atomic_load_ptr_explicit(volatile const struct aws_atomic_var *var, enum aws_memory_order memory_order) {
aws_atomic_priv_barrier_before(memory_order, aws_atomic_priv_load);
void *result = AWS_ATOMIC_VAR_PTRVAL(var);
aws_atomic_priv_barrier_after(memory_order, aws_atomic_priv_load);
return result;
}
AWS_STATIC_IMPL
void aws_atomic_store_int_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order memory_order) {
if (memory_order != aws_memory_order_seq_cst) {
aws_atomic_priv_barrier_before(memory_order, aws_atomic_priv_store);
AWS_ATOMIC_VAR_INTVAL(var) = n;
aws_atomic_priv_barrier_after(memory_order, aws_atomic_priv_store);
} else {
AWS_INTERLOCKED_INT(Exchange)(&AWS_ATOMIC_VAR_INTVAL(var), n);
}
}
AWS_STATIC_IMPL
void aws_atomic_store_ptr_explicit(volatile struct aws_atomic_var *var, void *p, enum aws_memory_order memory_order) {
aws_atomic_priv_check_order(memory_order);
if (memory_order != aws_memory_order_seq_cst) {
aws_atomic_priv_barrier_before(memory_order, aws_atomic_priv_store);
AWS_ATOMIC_VAR_PTRVAL(var) = p;
aws_atomic_priv_barrier_after(memory_order, aws_atomic_priv_store);
} else {
_InterlockedExchangePointer(&AWS_ATOMIC_VAR_PTRVAL(var), p);
}
}
AWS_STATIC_IMPL
size_t aws_atomic_exchange_int_explicit(
volatile struct aws_atomic_var *var,
size_t n,
enum aws_memory_order memory_order) {
aws_atomic_priv_check_order(memory_order);
return AWS_INTERLOCKED_INT(Exchange)(&AWS_ATOMIC_VAR_INTVAL(var), n);
}
AWS_STATIC_IMPL
void *aws_atomic_exchange_ptr_explicit(
volatile struct aws_atomic_var *var,
void *p,
enum aws_memory_order memory_order) {
aws_atomic_priv_check_order(memory_order);
return _InterlockedExchangePointer(&AWS_ATOMIC_VAR_PTRVAL(var), p);
}
AWS_STATIC_IMPL
bool aws_atomic_compare_exchange_int_explicit(
volatile struct aws_atomic_var *var,
size_t *expected,
size_t desired,
enum aws_memory_order order_success,
enum aws_memory_order order_failure) {
aws_atomic_priv_check_order(order_success);
aws_atomic_priv_check_order(order_failure);
size_t oldval = AWS_INTERLOCKED_INT(CompareExchange)(&AWS_ATOMIC_VAR_INTVAL(var), desired, *expected);
bool successful = oldval == *expected;
*expected = oldval;
return successful;
}
AWS_STATIC_IMPL
bool aws_atomic_compare_exchange_ptr_explicit(
volatile struct aws_atomic_var *var,
void **expected,
void *desired,
enum aws_memory_order order_success,
enum aws_memory_order order_failure) {
aws_atomic_priv_check_order(order_success);
aws_atomic_priv_check_order(order_failure);
void *oldval = _InterlockedCompareExchangePointer(&AWS_ATOMIC_VAR_PTRVAL(var), desired, *expected);
bool successful = oldval == *expected;
*expected = oldval;
return successful;
}
AWS_STATIC_IMPL
size_t aws_atomic_fetch_add_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) {
aws_atomic_priv_check_order(order);
return AWS_INTERLOCKED_INT(ExchangeAdd)(&AWS_ATOMIC_VAR_INTVAL(var), n);
}
AWS_STATIC_IMPL
size_t aws_atomic_fetch_sub_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) {
aws_atomic_priv_check_order(order);
return AWS_INTERLOCKED_INT(ExchangeAdd)(&AWS_ATOMIC_VAR_INTVAL(var), -(aws_atomic_impl_int_t)n);
}
AWS_STATIC_IMPL
size_t aws_atomic_fetch_or_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) {
aws_atomic_priv_check_order(order);
return AWS_INTERLOCKED_INT(Or)(&AWS_ATOMIC_VAR_INTVAL(var), n);
}
AWS_STATIC_IMPL
size_t aws_atomic_fetch_and_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) {
aws_atomic_priv_check_order(order);
return AWS_INTERLOCKED_INT(And)(&AWS_ATOMIC_VAR_INTVAL(var), n);
}
AWS_STATIC_IMPL
size_t aws_atomic_fetch_xor_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order) {
aws_atomic_priv_check_order(order);
return AWS_INTERLOCKED_INT(Xor)(&AWS_ATOMIC_VAR_INTVAL(var), n);
}
AWS_STATIC_IMPL
void aws_atomic_thread_fence(enum aws_memory_order order) {
volatile aws_atomic_impl_int_t x = 0;
aws_atomic_priv_check_order(order);
switch (order) {
case aws_memory_order_seq_cst:
AWS_INTERLOCKED_INT(Exchange)(&x, 1);
break;
case aws_memory_order_release:
case aws_memory_order_acquire:
case aws_memory_order_acq_rel:
_ReadWriteBarrier();
break;
case aws_memory_order_relaxed:
break;
}
}
#define AWS_ATOMICS_HAVE_THREAD_FENCE
AWS_EXTERN_C_END
#endif