1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#pragma once 14 15#include <assert.h> 16#include <limits.h> 17#include <stddef.h> 18 19/** \brief Atomically increment an integer, accounting for possible overflow. 20 * 21 * @param x Pointer to integer to increment. 22 * @param[out] oldval Previous value of the integer. May be written to even if 23 * the increment fails. 24 * @param success_memorder The memory order to enforce 25 * @return 0 if the increment succeeds, non-zero if it would cause an overflow. 26 */ 27static inline int sync_atomic_increment_safe(volatile int *x, int *oldval, int success_memorder) { 28 assert(x != NULL); 29 assert(oldval != NULL); 30 do { 31 *oldval = *x; 32 if (*oldval == INT_MAX) { 33 /* We would overflow */ 34 return -1; 35 } 36 } while (!__atomic_compare_exchange_n(x, oldval, *oldval + 1, 1, success_memorder, __ATOMIC_RELAXED)); 37 return 0; 38} 39 40/** \brief Atomically decrement an integer, accounting for possible overflow. 41 * 42 * @param x Pointer to integer to decrement. 43 * @param[out] oldval Previous value of the integer. May be written to even if 44 * the decrement fails. 45 * @param success_memorder The memory order to enforce if the decrement is successful 46 * @return 0 if the decrement succeeds, non-zero if it would cause an overflow. 47 */ 48static inline int sync_atomic_decrement_safe(volatile int *x, int *oldval, int success_memorder) { 49 assert(x != NULL); 50 assert(oldval != NULL); 51 do { 52 *oldval = *x; 53 if (*oldval == INT_MIN) { 54 /* We would overflow */ 55 return -1; 56 } 57 } while (!__atomic_compare_exchange_n(x, oldval, *oldval - 1, 1, success_memorder, __ATOMIC_RELAXED)); 58 return 0; 59} 60 61/* Atomically increment an integer and return its new value. */ 62static inline int sync_atomic_increment(volatile int *x, int memorder) { 63 return __atomic_add_fetch(x, 1, memorder); 64} 65 66/* Atomically decrement an integer and return its new value. */ 67static inline int sync_atomic_decrement(volatile int *x, int memorder) { 68 return __atomic_sub_fetch(x, 1, memorder); 69} 70 71