1 /* Atomic operations used inside libc. Linux/SH version. 2 Copyright (C) 2003 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 The GNU C Library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 The GNU C Library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library; if not, see 17 <http://www.gnu.org/licenses/>. */ 18 19 #include <stdint.h> 20 21 22 typedef int8_t atomic8_t; 23 typedef uint8_t uatomic8_t; 24 typedef int_fast8_t atomic_fast8_t; 25 typedef uint_fast8_t uatomic_fast8_t; 26 27 typedef int16_t atomic16_t; 28 typedef uint16_t uatomic16_t; 29 typedef int_fast16_t atomic_fast16_t; 30 typedef uint_fast16_t uatomic_fast16_t; 31 32 typedef int32_t atomic32_t; 33 typedef uint32_t uatomic32_t; 34 typedef int_fast32_t atomic_fast32_t; 35 typedef uint_fast32_t uatomic_fast32_t; 36 37 typedef int64_t atomic64_t; 38 typedef uint64_t uatomic64_t; 39 typedef int_fast64_t atomic_fast64_t; 40 typedef uint_fast64_t uatomic_fast64_t; 41 42 typedef intptr_t atomicptr_t; 43 typedef uintptr_t uatomicptr_t; 44 typedef intmax_t atomic_max_t; 45 typedef uintmax_t uatomic_max_t; 46 47 /* SH kernel has implemented a gUSA ("g" User Space Atomicity) support 48 for the user space atomicity. The atomicity macros use this scheme. 49 50 Reference: 51 Niibe Yutaka, "gUSA: Simple and Efficient User Space Atomicity 52 Emulation with Little Kernel Modification", Linux Conference 2002, 53 Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in 54 Japanese). 55 56 Niibe Yutaka, "gUSA: User Space Atomicity with Little Kernel 57 Modification", LinuxTag 2003, Rome. 58 http://www.semmel.ch/Linuxtag-DVD/talks/170/paper.html (in English). 59 60 B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for 61 Uniprocessors", Proceedings of the Fifth Architectural Support for 62 Programming Languages and Operating Systems (ASPLOS), pp. 223-233, 63 October 1992. http://www.cs.washington.edu/homes/bershad/Papers/Rcs.ps 64 65 SuperH ABI: 66 r15: -(size of atomic instruction sequence) < 0 67 r0: end point 68 r1: saved stack pointer 69 */ 70 71 #if __GNUC_PREREQ (4, 7) 72 # define rNOSP "u" 73 #else 74 # define rNOSP "r" 75 #endif 76 77 /* Avoid having lots of different versions of compare and exchange, 78 by having this one complicated version. Parameters: 79 bwl: b, w or l for 8, 16 and 32 bit versions. 80 version: val or bool, depending on whether the result is the 81 previous value or a bool indicating whether the transfer 82 did happen (note this needs inverting before being 83 returned in atomic_compare_and_exchange_bool). 84 */ 85 86 #define __arch_compare_and_exchange_n(mem, newval, oldval, bwl, version) \ 87 ({ signed long __arch_result; \ 88 __asm__ __volatile__ ("\ 89 .align 2\n\ 90 mova 1f,r0\n\ 91 nop\n\ 92 mov r15,r1\n\ 93 mov #-8,r15\n\ 94 0: mov." #bwl " @%1,%0\n\ 95 cmp/eq %0,%3\n\ 96 bf 1f\n\ 97 mov." #bwl " %2,@%1\n\ 98 1: mov r1,r15\n\ 99 .ifeqs \"bool\",\"" #version "\"\n\ 100 movt %0\n\ 101 .endif\n" \ 102 : "=&r" (__arch_result) \ 103 : rNOSP (mem), rNOSP (newval), rNOSP (oldval) \ 104 : "r0", "r1", "t", "memory"); \ 105 __arch_result; }) 106 107 #define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ 108 __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, val) 109 110 #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ 111 __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, val) 112 113 #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ 114 __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, val) 115 116 /* XXX We do not really need 64-bit compare-and-exchange. At least 117 not in the moment. Using it would mean causing portability 118 problems since not many other 32-bit architectures have support for 119 such an operation. So don't define any code for now. */ 120 121 # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ 122 (abort (), 0) 123 124 /* For "bool" routines, return if the exchange did NOT occur */ 125 126 #define __arch_compare_and_exchange_bool_8_acq(mem, newval, oldval) \ 127 (! __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, bool)) 128 129 #define __arch_compare_and_exchange_bool_16_acq(mem, newval, oldval) \ 130 (! __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, bool)) 131 132 #define __arch_compare_and_exchange_bool_32_acq(mem, newval, oldval) \ 133 (! __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, bool)) 134 135 # define __arch_compare_and_exchange_bool_64_acq(mem, newval, oldval) \ 136 (abort (), 0) 137 138 /* Similar to the above, have one template which can be used in a 139 number of places. This version returns both the old and the new 140 values of the location. Parameters: 141 bwl: b, w or l for 8, 16 and 32 bit versions. 142 oper: The instruction to perform on the old value. 143 Note old is not sign extended, so should be an unsigned long. 144 */ 145 146 #define __arch_operate_old_new_n(mem, value, old, new, bwl, oper) \ 147 (void) ({ __asm__ __volatile__ ("\ 148 .align 2\n\ 149 mova 1f,r0\n\ 150 mov r15,r1\n\ 151 nop\n\ 152 mov #-8,r15\n\ 153 0: mov." #bwl " @%2,%0\n\ 154 mov %0,%1\n\ 155 " #oper " %3,%1\n\ 156 mov." #bwl " %1,@%2\n\ 157 1: mov r1,r15" \ 158 : "=&r" (old), "=&r"(new) \ 159 : rNOSP (mem), rNOSP (value) \ 160 : "r0", "r1", "memory"); \ 161 }) 162 163 #define __arch_exchange_and_add_8_int(mem, value) \ 164 ({ int32_t __value = (value), __new, __old; \ 165 __arch_operate_old_new_n((mem), __value, __old, __new, b, add); \ 166 __old; }) 167 168 #define __arch_exchange_and_add_16_int(mem, value) \ 169 ({ int32_t __value = (value), __new, __old; \ 170 __arch_operate_old_new_n((mem), __value, __old, __new, w, add); \ 171 __old; }) 172 173 #define __arch_exchange_and_add_32_int(mem, value) \ 174 ({ int32_t __value = (value), __new, __old; \ 175 __arch_operate_old_new_n((mem), __value, __old, __new, l, add); \ 176 __old; }) 177 178 #define __arch_exchange_and_add_64_int(mem, value) \ 179 (abort (), 0) 180 181 #define atomic_exchange_and_add(mem, value) \ 182 __atomic_val_bysize (__arch_exchange_and_add, int, mem, value) 183 184 185 /* Again, another template. We get a slight optimisation when the old value 186 does not need to be returned. Parameters: 187 bwl: b, w or l for 8, 16 and 32 bit versions. 188 oper: The instruction to perform on the old value. 189 */ 190 191 #define __arch_operate_new_n(mem, value, bwl, oper) \ 192 ({ int32_t __value = (value), __new; \ 193 __asm__ __volatile__ ("\ 194 .align 2\n\ 195 mova 1f,r0\n\ 196 mov r15,r1\n\ 197 mov #-6,r15\n\ 198 0: mov." #bwl " @%1,%0\n\ 199 " #oper " %2,%0\n\ 200 mov." #bwl " %0,@%1\n\ 201 1: mov r1,r15" \ 202 : "=&r" (__new) \ 203 : rNOSP (mem), rNOSP (__value) \ 204 : "r0", "r1", "memory"); \ 205 __new; \ 206 }) 207 208 #define __arch_add_8_int(mem, value) \ 209 __arch_operate_new_n(mem, value, b, add) 210 211 #define __arch_add_16_int(mem, value) \ 212 __arch_operate_new_n(mem, value, w, add) 213 214 #define __arch_add_32_int(mem, value) \ 215 __arch_operate_new_n(mem, value, l, add) 216 217 #define __arch_add_64_int(mem, value) \ 218 (abort (), 0) 219 220 #define atomic_add(mem, value) \ 221 ((void) __atomic_val_bysize (__arch_add, int, mem, value)) 222 223 224 #define __arch_add_negative_8_int(mem, value) \ 225 (__arch_operate_new_n(mem, value, b, add) < 0) 226 227 #define __arch_add_negative_16_int(mem, value) \ 228 (__arch_operate_new_n(mem, value, w, add) < 0) 229 230 #define __arch_add_negative_32_int(mem, value) \ 231 (__arch_operate_new_n(mem, value, l, add) < 0) 232 233 #define __arch_add_negative_64_int(mem, value) \ 234 (abort (), 0) 235 236 #define atomic_add_negative(mem, value) \ 237 __atomic_bool_bysize (__arch_add_negative, int, mem, value) 238 239 240 #define __arch_add_zero_8_int(mem, value) \ 241 (__arch_operate_new_n(mem, value, b, add) == 0) 242 243 #define __arch_add_zero_16_int(mem, value) \ 244 (__arch_operate_new_n(mem, value, w, add) == 0) 245 246 #define __arch_add_zero_32_int(mem, value) \ 247 (__arch_operate_new_n(mem, value, l, add) == 0) 248 249 #define __arch_add_zero_64_int(mem, value) \ 250 (abort (), 0) 251 252 #define atomic_add_zero(mem, value) \ 253 __atomic_bool_bysize (__arch_add_zero, int, mem, value) 254 255 256 #define atomic_increment_and_test(mem) atomic_add_zero((mem), 1) 257 #define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1) 258 259 260 #define __arch_bit_set_8_int(mem, value) \ 261 __arch_operate_new_n(mem, 1<<(value), b, or) 262 263 #define __arch_bit_set_16_int(mem, value) \ 264 __arch_operate_new_n(mem, 1<<(value), w, or) 265 266 #define __arch_bit_set_32_int(mem, value) \ 267 __arch_operate_new_n(mem, 1<<(value), l, or) 268 269 #define __arch_bit_set_64_int(mem, value) \ 270 (abort (), 0) 271 272 #define __arch_add_64_int(mem, value) \ 273 (abort (), 0) 274 275 #define atomic_bit_set(mem, value) \ 276 ((void) __atomic_val_bysize (__arch_bit_set, int, mem, value)) 277 278 279 #define __arch_bit_test_set_8_int(mem, value) \ 280 ({ int32_t __value = 1<<(value), __new, __old; \ 281 __arch_operate_old_new_n((mem), __value, __old, __new, b, or); \ 282 __old & __value; }) 283 284 #define __arch_bit_test_set_16_int(mem, value) \ 285 ({ int32_t __value = 1<<(value), __new, __old; \ 286 __arch_operate_old_new_n((mem), __value, __old, __new, w, or); \ 287 __old & __value; }) 288 289 #define __arch_bit_test_set_32_int(mem, value) \ 290 ({ int32_t __value = 1<<(value), __new, __old; \ 291 __arch_operate_old_new_n((mem), __value, __old, __new, l, or); \ 292 __old & __value; }) 293 294 #define __arch_bit_test_set_64_int(mem, value) \ 295 (abort (), 0) 296 297 #define atomic_bit_test_set(mem, value) \ 298 __atomic_val_bysize (__arch_bit_test_set, int, mem, value) 299