/************************************************************************* * * Copyright (C) 2018-2023 Ruilin Peng (Nick) . * * smartdns is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * smartdns is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef _GENERIC_ATOMIC_H #define _GENERIC_ATOMIC_H #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) #define READ_ONCE(x) \ ({ typeof(x) ___x = ACCESS_ONCE(x); ___x; }) /** * Atomic type. */ typedef struct { int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } /** * Read atomic variable * @param v pointer of type atomic_t * * Atomically reads the value of @v. */ static inline int atomic_read(const atomic_t *v) { return READ_ONCE((v)->counter); } /** * Set atomic variable * @param v pointer of type atomic_t * @param i required value */ static inline void atomic_set(atomic_t *v, int i) { v->counter = i; } /** * Add to the atomic variable * @param i integer value to add * @param v pointer of type atomic_t */ static inline void atomic_add( int i, atomic_t *v ) { (void)__sync_add_and_fetch(&v->counter, i); } /** * Subtract the atomic variable * @param i integer value to subtract * @param v pointer of type atomic_t * * Atomically subtracts @i from @v. */ static inline void atomic_sub( int i, atomic_t *v ) { (void)__sync_sub_and_fetch(&v->counter, i); } /** * Subtract value from variable and test result * @param i integer value to subtract * @param v pointer of type atomic_t * * Atomically subtracts @i from @v and returns * true if the result is zero, or false for all * other cases. */ static inline int atomic_sub_and_test( int i, atomic_t *v ) { return !(__sync_sub_and_fetch(&v->counter, i)); } /** * Increment atomic variable * @param v pointer of type atomic_t * * Atomically increments @v by 1. */ static inline void atomic_inc( atomic_t *v ) { (void)__sync_add_and_fetch(&v->counter, 1); } /** * @brief decrement atomic variable * @param v: pointer of type atomic_t * * Atomically decrements @v by 1. Note that the guaranteed * useful range of an atomic_t is only 24 bits. */ static inline void atomic_dec( atomic_t *v ) { (void)__sync_sub_and_fetch(&v->counter, 1); } /** * Increment atomic variable * @param v pointer of type atomic_t * * Atomically increments @v by 1. */ static inline int atomic_inc_return( atomic_t *v ) { return __sync_add_and_fetch(&v->counter, 1); } /** * @brief decrement atomic variable * @param v: pointer of type atomic_t * * Atomically decrements @v by 1. Note that the guaranteed * useful range of an atomic_t is only 24 bits. */ static inline int atomic_dec_return( atomic_t *v ) { return __sync_sub_and_fetch(&v->counter, 1); } /** * @brief Decrement and test * @param v pointer of type atomic_t * * Atomically decrements @v by 1 and * returns true if the result is 0, or false for all other * cases. */ static inline int atomic_dec_and_test( atomic_t *v ) { return !(__sync_sub_and_fetch(&v->counter, 1)); } /** * @brief Increment and test * @param v pointer of type atomic_t * * Atomically increments @v by 1 * and returns true if the result is zero, or false for all * other cases. */ static inline int atomic_inc_and_test( atomic_t *v ) { return !(__sync_add_and_fetch(&v->counter, 1)); } /** * @brief add and test if negative * @param v pointer of type atomic_t * @param i integer value to add * * Atomically adds @i to @v and returns true * if the result is negative, or false when * result is greater than or equal to zero. */ static inline int atomic_add_negative( int i, atomic_t *v ) { return (__sync_add_and_fetch(&v->counter, i) < 0); } #endif