|
| 1 | +#include <stdint.h> |
| 2 | +#include <time.h> |
| 3 | +#include <errno.h> |
| 4 | + |
| 5 | +#define DEFINE_GLOBAL_GETTER(name, core_type, c_type) \ |
| 6 | + static inline c_type name##_get(void) { \ |
| 7 | + c_type val; \ |
| 8 | + __asm__( \ |
| 9 | + ".globaltype " #name ", " #core_type "\n" \ |
| 10 | + "global.get " #name "\n" \ |
| 11 | + "local.set %0\n" \ |
| 12 | + : "=r"(val)); \ |
| 13 | + return val; \ |
| 14 | + } |
| 15 | +#define DEFINE_GLOBAL_SETTER(name, core_type, c_type) \ |
| 16 | + static inline void name##_set(c_type val) { \ |
| 17 | + __asm__( \ |
| 18 | + ".globaltype " #name ", " #core_type "\n" \ |
| 19 | + "local.get %0\n" \ |
| 20 | + "global.set " #name "\n" \ |
| 21 | + : : "r"(val)); \ |
| 22 | + } |
| 23 | + |
| 24 | +#define DEFINE_RW_GLOBAL(name, core_type, c_type) \ |
| 25 | + __asm__( \ |
| 26 | + ".globaltype " #name ", " #core_type "\n" \ |
| 27 | + ".global " #name "\n" \ |
| 28 | + #name ":\n" \ |
| 29 | + ); \ |
| 30 | + DEFINE_GLOBAL_GETTER(name, core_type, c_type) \ |
| 31 | + DEFINE_GLOBAL_SETTER(name, core_type, c_type) |
| 32 | + |
| 33 | +DEFINE_RW_GLOBAL(__wasilibc_use_busy_futex, i32, int32_t) |
| 34 | + |
| 35 | +void __wasilibc_enable_futex_busywait_on_current_thread(void) |
| 36 | +{ |
| 37 | + __wasilibc_use_busy_futex_set(1); |
| 38 | +} |
| 39 | + |
| 40 | +int __wasilibc_futex_wait_atomic_wait(volatile void *addr, int op, int val, int64_t max_wait_ns); |
| 41 | + |
| 42 | +int __wasilibc_futex_wait_maybe_busy(volatile void *addr, int op, int val, int64_t max_wait_ns) |
| 43 | +{ |
| 44 | + // PLEASE NOTE THAT WE CANNOT CALL LIBC FUNCTIONS THAT USE FUTEXES HERE |
| 45 | + |
| 46 | + if (!__wasilibc_use_busy_futex_get()) { |
| 47 | + return __wasilibc_futex_wait_atomic_wait(addr, op, val, max_wait_ns); |
| 48 | + } |
| 49 | + |
| 50 | + struct timespec start; |
| 51 | + int r = clock_gettime(CLOCK_REALTIME, &start); |
| 52 | + |
| 53 | + // If we can't get the current time, we can't wait with a timeout. |
| 54 | + if (r) return r; |
| 55 | + |
| 56 | + while (1) { |
| 57 | + // Check timeout if it's a positive value |
| 58 | + if (max_wait_ns >= 0) { |
| 59 | + struct timespec now; |
| 60 | + r = clock_gettime(CLOCK_REALTIME, &now); |
| 61 | + if (r) return r; |
| 62 | + |
| 63 | + int64_t elapsed_ns = (now.tv_sec - start.tv_sec) * 1000000000 + now.tv_nsec - start.tv_nsec; |
| 64 | + if (elapsed_ns >= max_wait_ns) { |
| 65 | + return -ETIMEDOUT; |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + if (__c11_atomic_load((_Atomic int *)addr, __ATOMIC_SEQ_CST) != val) { |
| 70 | + break; |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + return 0; |
| 75 | +} |
0 commit comments