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