As a followup, here's how one would use gsync to implement something akin to Linux futexes.
=============================== #include <mach/gnumach.h> #include <mach.h> /* This bit signals that the lock is being held. The rest of * the word tells us how many waiters there are. */ #define BIT31 (1U << 31) #define atomic_cas_bool(Ptr, Exp, Nval) \ ({ \ typeof (Exp) __e = (Exp); \ __atomic_compare_exchange_n ((Ptr), &__e, (Nval), 1, \ __ATOMIC_ACQ_REL, __ATOMIC_RELAXED); \ }) #define atomic_add(Ptr, Val) \ __atomic_fetch_add ((Ptr), (Val), __ATOMIC_ACQ_REL) /* Lock the futex PTR. FLAGS may be zero in case we're dealing * with a task-local lock, or GSYNC_SHARED for a task-shared one. */ static void futex_lock (unsigned int *ptr, int flags) { unsigned int val = *ptr; if (!(val & BIT31) && atomic_cas_bool (ptr, val, val | BIT31)) return; atomic_add (ptr, 1); while (1) { val = *ptr; if (!(val & BIT31) && atomic_cas_bool (ptr, val, (val - 1) | BIT31)) break; gsync_wait (mach_task_self (), (vm_offset_t)ptr, val, 0, 0, flags); } } /* Unlock the futex PTR. See above for a description on what FLAGS does. */ static void futex_unlock (unsigned int *ptr, int flags) { unsigned int val = atomic_add (ptr, BIT31); if (val != BIT31) gsync_wait (mach_task_self (), (vm_offset_t)ptr, 0, flags); }