If have no these memory barriers, sometime it will cause bug in multiple threads program.
Unified · Split
| @@ -15,6 +15,56 @@ · 14 unmodified lines | |||
| 15 | #define __ATOMIC_SEQ_CST 5 | 15 | #define __ATOMIC_SEQ_CST 5 |
| 16 | typedef __SIZE_TYPE__ size_t; | 16 | typedef __SIZE_TYPE__ size_t; |
| 17 | 17 | ||
| 18 | /* uses alias to allow building with gcc/clang */ | ||
| 19 | #ifdef __TINYC__ | ||
| 20 | #define ATOMIC(x) __atomic_##x | ||
| 21 | #else | ||
| 22 | #define ATOMIC(x) __tcc_atomic_##x | ||
| 23 | #endif | ||
| 24 | |||
| 25 | void ATOMIC(signal_fence) (int memorder) | ||
| 26 | { | ||
| 27 | } | ||
| 28 | |||
| 29 | void ATOMIC(thread_fence) (int memorder) | ||
| 30 | { | ||
| 31 | #if defined __i386__ | ||
| 32 | __asm__ volatile("lock orl $0, (%esp)"); | ||
| 33 | #elif defined __x86_64__ | ||
| 34 | __asm__ volatile("lock orq $0, (%rsp)"); | ||
| 35 | #elif defined __arm__ | ||
| 36 | __asm__ volatile(".int 0xee070fba"); // mcr p15, 0, r0, c7, c10, 5 | ||
| 37 | #elif defined __aarch64__ | ||
| 38 | __asm__ volatile(".int 0xd5033bbf"); // dmb ish | ||
| 39 | #elif defined __riscv | ||
| 40 | __asm__ volatile(".int 0x0ff0000f"); // fence iorw,iorw | ||
| 41 | #endif | ||
| 42 | } | ||
| 43 | |||
| 44 | bool ATOMIC(is_lock_free) (unsigned long size, const volatile void *ptr) | ||
| 45 | { | ||
| 46 | bool ret; | ||
| 47 | |||
| 48 | switch (size) { | ||
| 49 | case 1: ret = true; break; | ||
| 50 | case 2: ret = true; break; | ||
| 51 | case 4: ret = true; break; | ||
| 52 | #if defined __x86_64__ || defined __aarch64__ || defined __riscv | ||
| 53 | case 8: ret = true; break; | ||
| 54 | #else | ||
| 55 | case 8: ret = false; break; | ||
| 56 | #endif | ||
| 57 | default: ret = false; break; | ||
| 58 | } | ||
| 59 | return ret; | ||
| 60 | } | ||
| 61 | |||
| 62 | #ifndef __TINYC__ | ||
| 63 | void __atomic_signal_fence(int memorder) __attribute__((alias("__tcc_atomic_signal_fence"))); | ||
| 64 | void __atomic_thread_fence(int memorder) __attribute__((alias("__tcc_atomic_thread_fence"))); | ||
| 65 | bool __atomic_is_lock_free(unsigned long size, const volatile void *ptr) __attribute__((alias("__tcc_atomic_is_lock_free"))); | ||
| 66 | #endif | ||
| 67 | |||
| 18 | #if defined __i386__ || defined __x86_64__ | 68 | #if defined __i386__ || defined __x86_64__ |
| 19 | #define ATOMIC_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \ | 69 | #define ATOMIC_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \ |
| 20 | bool __atomic_compare_exchange_##MODE \ | 70 | bool __atomic_compare_exchange_##MODE \ |
| @@ -42,6 +92,7 @@ typedef __SIZE_TYPE__ size_t; · 21 unmodified lines | |||
| 42 | #define ATOMIC_LOAD(TYPE, MODE) \ | 92 | #define ATOMIC_LOAD(TYPE, MODE) \ |
| 43 | TYPE __atomic_load_##MODE(const volatile void *atom, int memorder) \ | 93 | TYPE __atomic_load_##MODE(const volatile void *atom, int memorder) \ |
| 44 | { \ | 94 | { \ |
| 95 | __atomic_thread_fence(__ATOMIC_ACQUIRE); \ | ||
| 45 | return *(volatile TYPE *)atom; \ | 96 | return *(volatile TYPE *)atom; \ |
| 46 | } | 97 | } |
| 47 | 98 | ||
| @@ -49,6 +100,7 @@ typedef __SIZE_TYPE__ size_t; · 1 unmodified line | |||
| 49 | void __atomic_store_##MODE(volatile void *atom, TYPE value, int memorder) \ | 100 | void __atomic_store_##MODE(volatile void *atom, TYPE value, int memorder) \ |
| 50 | { \ | 101 | { \ |
| 51 | *(volatile TYPE *)atom = value; \ | 102 | *(volatile TYPE *)atom = value; \ |
| 103 | __atomic_thread_fence(__ATOMIC_RELEASE); \ | ||
| 52 | } | 104 | } |
| 53 | 105 | ||
| 54 | #define ATOMIC_GEN_OP(TYPE, MODE, NAME, OP, RET) \ | 106 | #define ATOMIC_GEN_OP(TYPE, MODE, NAME, OP, RET) \ |
| @@ -114,53 +166,3 @@ ATOMIC_GEN(uint32_t, 4, "l") · 59 unmodified lines | |||
| 114 | #if defined __x86_64__ || defined __aarch64__ || defined __riscv | 166 | #if defined __x86_64__ || defined __aarch64__ || defined __riscv |
| 115 | ATOMIC_GEN(uint64_t, 8, "q") | 167 | ATOMIC_GEN(uint64_t, 8, "q") |
| 116 | #endif | 168 | #endif |
| 117 | |||
| 118 | /* uses alias to allow building with gcc/clang */ | ||
| 119 | #ifdef __TINYC__ | ||
| 120 | #define ATOMIC(x) __atomic_##x | ||
| 121 | #else | ||
| 122 | #define ATOMIC(x) __tcc_atomic_##x | ||
| 123 | #endif | ||
| 124 | |||
| 125 | void ATOMIC(signal_fence) (int memorder) | ||
| 126 | { | ||
| 127 | } | ||
| 128 | |||
| 129 | void ATOMIC(thread_fence) (int memorder) | ||
| 130 | { | ||
| 131 | #if defined __i386__ | ||
| 132 | __asm__ volatile("lock orl $0, (%esp)"); | ||
| 133 | #elif defined __x86_64__ | ||
| 134 | __asm__ volatile("lock orq $0, (%rsp)"); | ||
| 135 | #elif defined __arm__ | ||
| 136 | __asm__ volatile(".int 0xee070fba"); // mcr p15, 0, r0, c7, c10, 5 | ||
| 137 | #elif defined __aarch64__ | ||
| 138 | __asm__ volatile(".int 0xd5033bbf"); // dmb ish | ||
| 139 | #elif defined __riscv | ||
| 140 | __asm__ volatile(".int 0x0ff0000f"); // fence iorw,iorw | ||
| 141 | #endif | ||
| 142 | } | ||
| 143 | |||
| 144 | bool ATOMIC(is_lock_free) (unsigned long size, const volatile void *ptr) | ||
| 145 | { | ||
| 146 | bool ret; | ||
| 147 | |||
| 148 | switch (size) { | ||
| 149 | case 1: ret = true; break; | ||
| 150 | case 2: ret = true; break; | ||
| 151 | case 4: ret = true; break; | ||
| 152 | #if defined __x86_64__ || defined __aarch64__ || defined __riscv | ||
| 153 | case 8: ret = true; break; | ||
| 154 | #else | ||
| 155 | case 8: ret = false; break; | ||
| 156 | #endif | ||
| 157 | default: ret = false; break; | ||
| 158 | } | ||
| 159 | return ret; | ||
| 160 | } | ||
| 161 | |||
| 162 | #ifndef __TINYC__ | ||
| 163 | void __atomic_signal_fence(int memorder) __attribute__((alias("__tcc_atomic_signal_fence"))); | ||
| 164 | void __atomic_thread_fence(int memorder) __attribute__((alias("__tcc_atomic_thread_fence"))); | ||
| 165 | bool __atomic_is_lock_free(unsigned long size, const volatile void *ptr) __attribute__((alias("__tcc_atomic_is_lock_free"))); | ||
| 166 | #endif | ||