Home | History | Annotate | Download | only in include
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2014 Google, Inc.
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 #pragma once
     20 
     21 #include <stdbool.h>
     22 #include <stdint.h>
     23 
     24 // Set of atomic operations to work on data structures.
     25 // The atomic type data should only be manipulated by these functions.
     26 // This uses the gcc built in functions.
     27 //  gcc doc section 6.50 "Built-in functions for memory model aware atomic operations"
     28 //
     29 // Data types:
     30 // atomic_<name>_t
     31 //
     32 // e.g.
     33 //  atomic_s32_t for a signed 32 bit integer.
     34 //  atomic_u32_t for an unsigned 32 bit integer.
     35 //
     36 // Functions:
     37 // atomic_<operation>_<name>(atomic_t *, ...)
     38 //
     39 // e.g.
     40 //  uint32_t atomic_dec_prefix_u32(volatile atomic_u32_t *atomic)
     41 //
     42 // The prefix/postfix classification corresponds which value is returned
     43 // from the function call, the old or the new one.
     44 
     45 #if defined(GCC_VERSION) && GCC_VERSION < 40700
     46 #warning "Atomics not supported"
     47 #endif
     48 
     49 #define ATOMIC_TYPE(name, type) \
     50   struct atomic_##name { \
     51     type _val; \
     52 }; \
     53 typedef struct atomic_##name atomic_##name##_t;
     54 
     55 #define ATOMIC_STORE(name, type, sz) \
     56 static inline void atomic_store_##name(volatile atomic_##name##_t *atomic, type val) { \
     57   __atomic_store_##sz(&atomic->_val, val, __ATOMIC_SEQ_CST); \
     58 }
     59 
     60 #define ATOMIC_LOAD(name, type, sz) \
     61 static inline type atomic_load_##name(volatile atomic_##name##_t *atomic) { \
     62   return __atomic_load_##sz(&atomic->_val, __ATOMIC_SEQ_CST); \
     63 }
     64 
     65 // Returns value after operation, e.g. new value
     66 #define ATOMIC_INC_PREFIX(name, type, sz) \
     67 static inline type atomic_inc_prefix_##name(volatile atomic_##name##_t *atomic) { \
     68   return __atomic_add_fetch_##sz(atomic, 1, __ATOMIC_SEQ_CST); \
     69 }
     70 
     71 // Returns value after operation, e.g. new value
     72 #define ATOMIC_DEC_PREFIX(name, type, sz) \
     73 static inline type atomic_dec_prefix_##name(volatile atomic_##name##_t *atomic) { \
     74   return __atomic_sub_fetch_##sz(atomic, 1, __ATOMIC_SEQ_CST); \
     75 }
     76 
     77 // Returns value before operation, e.g. old value
     78 #define ATOMIC_INC_POSTFIX(name, type, sz) \
     79 static inline type atomic_inc_postfix_##name(volatile atomic_##name##_t *atomic) { \
     80   return __atomic_fetch_add_##sz(atomic, 1, __ATOMIC_SEQ_CST); \
     81 }
     82 
     83 // Returns value before operation, e.g. old value
     84 #define ATOMIC_DEC_POSTFIX(name, type, sz) \
     85 static inline type atomic_dec_postfix_##name(volatile atomic_##name##_t *atomic) { \
     86   return __atomic_fetch_sub_##sz(atomic, 1, __ATOMIC_SEQ_CST); \
     87 }
     88 
     89 // Returns value after operation, e.g. new value
     90 #define ATOMIC_ADD(name, type, sz) \
     91 static inline type atomic_add_##name(volatile atomic_##name##_t *atomic, type val) { \
     92   return __atomic_add_fetch_##sz(atomic, val, __ATOMIC_SEQ_CST); \
     93 }
     94 
     95 // Returns value after operation, e.g. new value
     96 #define ATOMIC_SUB(name, type, sz) \
     97 static inline type atomic_sub_##name(volatile atomic_##name##_t *atomic, type val) { \
     98   return __atomic_sub_fetch_##sz(atomic, val, __ATOMIC_SEQ_CST); \
     99 }
    100 
    101 #define ATOMIC_MAKE(name, type, sz) \
    102   ATOMIC_TYPE(name, type) \
    103   ATOMIC_STORE(name, type, sz) \
    104   ATOMIC_LOAD(name, type, sz) \
    105   ATOMIC_INC_PREFIX(name, type, sz) \
    106   ATOMIC_DEC_PREFIX(name, type, sz) \
    107   ATOMIC_INC_POSTFIX(name, type, sz) \
    108   ATOMIC_DEC_POSTFIX(name, type, sz) \
    109   ATOMIC_ADD(name, type, sz) \
    110   ATOMIC_SUB(name, type, sz)
    111 
    112 ATOMIC_MAKE(s32, int32_t, 4)
    113 ATOMIC_MAKE(u32, uint32_t, 4)
    114 ATOMIC_MAKE(s64, int64_t, 8)
    115 ATOMIC_MAKE(u64, uint64_t, 8)
    116