-again:
- // Mach semaphores appear to sometimes spuriously wake up. Therefore,
- // we keep a parallel count of the number of times a Mach semaphore is
- // signaled (6880961).
- while ((orig = dsema->dsema_sent_ksignals)) {
- if (dispatch_atomic_cmpxchg2o(dsema, dsema_sent_ksignals, orig,
- orig - 1)) {
- return 0;
- }
- }
-
-#if USE_MACH_SEM
- mach_timespec_t _timeout;
- kern_return_t kr;
-
- _dispatch_semaphore_create_port(&dsema->dsema_port);
-
- // From xnu/osfmk/kern/sync_sema.c:
- // wait_semaphore->count = -1; /* we don't keep an actual count */
- //
- // The code above does not match the documentation, and that fact is
- // not surprising. The documented semantics are clumsy to use in any
- // practical way. The above hack effectively tricks the rest of the
- // Mach semaphore logic to behave like the libdispatch algorithm.
-
- switch (timeout) {
- default:
- do {
- uint64_t nsec = _dispatch_timeout(timeout);
- _timeout.tv_sec = (typeof(_timeout.tv_sec))(nsec / NSEC_PER_SEC);
- _timeout.tv_nsec = (typeof(_timeout.tv_nsec))(nsec % NSEC_PER_SEC);
- kr = slowpath(semaphore_timedwait(dsema->dsema_port, _timeout));
- } while (kr == KERN_ABORTED);
-
- if (kr != KERN_OPERATION_TIMED_OUT) {
- DISPATCH_SEMAPHORE_VERIFY_KR(kr);
- break;
- }
- // Fall through and try to undo what the fast path did to
- // dsema->dsema_value
- case DISPATCH_TIME_NOW:
- while ((orig = dsema->dsema_value) < 0) {
- if (dispatch_atomic_cmpxchg2o(dsema, dsema_value, orig, orig + 1)) {
- return KERN_OPERATION_TIMED_OUT;
- }
- }
- // Another thread called semaphore_signal().
- // Fall through and drain the wakeup.
- case DISPATCH_TIME_FOREVER:
- do {
- kr = semaphore_wait(dsema->dsema_port);
- } while (kr == KERN_ABORTED);
- DISPATCH_SEMAPHORE_VERIFY_KR(kr);
- break;
- }
-#elif USE_POSIX_SEM
- struct timespec _timeout;
- int ret;
-