/* * Copyright (C) 2014 Freie UniversitÀt Berlin * Copyright (C) 2015 Eistec AB * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @addtogroup core_util * @{ * * @file * @brief Functions for atomic handling of variables * * @author Kaspar Schleiser * @author Joakim NohlgÄrd */ #ifndef ATOMIC_H_ #define ATOMIC_H_ #ifdef __cplusplus extern "C" { #endif /** * @brief Integer variable for use in atomic counters. * * @note This type is a struct for hard type checking (let the compiler warn * if int is assigned regularly). */ typedef struct { volatile int value; /**< the actual value */ } atomic_int_t; /** * @brief Initializer for atomic variables * * @param[in] val initial value for the atomic integer */ #define ATOMIC_INIT(val) {(val)} /** * @brief Atomic Compare and Swap * * Updates the value in var iff the current value of var is equal to old. * * @param[inout] var Atomic variable to update * @param[in] old The old value to compare against * @param[in] now The new value to write to var * * @return 1 if the write completed successfully * @return 0 if the write failed. */ int atomic_cas(atomic_int_t *var, int old, int now); /** * @brief Increment a counter variable by one atomically and return the old value. * * @param[inout] var Pointer to a counter variable. * * @return The value of *val* before the increment. */ static inline int atomic_inc(atomic_int_t *var) { int old; do { old = var->value; } while (!atomic_cas(var, old, old + 1)); return old; } /** * @brief Decrement a counter variable by one atomically and return the old value. * * @param[inout] var Pointer to a counter variable. * * @return The value of *val* before the decrement. */ static inline int atomic_dec(atomic_int_t *var) { int old; do { old = var->value; } while (!atomic_cas(var, old, old - 1)); return old; } /** * @brief Set an atomic variable to 1. * * @param[inout] var Pointer to an atomic variable to update * * @return 1 if the old value was 0 and the variable was successfully updated * @return 0 if the variable was already set */ static inline int atomic_set_to_one(atomic_int_t *var) { do { if (var->value != 0) { return 0; } } while (!atomic_cas(var, 0, 1)); return 1; } /** * @brief Set an atomic variable to 0. * * @param[inout] var Pointer to an atomic variable to update * * @return 1 if the old value was not 0 and the variable was successfully updated * @return 0 if the variable was already cleared */ static inline int atomic_set_to_zero(atomic_int_t *var) { int old; do { old = var->value; if (old == 0) { return 0; } } while (!atomic_cas(var, old, 0)); return 1; } /** * @brief Get the value of an atomic int * * @param[in] var Atomic variable * * @return the value of the atomic integer * * @note This can be used for non-thread-safe assignment of the atomic integer */ #define ATOMIC_VALUE(var) ((var).value) #ifdef __cplusplus } #endif #endif /* ATOMIC_H_ */ /** @} */