LCOV - code coverage report
Current view: top level - aws-c-common/include/aws/common - atomics.h (source / functions) Hit Total Coverage
Test: all_fuzz.info Lines: 1 2 50.0 %
Date: 2021-04-23 16:28:21 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef AWS_COMMON_ATOMICS_H
       2             : #define AWS_COMMON_ATOMICS_H
       3             : 
       4             : #include <aws/common/common.h>
       5             : 
       6             : /**
       7             :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       8             :  * SPDX-License-Identifier: Apache-2.0.
       9             :  */
      10             : 
      11             : /**
      12             :  * struct aws_atomic_var represents an atomic variable - a value which can hold an integer or pointer
      13             :  * that can be manipulated atomically. struct aws_atomic_vars should normally only be manipulated
      14             :  * with atomics methods defined in this header.
      15             :  */
      16             : struct aws_atomic_var {
      17             :     void *value;
      18             : };
      19             : /* Helpers for extracting the integer and pointer values from aws_atomic_var. */
      20      145838 : #define AWS_ATOMIC_VAR_PTRVAL(var) ((var)->value)
      21           0 : #define AWS_ATOMIC_VAR_INTVAL(var) (*(aws_atomic_impl_int_t *)(var))
      22             : 
      23             : /*
      24             :  * This enumeration specifies the memory ordering properties requested for a particular
      25             :  * atomic operation. The atomic operation may provide stricter ordering than requested.
      26             :  * Note that, within a single thread, all operations are still sequenced (that is, a thread
      27             :  * sees its own atomic writes and reads happening in program order, but other threads may
      28             :  * disagree on this ordering).
      29             :  *
      30             :  * The behavior of these memory orderings are the same as in the C11 atomics API; however,
      31             :  * we only implement a subset that can be portably implemented on the compilers we target.
      32             :  */
      33             : 
      34             : enum aws_memory_order {
      35             :     /**
      36             :      * No particular ordering constraints are guaranteed relative to other
      37             :      * operations at all; we merely ensure that the operation itself is atomic.
      38             :      */
      39             :     aws_memory_order_relaxed = 0,
      40             :     /* aws_memory_order_consume - not currently implemented */
      41             : 
      42             :     /**
      43             :      * Specifies acquire ordering. No reads or writes on the current thread can be
      44             :      * reordered to happen before this operation. This is typically paired with a release
      45             :      * ordering; any writes that happened on the releasing operation will be visible
      46             :      * after the paired acquire operation.
      47             :      *
      48             :      * Acquire ordering is only meaningful on load or load-store operations.
      49             :      */
      50             :     aws_memory_order_acquire = 2, /* leave a spot for consume if we ever add it */
      51             : 
      52             :     /**
      53             :      * Specifies release order. No reads or writes can be reordered to come after this
      54             :      * operation. Typically paired with an acquire operation.
      55             :      *
      56             :      * Release ordering is only meaningful on store or load-store operations.
      57             :      */
      58             :     aws_memory_order_release,
      59             : 
      60             :     /**
      61             :      * Specifies acquire-release order; if this operation acts as a load, it acts as an
      62             :      * acquire operation; if it acts as a store, it acts as a release operation; if it's
      63             :      * a load-store, it does both.
      64             :      */
      65             :     aws_memory_order_acq_rel,
      66             : 
      67             :     /*
      68             :      * Specifies sequentially consistent order. This behaves as acq_rel, but in addition,
      69             :      * all seq_cst operations appear to occur in some globally consistent order.
      70             :      *
      71             :      * TODO: Figure out how to correctly implement this in MSVC. It appears that interlocked
      72             :      * functions provide only acq_rel ordering.
      73             :      */
      74             :     aws_memory_order_seq_cst
      75             : };
      76             : 
      77             : /**
      78             :  * Statically initializes an aws_atomic_var to a given size_t value.
      79             :  */
      80             : #define AWS_ATOMIC_INIT_INT(x)                                                                                         \
      81             :     { .value = (void *)(uintptr_t)(x) }
      82             : 
      83             : /**
      84             :  * Statically initializes an aws_atomic_var to a given void * value.
      85             :  */
      86             : #define AWS_ATOMIC_INIT_PTR(x)                                                                                         \
      87             :     { .value = (void *)(x) }
      88             : 
      89             : AWS_EXTERN_C_BEGIN
      90             : 
      91             : /*
      92             :  * Note: We do not use the C11 atomics API; this is because we want to make sure the representation
      93             :  * (and behavior) of atomic values is consistent, regardless of what --std= flag you pass to your compiler.
      94             :  * Since C11 atomics can silently introduce locks, we run the risk of creating such ABI inconsistencies
      95             :  * if we decide based on compiler features which atomics API to use, and in practice we expect to have
      96             :  * either the GNU or MSVC atomics anyway.
      97             :  *
      98             :  * As future work, we could test to see if the C11 atomics API on this platform behaves consistently
      99             :  * with the other APIs and use it if it does.
     100             :  */
     101             : 
     102             : /**
     103             :  * Initializes an atomic variable with an integer value. This operation should be done before any
     104             :  * other operations on this atomic variable, and must be done before attempting any parallel operations.
     105             :  *
     106             :  * This operation does not imply a barrier. Ensure that you use an acquire-release barrier (or stronger)
     107             :  * when communicating the fact that initialization is complete to the other thread. Launching the thread
     108             :  * implies a sufficiently strong barrier.
     109             :  */
     110             : AWS_STATIC_IMPL
     111             : void aws_atomic_init_int(volatile struct aws_atomic_var *var, size_t n);
     112             : 
     113             : /**
     114             :  * Initializes an atomic variable with a pointer value. This operation should be done before any
     115             :  * other operations on this atomic variable, and must be done before attempting any parallel operations.
     116             :  *
     117             :  * This operation does not imply a barrier. Ensure that you use an acquire-release barrier (or stronger)
     118             :  * when communicating the fact that initialization is complete to the other thread. Launching the thread
     119             :  * implies a sufficiently strong barrier.
     120             :  */
     121             : AWS_STATIC_IMPL
     122             : void aws_atomic_init_ptr(volatile struct aws_atomic_var *var, void *p);
     123             : 
     124             : /**
     125             :  * Reads an atomic var as an integer, using the specified ordering, and returns the result.
     126             :  */
     127             : AWS_STATIC_IMPL
     128             : size_t aws_atomic_load_int_explicit(volatile const struct aws_atomic_var *var, enum aws_memory_order memory_order);
     129             : 
     130             : /**
     131             :  * Reads an atomic var as an integer, using sequentially consistent ordering, and returns the result.
     132             :  */
     133             : AWS_STATIC_IMPL
     134             : size_t aws_atomic_load_int(volatile const struct aws_atomic_var *var);
     135             : /**
     136             :  * Reads an atomic var as a pointer, using the specified ordering, and returns the result.
     137             :  */
     138             : AWS_STATIC_IMPL
     139             : void *aws_atomic_load_ptr_explicit(volatile const struct aws_atomic_var *var, enum aws_memory_order memory_order);
     140             : 
     141             : /**
     142             :  * Reads an atomic var as a pointer, using sequentially consistent ordering, and returns the result.
     143             :  */
     144             : AWS_STATIC_IMPL
     145             : void *aws_atomic_load_ptr(volatile const struct aws_atomic_var *var);
     146             : 
     147             : /**
     148             :  * Stores an integer into an atomic var, using the specified ordering.
     149             :  */
     150             : AWS_STATIC_IMPL
     151             : void aws_atomic_store_int_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order memory_order);
     152             : 
     153             : /**
     154             :  * Stores an integer into an atomic var, using sequentially consistent ordering.
     155             :  */
     156             : AWS_STATIC_IMPL
     157             : void aws_atomic_store_int(volatile struct aws_atomic_var *var, size_t n);
     158             : 
     159             : /**
     160             :  * Stores a pointer into an atomic var, using the specified ordering.
     161             :  */
     162             : AWS_STATIC_IMPL
     163             : void aws_atomic_store_ptr_explicit(volatile struct aws_atomic_var *var, void *p, enum aws_memory_order memory_order);
     164             : 
     165             : /**
     166             :  * Stores a pointer into an atomic var, using sequentially consistent ordering.
     167             :  */
     168             : AWS_STATIC_IMPL
     169             : void aws_atomic_store_ptr(volatile struct aws_atomic_var *var, void *p);
     170             : 
     171             : /**
     172             :  * Exchanges an integer with the value in an atomic_var, using the specified ordering.
     173             :  * Returns the value that was previously in the atomic_var.
     174             :  */
     175             : AWS_STATIC_IMPL
     176             : size_t aws_atomic_exchange_int_explicit(
     177             :     volatile struct aws_atomic_var *var,
     178             :     size_t n,
     179             :     enum aws_memory_order memory_order);
     180             : 
     181             : /**
     182             :  * Exchanges an integer with the value in an atomic_var, using sequentially consistent ordering.
     183             :  * Returns the value that was previously in the atomic_var.
     184             :  */
     185             : AWS_STATIC_IMPL
     186             : size_t aws_atomic_exchange_int(volatile struct aws_atomic_var *var, size_t n);
     187             : 
     188             : /**
     189             :  * Exchanges a pointer with the value in an atomic_var, using the specified ordering.
     190             :  * Returns the value that was previously in the atomic_var.
     191             :  */
     192             : AWS_STATIC_IMPL
     193             : void *aws_atomic_exchange_ptr_explicit(
     194             :     volatile struct aws_atomic_var *var,
     195             :     void *p,
     196             :     enum aws_memory_order memory_order);
     197             : 
     198             : /**
     199             :  * Exchanges an integer with the value in an atomic_var, using sequentially consistent ordering.
     200             :  * Returns the value that was previously in the atomic_var.
     201             :  */
     202             : AWS_STATIC_IMPL
     203             : void *aws_atomic_exchange_ptr(volatile struct aws_atomic_var *var, void *p);
     204             : 
     205             : /**
     206             :  * Atomically compares *var to *expected; if they are equal, atomically sets *var = desired. Otherwise, *expected is set
     207             :  * to the value in *var. On success, the memory ordering used was order_success; otherwise, it was order_failure.
     208             :  * order_failure must be no stronger than order_success, and must not be release or acq_rel.
     209             :  * Returns true if the compare was successful and the variable updated to desired.
     210             :  */
     211             : AWS_STATIC_IMPL
     212             : bool aws_atomic_compare_exchange_int_explicit(
     213             :     volatile struct aws_atomic_var *var,
     214             :     size_t *expected,
     215             :     size_t desired,
     216             :     enum aws_memory_order order_success,
     217             :     enum aws_memory_order order_failure);
     218             : 
     219             : /**
     220             :  * Atomically compares *var to *expected; if they are equal, atomically sets *var = desired. Otherwise, *expected is set
     221             :  * to the value in *var. Uses sequentially consistent memory ordering, regardless of success or failure.
     222             :  * Returns true if the compare was successful and the variable updated to desired.
     223             :  */
     224             : AWS_STATIC_IMPL
     225             : bool aws_atomic_compare_exchange_int(volatile struct aws_atomic_var *var, size_t *expected, size_t desired);
     226             : 
     227             : /**
     228             :  * Atomically compares *var to *expected; if they are equal, atomically sets *var = desired. Otherwise, *expected is set
     229             :  * to the value in *var. On success, the memory ordering used was order_success; otherwise, it was order_failure.
     230             :  * order_failure must be no stronger than order_success, and must not be release or acq_rel.
     231             :  * Returns true if the compare was successful and the variable updated to desired.
     232             :  */
     233             : AWS_STATIC_IMPL
     234             : bool aws_atomic_compare_exchange_ptr_explicit(
     235             :     volatile struct aws_atomic_var *var,
     236             :     void **expected,
     237             :     void *desired,
     238             :     enum aws_memory_order order_success,
     239             :     enum aws_memory_order order_failure);
     240             : 
     241             : /**
     242             :  * Atomically compares *var to *expected; if they are equal, atomically sets *var = desired. Otherwise, *expected is set
     243             :  * to the value in *var. Uses sequentially consistent memory ordering, regardless of success or failure.
     244             :  * Returns true if the compare was successful and the variable updated to desired.
     245             :  */
     246             : AWS_STATIC_IMPL
     247             : bool aws_atomic_compare_exchange_ptr(volatile struct aws_atomic_var *var, void **expected, void *desired);
     248             : 
     249             : /**
     250             :  * Atomically adds n to *var, and returns the previous value of *var.
     251             :  */
     252             : AWS_STATIC_IMPL
     253             : size_t aws_atomic_fetch_add_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order);
     254             : 
     255             : /**
     256             :  * Atomically subtracts n from *var, and returns the previous value of *var.
     257             :  */
     258             : AWS_STATIC_IMPL
     259             : size_t aws_atomic_fetch_sub_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order);
     260             : 
     261             : /**
     262             :  * Atomically ORs n with *var, and returns the previous value of *var.
     263             :  */
     264             : AWS_STATIC_IMPL
     265             : size_t aws_atomic_fetch_or_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order);
     266             : 
     267             : /**
     268             :  * Atomically ANDs n with *var, and returns the previous value of *var.
     269             :  */
     270             : AWS_STATIC_IMPL
     271             : size_t aws_atomic_fetch_and_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order);
     272             : 
     273             : /**
     274             :  * Atomically XORs n with *var, and returns the previous value of *var.
     275             :  */
     276             : AWS_STATIC_IMPL
     277             : size_t aws_atomic_fetch_xor_explicit(volatile struct aws_atomic_var *var, size_t n, enum aws_memory_order order);
     278             : 
     279             : /**
     280             :  * Atomically adds n to *var, and returns the previous value of *var.
     281             :  * Uses sequentially consistent ordering.
     282             :  */
     283             : AWS_STATIC_IMPL
     284             : size_t aws_atomic_fetch_add(volatile struct aws_atomic_var *var, size_t n);
     285             : 
     286             : /**
     287             :  * Atomically subtracts n from *var, and returns the previous value of *var.
     288             :  * Uses sequentially consistent ordering.
     289             :  */
     290             : AWS_STATIC_IMPL
     291             : size_t aws_atomic_fetch_sub(volatile struct aws_atomic_var *var, size_t n);
     292             : 
     293             : /**
     294             :  * Atomically ands n into *var, and returns the previous value of *var.
     295             :  * Uses sequentially consistent ordering.
     296             :  */
     297             : AWS_STATIC_IMPL
     298             : size_t aws_atomic_fetch_and(volatile struct aws_atomic_var *var, size_t n);
     299             : 
     300             : /**
     301             :  * Atomically ors n into *var, and returns the previous value of *var.
     302             :  * Uses sequentially consistent ordering.
     303             :  */
     304             : AWS_STATIC_IMPL
     305             : size_t aws_atomic_fetch_or(volatile struct aws_atomic_var *var, size_t n);
     306             : 
     307             : /**
     308             :  * Atomically xors n into *var, and returns the previous value of *var.
     309             :  * Uses sequentially consistent ordering.
     310             :  */
     311             : AWS_STATIC_IMPL
     312             : size_t aws_atomic_fetch_xor(volatile struct aws_atomic_var *var, size_t n);
     313             : 
     314             : /**
     315             :  * Provides the same reordering guarantees as an atomic operation with the specified memory order, without
     316             :  * needing to actually perform an atomic operation.
     317             :  */
     318             : AWS_STATIC_IMPL
     319             : void aws_atomic_thread_fence(enum aws_memory_order order);
     320             : 
     321             : #ifndef AWS_NO_STATIC_IMPL
     322             : #    include <aws/common/atomics.inl>
     323             : #endif /* AWS_NO_STATIC_IMPL */
     324             : 
     325             : AWS_EXTERN_C_END
     326             : 
     327             : #endif

Generated by: LCOV version 1.13