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