| 1 | /* Haiku-specific atomic operations for libgcc. |
| 2 | Copyright (C) 2008-2013 Free Software Foundation, Inc. |
| 3 | Contributed by CodeSourcery. |
| 4 | Modified for Haiku project by Shantanu Gupta <shans95g@gmail.com> (2014) |
| 5 | |
| 6 | This file is part of GCC. |
| 7 | |
| 8 | GCC is free software; you can redistribute it and/or modify it under |
| 9 | the terms of the GNU General Public License as published by the Free |
| 10 | Software Foundation; either version 3, or (at your option) any later |
| 11 | version. |
| 12 | |
| 13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| 14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 16 | for more details. |
| 17 | |
| 18 | Under Section 7 of GPL version 3, you are granted additional |
| 19 | permissions described in the GCC Runtime Library Exception, version |
| 20 | 3.1, as published by the Free Software Foundation. |
| 21 | |
| 22 | You should have received a copy of the GNU General Public License and |
| 23 | a copy of the GCC Runtime Library Exception along with this program; |
| 24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| 25 | <http://www.gnu.org/licenses/>. */ |
| 26 | |
| 27 | extern int _kern_atomic_test_and_set(int *value, int newValue, int testAgainst); |
| 28 | extern int _kern_atomic_add(int *value, int addValue); |
| 29 | extern int _kern_atomic_and(int *value, int andValue); |
| 30 | extern int _kern_atomic_or(int *value, int orValue); |
| 31 | |
| 32 | static inline int _kern_atomic_sub(int *value, int subValue) |
| 33 | { |
| 34 | return _kern_atomic_add(value, -subValue); |
| 35 | } |
| 36 | |
| 37 | #define HIDDEN __attribute__ ((visibility ("hidden"))) |
| 38 | |
| 39 | #ifdef __ARMEL__ |
| 40 | #define INVERT_MASK_1 0 |
| 41 | #define INVERT_MASK_2 0 |
| 42 | #else |
| 43 | #define INVERT_MASK_1 24 |
| 44 | #define INVERT_MASK_2 16 |
| 45 | #endif |
| 46 | |
| 47 | #define MASK_1 0xffu |
| 48 | #define MASK_2 0xffffu |
| 49 | |
| 50 | #define FETCH_AND_OP_WORD(OP) \ |
| 51 | int HIDDEN \ |
| 52 | __sync_fetch_and_##OP##_4(int *ptr, int val) \ |
| 53 | { \ |
| 54 | return _kern_atomic_##OP (ptr, val); \ |
| 55 | } |
| 56 | |
| 57 | // FETCH_AND_OP_WORD (add) TODO: Cleanup duplication in libroot.so |
| 58 | FETCH_AND_OP_WORD (sub) |
| 59 | FETCH_AND_OP_WORD (or) |
| 60 | FETCH_AND_OP_WORD (and) |
| 61 | |
| 62 | #define FETCH_AND_OP_WORD_EX(OP, PFX_OP, INF_OP) \ |
| 63 | int HIDDEN \ |
| 64 | __sync_fetch_and_##OP##_4(int *ptr, int val) \ |
| 65 | { \ |
| 66 | int tmp; \ |
| 67 | \ |
| 68 | do { \ |
| 69 | tmp = *ptr; \ |
| 70 | } while(_kern_atomic_test_and_set(ptr, PFX_OP(tmp INF_OP val), tmp) != tmp); \ |
| 71 | \ |
| 72 | return tmp; \ |
| 73 | } |
| 74 | |
| 75 | FETCH_AND_OP_WORD_EX (xor, , ^) // TODO: Not supported by haiku ? |
| 76 | FETCH_AND_OP_WORD_EX (nand, ~, &) // TODO: Not supported by haiku ? |
| 77 | |
| 78 | #define OP_AND_FETCH_WORD(OP, INF_OP) \ |
| 79 | int HIDDEN \ |
| 80 | __sync_##OP##_and_fetch_4(int *ptr, int val) \ |
| 81 | { \ |
| 82 | return (_kern_atomic_##OP (ptr, val) INF_OP val); \ |
| 83 | } |
| 84 | |
| 85 | OP_AND_FETCH_WORD (add, +) |
| 86 | OP_AND_FETCH_WORD (sub, -) |
| 87 | OP_AND_FETCH_WORD (or, |) |
| 88 | OP_AND_FETCH_WORD (and, &) |
| 89 | |
| 90 | #define OP_AND_FETCH_WORD_EX(OP, PFX_OP, INF_OP) \ |
| 91 | int HIDDEN \ |
| 92 | __sync_##OP##_and_fetch_4(int *ptr, int val) \ |
| 93 | { \ |
| 94 | int tmp; \ |
| 95 | \ |
| 96 | do { \ |
| 97 | tmp = *ptr; \ |
| 98 | } while(_kern_atomic_test_and_set(ptr, PFX_OP(tmp INF_OP val), tmp) != tmp); \ |
| 99 | \ |
| 100 | return PFX_OP (tmp INF_OP val); \ |
| 101 | } |
| 102 | |
| 103 | OP_AND_FETCH_WORD_EX (xor, , ^) |
| 104 | OP_AND_FETCH_WORD_EX (nand, ~, &) |
| 105 | |
| 106 | #define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH |
| 107 | #define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH |
| 108 | |
| 109 | #define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \ |
| 110 | TYPE HIDDEN \ |
| 111 | NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \ |
| 112 | { \ |
| 113 | int *wordptr = (int *) ((unsigned int) ptr & ~3); \ |
| 114 | unsigned int mask, shift, oldval, newval; \ |
| 115 | \ |
| 116 | shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ |
| 117 | mask = MASK_##WIDTH << shift; \ |
| 118 | \ |
| 119 | do { \ |
| 120 | oldval = *wordptr; \ |
| 121 | newval = ((PFX_OP (((oldval & mask) >> shift) \ |
| 122 | INF_OP (unsigned int) val)) << shift) & mask; \ |
| 123 | newval |= oldval & ~mask; \ |
| 124 | } while ((unsigned int) _kern_atomic_test_and_set(wordptr, newval, oldval) \ |
| 125 | != oldval); \ |
| 126 | \ |
| 127 | return (RETURN & mask) >> shift; \ |
| 128 | } |
| 129 | |
| 130 | SUBWORD_SYNC_OP (add, , +, short, 2, oldval) |
| 131 | SUBWORD_SYNC_OP (sub, , -, short, 2, oldval) |
| 132 | SUBWORD_SYNC_OP (or, , |, short, 2, oldval) |
| 133 | SUBWORD_SYNC_OP (and, , &, short, 2, oldval) |
| 134 | SUBWORD_SYNC_OP (xor, , ^, short, 2, oldval) |
| 135 | SUBWORD_SYNC_OP (nand, ~, &, short, 2, oldval) |
| 136 | |
| 137 | SUBWORD_SYNC_OP (add, , +, signed char, 1, oldval) |
| 138 | SUBWORD_SYNC_OP (sub, , -, signed char, 1, oldval) |
| 139 | SUBWORD_SYNC_OP (or, , |, signed char, 1, oldval) |
| 140 | SUBWORD_SYNC_OP (and, , &, signed char, 1, oldval) |
| 141 | SUBWORD_SYNC_OP (xor, , ^, signed char, 1, oldval) |
| 142 | SUBWORD_SYNC_OP (nand, ~, &, signed char, 1, oldval) |
| 143 | |
| 144 | SUBWORD_SYNC_OP (add, , +, short, 2, newval) |
| 145 | SUBWORD_SYNC_OP (sub, , -, short, 2, newval) |
| 146 | SUBWORD_SYNC_OP (or, , |, short, 2, newval) |
| 147 | SUBWORD_SYNC_OP (and, , &, short, 2, newval) |
| 148 | SUBWORD_SYNC_OP (xor, , ^, short, 2, newval) |
| 149 | SUBWORD_SYNC_OP (nand, ~, &, short, 2, newval) |
| 150 | |
| 151 | SUBWORD_SYNC_OP (add, , +, signed char, 1, newval) |
| 152 | SUBWORD_SYNC_OP (sub, , -, signed char, 1, newval) |
| 153 | SUBWORD_SYNC_OP (or, , |, signed char, 1, newval) |
| 154 | SUBWORD_SYNC_OP (and, , &, signed char, 1, newval) |
| 155 | SUBWORD_SYNC_OP (xor, , ^, signed char, 1, newval) |
| 156 | SUBWORD_SYNC_OP (nand, ~, &, signed char, 1, newval) |
| 157 | |
| 158 | int HIDDEN |
| 159 | __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) |
| 160 | { |
| 161 | int actual_oldval; |
| 162 | |
| 163 | for (;;) |
| 164 | { |
| 165 | actual_oldval = *ptr; |
| 166 | |
| 167 | if (__builtin_expect (oldval != actual_oldval, 0)) |
| 168 | return actual_oldval; |
| 169 | |
| 170 | if (_kern_atomic_test_and_set(ptr, newval, oldval) == oldval) |
| 171 | return oldval; |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | #define SUBWORD_VAL_CAS(TYPE, WIDTH) \ |
| 176 | TYPE HIDDEN \ |
| 177 | __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, TYPE newval) \ |
| 178 | { \ |
| 179 | int *wordptr = (int *)((unsigned int) ptr & ~3); \ |
| 180 | unsigned int mask, shift, actual_oldval, actual_newval; \ |
| 181 | \ |
| 182 | shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ |
| 183 | mask = MASK_##WIDTH << shift; \ |
| 184 | \ |
| 185 | for (;;) \ |
| 186 | { \ |
| 187 | actual_oldval = *wordptr; \ |
| 188 | \ |
| 189 | if (__builtin_expect (((actual_oldval & mask) >> shift) != \ |
| 190 | ((unsigned int) oldval & MASK_##WIDTH), 0)) \ |
| 191 | return (actual_oldval & mask) >> shift; \ |
| 192 | \ |
| 193 | actual_newval = (actual_oldval & ~mask) \ |
| 194 | | (((unsigned int) newval << shift) & mask); \ |
| 195 | \ |
| 196 | if ((unsigned int) _kern_atomic_test_and_set(wordptr, actual_newval, \ |
| 197 | actual_oldval) == actual_oldval) \ |
| 198 | return oldval; \ |
| 199 | } \ |
| 200 | } |
| 201 | |
| 202 | SUBWORD_VAL_CAS (short, 2) |
| 203 | SUBWORD_VAL_CAS (signed char, 1) |
| 204 | |
| 205 | typedef unsigned char bool; |
| 206 | |
| 207 | bool HIDDEN |
| 208 | __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval) |
| 209 | { |
| 210 | return (_kern_atomic_test_and_set(ptr, newval, oldval) == oldval); |
| 211 | } |
| 212 | |
| 213 | #define SUBWORD_BOOL_CAS(TYPE, WIDTH) \ |
| 214 | bool HIDDEN \ |
| 215 | __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, TYPE newval) \ |
| 216 | { \ |
| 217 | TYPE actual_oldval = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \ |
| 218 | return (oldval == actual_oldval); \ |
| 219 | } |
| 220 | |
| 221 | SUBWORD_BOOL_CAS (short, 2) |
| 222 | SUBWORD_BOOL_CAS (signed char, 1) |
| 223 | |
| 224 | int HIDDEN |
| 225 | __sync_lock_test_and_set_4 (int *ptr, int val) |
| 226 | { |
| 227 | int oldval; |
| 228 | |
| 229 | do { |
| 230 | oldval = *ptr; |
| 231 | } while(_kern_atomic_test_and_set(ptr, val, oldval) != oldval); |
| 232 | |
| 233 | return oldval; |
| 234 | } |
| 235 | |
| 236 | #define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \ |
| 237 | TYPE HIDDEN \ |
| 238 | __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \ |
| 239 | { \ |
| 240 | unsigned int oldval, newval, shift, mask; \ |
| 241 | int *wordptr = (int *) ((unsigned int) ptr & ~3); \ |
| 242 | \ |
| 243 | shift = (((unsigned int) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ |
| 244 | mask = MASK_##WIDTH << shift; \ |
| 245 | \ |
| 246 | do { \ |
| 247 | oldval = *wordptr; \ |
| 248 | newval = (oldval & ~mask) \ |
| 249 | | (((unsigned int) val << shift) & mask); \ |
| 250 | } while ((unsigned int) _kern_atomic_test_and_set(wordptr, newval, oldval) \ |
| 251 | != oldval); \ |
| 252 | \ |
| 253 | return (oldval & mask) >> shift; \ |
| 254 | } |
| 255 | |
| 256 | SUBWORD_TEST_AND_SET (short, 2) |
| 257 | SUBWORD_TEST_AND_SET (signed char, 1) |
| 258 | |
| 259 | #define SYNC_LOCK_RELEASE(TYPE, WIDTH) \ |
| 260 | void HIDDEN \ |
| 261 | __sync_lock_release_##WIDTH (TYPE *ptr) \ |
| 262 | { \ |
| 263 | *ptr = 0; \ |
| 264 | } |
| 265 | |
| 266 | SYNC_LOCK_RELEASE (long long, 8) |
| 267 | SYNC_LOCK_RELEASE (int, 4) |
| 268 | SYNC_LOCK_RELEASE (short, 2) |
| 269 | SYNC_LOCK_RELEASE (char, 1) |
| 270 | |