1 /* 2 * Copyright (c) 2014-2017, Siemens AG. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #ifndef EMBB_BASE_C_INTERNAL_ATOMIC_FETCH_AND_ADD_H_ 28 #define EMBB_BASE_C_INTERNAL_ATOMIC_FETCH_AND_ADD_H_ 29 30 #ifndef DOXYGEN 31 32 /* 33 * See file and_assign.h for a detailed (and operation independent) description 34 * of the following macro. 35 */ 36 #ifdef EMBB_PLATFORM_ARCH_X86 37 38 #ifdef EMBB_PLATFORM_COMPILER_MSVC 39 #define EMBB_DEFINE_FETCH_AND_ADD(EMBB_PARAMETER_SIZE_BYTE, EMBB_ATOMIC_X86_SIZE_SUFFIX) \ 40 extern EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) __fastcall EMBB_CAT2(embb_internal__atomic_fetch_and_add_, EMBB_PARAMETER_SIZE_BYTE)_asm( \ 41 EMBB_CAT2(EMBB_BASE_BASIC_TYPE_ATOMIC_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) new_value); \ 42 EMBB_PLATFORM_INLINE EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) __fastcall EMBB_CAT2(embb_internal__atomic_fetch_and_add_, EMBB_PARAMETER_SIZE_BYTE) (\ 43 EMBB_CAT2(EMBB_BASE_BASIC_TYPE_ATOMIC_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) new_value) {\ 44 EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) result; \ 45 _ReadWriteBarrier(); \ 46 result = EMBB_CAT2(embb_internal__atomic_fetch_and_add_, \ 47 EMBB_PARAMETER_SIZE_BYTE)_asm(pointer_to_value, new_value); \ 48 _ReadWriteBarrier(); \ 49 return result; \ 50 } 51 #elif defined(EMBB_PLATFORM_COMPILER_GNUC) 52 #define EMBB_DEFINE_FETCH_AND_ADD(EMBB_PARAMETER_SIZE_BYTE, EMBB_ATOMIC_X86_SIZE_SUFFIX) \ 53 EMBB_PLATFORM_INLINE EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) EMBB_CAT2(embb_internal__atomic_fetch_and_add_, EMBB_PARAMETER_SIZE_BYTE) \ 54 (EMBB_CAT2(EMBB_BASE_BASIC_TYPE_ATOMIC_, EMBB_PARAMETER_SIZE_BYTE) volatile* pointer_to_value, EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) new_value) { \ 55 __asm__ __volatile__ ("lock xadd" EMBB_ATOMIC_X86_SIZE_SUFFIX " %1, %0" \ 56 : "+m" (*pointer_to_value), "+q" (new_value) \ 57 : \ 58 : "memory", "cc" ); \ 59 return new_value; \ 60 } 61 #else 62 #error "No atomic fetch and store implementation found" 63 #endif 64 65 /* 66 * The three or four macro calls below generate the methods for 1, 2, 4, and 67 * bytes, as stated in the macro definition. 68 */ 69 EMBB_DEFINE_FETCH_AND_ADD(1, "b") 70 EMBB_DEFINE_FETCH_AND_ADD(2, "w") 71 EMBB_DEFINE_FETCH_AND_ADD(4, "l") 72 #ifdef EMBB_64_BIT_ATOMIC_AVAILABLE 73 EMBB_DEFINE_FETCH_AND_ADD(8, "q") 74 #endif 75 76 #elif defined(EMBB_PLATFORM_ARCH_ARM) 77 78 #if defined(EMBB_PLATFORM_COMPILER_GNUC) 79 #define EMBB_DEFINE_FETCH_AND_ADD(EMBB_PARAMETER_SIZE_BYTE, \ 80 EMBB_ATOMIC_ARM_SIZE_SUFFIX) \ 81 EMBB_PLATFORM_INLINE \ 82 EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) \ 83 EMBB_CAT2(embb_internal__atomic_fetch_and_add_, \ 84 EMBB_PARAMETER_SIZE_BYTE)(\ 85 EMBB_CAT2(EMBB_BASE_BASIC_TYPE_ATOMIC_, EMBB_PARAMETER_SIZE_BYTE) \ 86 volatile* pointer_to_value, \ 87 EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) \ 88 new_value) { \ 89 EMBB_CAT2(EMBB_BASE_BASIC_TYPE_SIZE_, EMBB_PARAMETER_SIZE_BYTE) \ 90 tmp1, tmp2, result; \ 91 __asm__ __volatile__ ( \ 92 "dmb\n\t" \ 93 "loop_%=:\n\t" \ 94 "ldrex" EMBB_ATOMIC_ARM_SIZE_SUFFIX " %0, [%3]\n\t" \ 95 "add %1, %0, %4\n\t" \ 96 "strex" EMBB_ATOMIC_ARM_SIZE_SUFFIX " %2, %1, [%3]\n\t" \ 97 "teq %2, #0\n\t" \ 98 "bne loop_%=\n\t" \ 99 "isb" \ 100 : "=&r" (result), "=&r" (tmp1), "=&r" (tmp2) \ 101 : "r" (pointer_to_value), "r" (new_value) \ 102 : "memory", "cc" ); \ 103 return result; \ 104 } 105 #else 106 #error "No atomic fetch and store implementation found" 107 #endif 108 109 EMBB_DEFINE_FETCH_AND_ADD(1, "b") 110 EMBB_DEFINE_FETCH_AND_ADD(2, "h") 111 EMBB_DEFINE_FETCH_AND_ADD(4, "") 112 113 #else 114 #error "Unknown architecture" 115 #endif 116 117 #endif //DOXYGEN 118 119 #endif //EMBB_BASE_C_INTERNAL_ATOMIC_FETCH_AND_ADD_H_ 120