futex_darwin.c raw

   1  //go:build none
   2  
   3  // This file is manually included, to avoid CGo which would cause a circular
   4  // import.
   5  
   6  #include <stdint.h>
   7  
   8  // This API isn't documented by Apple, but it is used by LLVM libc++ (so should
   9  // be stable) and has been documented extensively here:
  10  // https://outerproduct.net/futex-dictionary.html
  11  
  12  int __ulock_wait(uint32_t operation, void *addr, uint64_t value, uint32_t timeout_us);
  13  int __ulock_wait2(uint32_t operation, void *addr, uint64_t value, uint64_t timeout_ns, uint64_t value2);
  14  int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
  15  
  16  // Operation code.
  17  #define UL_COMPARE_AND_WAIT 1
  18  
  19  // Flags to the operation value.
  20  #define ULF_WAKE_ALL 0x00000100
  21  #define ULF_NO_ERRNO 0x01000000
  22  
  23  void moxie_futex_wait(uint32_t *addr, uint32_t cmp) {
  24      __ulock_wait(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, (uint64_t)cmp, 0);
  25  }
  26  
  27  void moxie_futex_wait_timeout(uint32_t *addr, uint32_t cmp, uint64_t timeout) {
  28      // Make sure that an accidental use of a zero timeout is not treated as an
  29      // infinite timeout. Return if it's zero since it wouldn't be waiting for
  30      // any significant time anyway.
  31      // Probably unnecessary, but guards against potential bugs.
  32      if (timeout == 0) {
  33          return;
  34      }
  35  
  36      // Note: __ulock_wait2 is available since MacOS 11.
  37      // I think that's fine, since the version before that (MacOS 10.15) is EOL
  38      // since 2022. Though if needed, we could certainly use __ulock_wait instead
  39      // and deal with the smaller timeout value.
  40      __ulock_wait2(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, (uint64_t)cmp, timeout, 0);
  41  }
  42  
  43  void moxie_futex_wake(uint32_t *addr) {
  44      __ulock_wake(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO, addr, 0);
  45  }
  46  
  47  void moxie_futex_wake_all(uint32_t *addr) {
  48      __ulock_wake(UL_COMPARE_AND_WAIT|ULF_NO_ERRNO|ULF_WAKE_ALL, addr, 0);
  49  }
  50