2 * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
23 // semaphores are too fundamental to use the dispatch_assume*() macros
25 #define DISPATCH_SEMAPHORE_VERIFY_KR(x) do { \
26 if (slowpath((x) == KERN_INVALID_NAME)) { \
27 DISPATCH_CLIENT_CRASH("Use-after-free of dispatch_semaphore_t"); \
28 } else if (slowpath(x)) { \
29 DISPATCH_CRASH("mach semaphore API failure"); \
32 #define DISPATCH_GROUP_VERIFY_KR(x) do { \
33 if (slowpath((x) == KERN_INVALID_NAME)) { \
34 DISPATCH_CLIENT_CRASH("Use-after-free of dispatch_group_t"); \
35 } else if (slowpath(x)) { \
36 DISPATCH_CRASH("mach semaphore API failure"); \
40 #define DISPATCH_SEMAPHORE_VERIFY_RET(x) do { \
41 if (slowpath((x) == -1)) { \
42 DISPATCH_CRASH("POSIX semaphore API failure"); \
48 // rdar://problem/8428132
49 static DWORD best_resolution
= 1; // 1ms
52 _push_timer_resolution(DWORD ms
)
55 static dispatch_once_t once
;
58 // only update timer resolution if smaller than default 15.6ms
59 // zero means not updated
63 // aim for the best resolution we can accomplish
64 dispatch_once(&once
, ^{
67 res
= timeGetDevCaps(&tc
, sizeof(tc
));
68 if (res
== MMSYSERR_NOERROR
) {
69 best_resolution
= min(max(tc
.wPeriodMin
, best_resolution
),
74 res
= timeBeginPeriod(best_resolution
);
75 if (res
== TIMERR_NOERROR
) {
76 return best_resolution
;
78 // zero means not updated
82 // match ms parameter to result from _push_timer_resolution
84 _pop_timer_resolution(DWORD ms
)
90 #endif /* USE_WIN32_SEM */
93 DISPATCH_WEAK
// rdar://problem/8503746
94 long _dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema
);
96 static long _dispatch_group_wake(dispatch_semaphore_t dsema
);
99 #pragma mark dispatch_semaphore_t
102 _dispatch_semaphore_init(long value
, dispatch_object_t dou
)
104 dispatch_semaphore_t dsema
= dou
._dsema
;
106 dsema
->do_next
= (dispatch_semaphore_t
)DISPATCH_OBJECT_LISTLESS
;
107 dsema
->do_targetq
= _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT
,
109 dsema
->dsema_value
= value
;
110 dsema
->dsema_orig
= value
;
112 int ret
= sem_init(&dsema
->dsema_sem
, 0, 0);
113 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
118 dispatch_semaphore_create(long value
)
120 dispatch_semaphore_t dsema
;
122 // If the internal value is negative, then the absolute of the value is
123 // equal to the number of waiting threads. Therefore it is bogus to
124 // initialize the semaphore with a negative value.
129 dsema
= (dispatch_semaphore_t
)_dispatch_alloc(DISPATCH_VTABLE(semaphore
),
130 sizeof(struct dispatch_semaphore_s
) -
131 sizeof(dsema
->dsema_notify_head
) -
132 sizeof(dsema
->dsema_notify_tail
));
133 _dispatch_semaphore_init(value
, dsema
);
139 _dispatch_semaphore_create_port(semaphore_t
*s4
)
147 _dispatch_safe_fork
= false;
149 // lazily allocate the semaphore port
152 // 1) Switch to a doubly-linked FIFO in user-space.
153 // 2) User-space timers for the timeout.
154 // 3) Use the per-thread semaphore port.
156 while ((kr
= semaphore_create(mach_task_self(), &tmp
,
157 SYNC_POLICY_FIFO
, 0))) {
158 DISPATCH_VERIFY_MIG(kr
);
159 _dispatch_temporary_resource_shortage();
162 if (!dispatch_atomic_cmpxchg(s4
, 0, tmp
, relaxed
)) {
163 kr
= semaphore_destroy(mach_task_self(), tmp
);
164 DISPATCH_VERIFY_MIG(kr
);
165 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
170 _dispatch_semaphore_create_handle(HANDLE
*s4
)
178 // lazily allocate the semaphore port
180 while (!dispatch_assume(tmp
= CreateSemaphore(NULL
, 0, LONG_MAX
, NULL
))) {
181 _dispatch_temporary_resource_shortage();
184 if (!dispatch_atomic_cmpxchg(s4
, 0, tmp
)) {
191 _dispatch_semaphore_dispose(dispatch_object_t dou
)
193 dispatch_semaphore_t dsema
= dou
._dsema
;
195 if (dsema
->dsema_value
< dsema
->dsema_orig
) {
196 DISPATCH_CLIENT_CRASH(
197 "Semaphore/group object deallocated while in use");
202 if (dsema
->dsema_port
) {
203 kr
= semaphore_destroy(mach_task_self(), dsema
->dsema_port
);
204 DISPATCH_VERIFY_MIG(kr
);
205 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
207 dsema
->dsema_port
= MACH_PORT_DEAD
;
209 int ret
= sem_destroy(&dsema
->dsema_sem
);
210 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
212 if (dsema
->dsema_handle
) {
213 CloseHandle(dsema
->dsema_handle
);
219 _dispatch_semaphore_debug(dispatch_object_t dou
, char *buf
, size_t bufsiz
)
221 dispatch_semaphore_t dsema
= dou
._dsema
;
224 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
, "%s[%p] = { ",
225 dx_kind(dsema
), dsema
);
226 offset
+= _dispatch_object_debug_attr(dsema
, &buf
[offset
], bufsiz
- offset
);
228 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
, "port = 0x%u, ",
231 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
,
232 "value = %ld, orig = %ld }", dsema
->dsema_value
, dsema
->dsema_orig
);
238 _dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema
)
240 // Before dsema_sent_ksignals is incremented we can rely on the reference
241 // held by the waiter. However, once this value is incremented the waiter
242 // may return between the atomic increment and the semaphore_signal(),
243 // therefore an explicit reference must be held in order to safely access
244 // dsema after the atomic increment.
245 _dispatch_retain(dsema
);
247 #if USE_MACH_SEM || USE_POSIX_SEM
248 (void)dispatch_atomic_inc2o(dsema
, dsema_sent_ksignals
, relaxed
);
252 _dispatch_semaphore_create_port(&dsema
->dsema_port
);
253 kern_return_t kr
= semaphore_signal(dsema
->dsema_port
);
254 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
256 int ret
= sem_post(&dsema
->dsema_sem
);
257 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
259 _dispatch_semaphore_create_handle(&dsema
->dsema_handle
);
260 int ret
= ReleaseSemaphore(dsema
->dsema_handle
, 1, NULL
);
261 dispatch_assume(ret
);
264 _dispatch_release(dsema
);
269 dispatch_semaphore_signal(dispatch_semaphore_t dsema
)
271 long value
= dispatch_atomic_inc2o(dsema
, dsema_value
, release
);
272 if (fastpath(value
> 0)) {
275 if (slowpath(value
== LONG_MIN
)) {
276 DISPATCH_CLIENT_CRASH("Unbalanced call to dispatch_semaphore_signal()");
278 return _dispatch_semaphore_signal_slow(dsema
);
283 _dispatch_semaphore_wait_slow(dispatch_semaphore_t dsema
,
284 dispatch_time_t timeout
)
289 mach_timespec_t _timeout
;
292 struct timespec _timeout
;
301 #if USE_MACH_SEM || USE_POSIX_SEM
303 // Mach semaphores appear to sometimes spuriously wake up. Therefore,
304 // we keep a parallel count of the number of times a Mach semaphore is
305 // signaled (6880961).
306 orig
= dsema
->dsema_sent_ksignals
;
308 if (dispatch_atomic_cmpxchgvw2o(dsema
, dsema_sent_ksignals
, orig
,
309 orig
- 1, &orig
, relaxed
)) {
316 _dispatch_semaphore_create_port(&dsema
->dsema_port
);
318 _dispatch_semaphore_create_handle(&dsema
->dsema_handle
);
321 // From xnu/osfmk/kern/sync_sema.c:
322 // wait_semaphore->count = -1; /* we don't keep an actual count */
324 // The code above does not match the documentation, and that fact is
325 // not surprising. The documented semantics are clumsy to use in any
326 // practical way. The above hack effectively tricks the rest of the
327 // Mach semaphore logic to behave like the libdispatch algorithm.
333 uint64_t nsec
= _dispatch_timeout(timeout
);
334 _timeout
.tv_sec
= (typeof(_timeout
.tv_sec
))(nsec
/ NSEC_PER_SEC
);
335 _timeout
.tv_nsec
= (typeof(_timeout
.tv_nsec
))(nsec
% NSEC_PER_SEC
);
336 kr
= slowpath(semaphore_timedwait(dsema
->dsema_port
, _timeout
));
337 } while (kr
== KERN_ABORTED
);
339 if (kr
!= KERN_OPERATION_TIMED_OUT
) {
340 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
345 uint64_t nsec
= _dispatch_timeout(timeout
);
346 _timeout
.tv_sec
= (typeof(_timeout
.tv_sec
))(nsec
/ NSEC_PER_SEC
);
347 _timeout
.tv_nsec
= (typeof(_timeout
.tv_nsec
))(nsec
% NSEC_PER_SEC
);
348 ret
= slowpath(sem_timedwait(&dsema
->dsema_sem
, &_timeout
));
349 } while (ret
== -1 && errno
== EINTR
);
351 if (ret
== -1 && errno
!= ETIMEDOUT
) {
352 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
356 nsec
= _dispatch_timeout(timeout
);
357 msec
= (DWORD
)(nsec
/ (uint64_t)1000000);
358 resolution
= _push_timer_resolution(msec
);
359 wait_result
= WaitForSingleObject(dsema
->dsema_handle
, msec
);
360 _pop_timer_resolution(resolution
);
361 if (wait_result
!= WAIT_TIMEOUT
) {
365 // Fall through and try to undo what the fast path did to
366 // dsema->dsema_value
367 case DISPATCH_TIME_NOW
:
368 orig
= dsema
->dsema_value
;
370 if (dispatch_atomic_cmpxchgvw2o(dsema
, dsema_value
, orig
, orig
+ 1,
373 return KERN_OPERATION_TIMED_OUT
;
374 #elif USE_POSIX_SEM || USE_WIN32_SEM
380 // Another thread called semaphore_signal().
381 // Fall through and drain the wakeup.
382 case DISPATCH_TIME_FOREVER
:
385 kr
= semaphore_wait(dsema
->dsema_port
);
386 } while (kr
== KERN_ABORTED
);
387 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
390 ret
= sem_wait(&dsema
->dsema_sem
);
392 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
394 WaitForSingleObject(dsema
->dsema_handle
, INFINITE
);
398 #if USE_MACH_SEM || USE_POSIX_SEM
406 dispatch_semaphore_wait(dispatch_semaphore_t dsema
, dispatch_time_t timeout
)
408 long value
= dispatch_atomic_dec2o(dsema
, dsema_value
, acquire
);
409 if (fastpath(value
>= 0)) {
412 return _dispatch_semaphore_wait_slow(dsema
, timeout
);
416 #pragma mark dispatch_group_t
418 DISPATCH_ALWAYS_INLINE
419 static inline dispatch_group_t
420 _dispatch_group_create_with_count(long count
)
422 dispatch_group_t dg
= (dispatch_group_t
)_dispatch_alloc(
423 DISPATCH_VTABLE(group
), sizeof(struct dispatch_semaphore_s
));
424 _dispatch_semaphore_init(LONG_MAX
- count
, dg
);
429 dispatch_group_create(void)
431 return _dispatch_group_create_with_count(0);
435 _dispatch_group_create_and_enter(void)
437 return _dispatch_group_create_with_count(1);
441 dispatch_group_enter(dispatch_group_t dg
)
443 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)dg
;
444 long value
= dispatch_atomic_dec2o(dsema
, dsema_value
, acquire
);
445 if (slowpath(value
< 0)) {
446 DISPATCH_CLIENT_CRASH(
447 "Too many nested calls to dispatch_group_enter()");
453 _dispatch_group_wake(dispatch_semaphore_t dsema
)
455 dispatch_continuation_t next
, head
, tail
= NULL
, dc
;
458 head
= dispatch_atomic_xchg2o(dsema
, dsema_notify_head
, NULL
, relaxed
);
460 // snapshot before anything is notified/woken <rdar://problem/8554546>
461 tail
= dispatch_atomic_xchg2o(dsema
, dsema_notify_tail
, NULL
, relaxed
);
463 rval
= (long)dispatch_atomic_xchg2o(dsema
, dsema_group_waiters
, 0, relaxed
);
465 // wake group waiters
467 _dispatch_semaphore_create_port(&dsema
->dsema_port
);
469 kern_return_t kr
= semaphore_signal(dsema
->dsema_port
);
470 DISPATCH_GROUP_VERIFY_KR(kr
);
474 int ret
= sem_post(&dsema
->dsema_sem
);
475 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
478 _dispatch_semaphore_create_handle(&dsema
->dsema_handle
);
480 ret
= ReleaseSemaphore(dsema
->dsema_handle
, rval
, NULL
);
481 dispatch_assume(ret
);
483 #error "No supported semaphore type"
487 // async group notify blocks
489 next
= fastpath(head
->do_next
);
490 if (!next
&& head
!= tail
) {
491 _dispatch_wait_until(next
= fastpath(head
->do_next
));
493 dispatch_queue_t dsn_queue
= (dispatch_queue_t
)head
->dc_data
;
494 dc
= _dispatch_continuation_free_cacheonly(head
);
495 dispatch_async_f(dsn_queue
, head
->dc_ctxt
, head
->dc_func
);
496 _dispatch_release(dsn_queue
);
498 _dispatch_continuation_free_to_cache_limit(dc
);
500 } while ((head
= next
));
501 _dispatch_release(dsema
);
507 dispatch_group_leave(dispatch_group_t dg
)
509 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)dg
;
510 long value
= dispatch_atomic_inc2o(dsema
, dsema_value
, release
);
511 if (slowpath(value
< 0)) {
512 DISPATCH_CLIENT_CRASH("Unbalanced call to dispatch_group_leave()");
514 if (slowpath(value
== LONG_MAX
)) {
515 (void)_dispatch_group_wake(dsema
);
521 _dispatch_group_wait_slow(dispatch_semaphore_t dsema
, dispatch_time_t timeout
)
526 mach_timespec_t _timeout
;
528 #elif USE_POSIX_SEM // KVV
529 struct timespec _timeout
;
531 #elif USE_WIN32_SEM // KVV
539 // check before we cause another signal to be sent by incrementing
540 // dsema->dsema_group_waiters
541 value
= dispatch_atomic_load2o(dsema
, dsema_value
, seq_cst
); // 19296565
542 if (value
== LONG_MAX
) {
543 return _dispatch_group_wake(dsema
);
545 // Mach semaphores appear to sometimes spuriously wake up. Therefore,
546 // we keep a parallel count of the number of times a Mach semaphore is
547 // signaled (6880961).
548 (void)dispatch_atomic_inc2o(dsema
, dsema_group_waiters
, relaxed
);
549 // check the values again in case we need to wake any threads
550 value
= dispatch_atomic_load2o(dsema
, dsema_value
, seq_cst
); // 19296565
551 if (value
== LONG_MAX
) {
552 return _dispatch_group_wake(dsema
);
556 _dispatch_semaphore_create_port(&dsema
->dsema_port
);
558 _dispatch_semaphore_create_handle(&dsema
->dsema_handle
);
561 // From xnu/osfmk/kern/sync_sema.c:
562 // wait_semaphore->count = -1; /* we don't keep an actual count */
564 // The code above does not match the documentation, and that fact is
565 // not surprising. The documented semantics are clumsy to use in any
566 // practical way. The above hack effectively tricks the rest of the
567 // Mach semaphore logic to behave like the libdispatch algorithm.
573 uint64_t nsec
= _dispatch_timeout(timeout
);
574 _timeout
.tv_sec
= (typeof(_timeout
.tv_sec
))(nsec
/ NSEC_PER_SEC
);
575 _timeout
.tv_nsec
= (typeof(_timeout
.tv_nsec
))(nsec
% NSEC_PER_SEC
);
576 kr
= slowpath(semaphore_timedwait(dsema
->dsema_port
, _timeout
));
577 } while (kr
== KERN_ABORTED
);
579 if (kr
!= KERN_OPERATION_TIMED_OUT
) {
580 DISPATCH_GROUP_VERIFY_KR(kr
);
585 uint64_t nsec
= _dispatch_timeout(timeout
);
586 _timeout
.tv_sec
= (typeof(_timeout
.tv_sec
))(nsec
/ NSEC_PER_SEC
);
587 _timeout
.tv_nsec
= (typeof(_timeout
.tv_nsec
))(nsec
% NSEC_PER_SEC
);
588 ret
= slowpath(sem_timedwait(&dsema
->dsema_sem
, &_timeout
));
589 } while (ret
== -1 && errno
== EINTR
);
591 if (!(ret
== -1 && errno
== ETIMEDOUT
)) {
592 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
596 nsec
= _dispatch_timeout(timeout
);
597 msec
= (DWORD
)(nsec
/ (uint64_t)1000000);
598 resolution
= _push_timer_resolution(msec
);
599 wait_result
= WaitForSingleObject(dsema
->dsema_handle
, msec
);
600 _pop_timer_resolution(resolution
);
601 if (wait_result
!= WAIT_TIMEOUT
) {
605 // Fall through and try to undo the earlier change to
606 // dsema->dsema_group_waiters
607 case DISPATCH_TIME_NOW
:
608 orig
= dsema
->dsema_group_waiters
;
610 if (dispatch_atomic_cmpxchgvw2o(dsema
, dsema_group_waiters
, orig
,
611 orig
- 1, &orig
, relaxed
)) {
613 return KERN_OPERATION_TIMED_OUT
;
614 #elif USE_POSIX_SEM || USE_WIN32_SEM
620 // Another thread called semaphore_signal().
621 // Fall through and drain the wakeup.
622 case DISPATCH_TIME_FOREVER
:
625 kr
= semaphore_wait(dsema
->dsema_port
);
626 } while (kr
== KERN_ABORTED
);
627 DISPATCH_GROUP_VERIFY_KR(kr
);
630 ret
= sem_wait(&dsema
->dsema_sem
);
631 } while (ret
== -1 && errno
== EINTR
);
632 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
634 WaitForSingleObject(dsema
->dsema_handle
, INFINITE
);
642 dispatch_group_wait(dispatch_group_t dg
, dispatch_time_t timeout
)
644 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)dg
;
646 if (dsema
->dsema_value
== LONG_MAX
) {
651 return KERN_OPERATION_TIMED_OUT
;
652 #elif USE_POSIX_SEM || USE_WIN32_SEM
657 return _dispatch_group_wait_slow(dsema
, timeout
);
662 dispatch_group_notify_f(dispatch_group_t dg
, dispatch_queue_t dq
, void *ctxt
,
663 void (*func
)(void *))
665 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)dg
;
666 dispatch_continuation_t prev
, dsn
= _dispatch_continuation_alloc();
667 dsn
->do_vtable
= (void *)DISPATCH_OBJ_ASYNC_BIT
;
672 _dispatch_retain(dq
);
673 prev
= dispatch_atomic_xchg2o(dsema
, dsema_notify_tail
, dsn
, release
);
674 if (fastpath(prev
)) {
677 _dispatch_retain(dg
);
678 dispatch_atomic_store2o(dsema
, dsema_notify_head
, dsn
, seq_cst
);
679 // seq_cst with atomic store to notify_head <rdar://problem/11750916>
680 if (dispatch_atomic_load2o(dsema
, dsema_value
, seq_cst
) == LONG_MAX
) {
681 _dispatch_group_wake(dsema
);
688 dispatch_group_notify(dispatch_group_t dg
, dispatch_queue_t dq
,
691 dispatch_group_notify_f(dg
, dq
, _dispatch_Block_copy(db
),
692 _dispatch_call_block_and_release
);
697 #pragma mark _dispatch_thread_semaphore_t
699 _dispatch_thread_semaphore_t
700 _dispatch_thread_semaphore_create(void)
702 _dispatch_safe_fork
= false;
703 #if DISPATCH_USE_OS_SEMAPHORE_CACHE
704 return _os_semaphore_create();
708 while (slowpath(kr
= semaphore_create(mach_task_self(), &s4
,
709 SYNC_POLICY_FIFO
, 0))) {
710 DISPATCH_VERIFY_MIG(kr
);
711 _dispatch_temporary_resource_shortage();
716 int ret
= sem_init(&s4
, 0, 0);
717 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
721 while (!dispatch_assume(tmp
= CreateSemaphore(NULL
, 0, LONG_MAX
, NULL
))) {
722 _dispatch_temporary_resource_shortage();
724 return (_dispatch_thread_semaphore_t
)tmp
;
726 #error "No supported semaphore type"
731 _dispatch_thread_semaphore_dispose(_dispatch_thread_semaphore_t sema
)
733 #if DISPATCH_USE_OS_SEMAPHORE_CACHE
734 return _os_semaphore_dispose(sema
);
736 semaphore_t s4
= (semaphore_t
)sema
;
737 kern_return_t kr
= semaphore_destroy(mach_task_self(), s4
);
738 DISPATCH_VERIFY_MIG(kr
);
739 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
741 sem_t s4
= (sem_t
)sema
;
742 int ret
= sem_destroy(&s4
);
743 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
745 // XXX: signal the semaphore?
747 success
= CloseHandle((HANDLE
)sema
);
748 dispatch_assume(success
);
750 #error "No supported semaphore type"
755 _dispatch_thread_semaphore_signal(_dispatch_thread_semaphore_t sema
)
757 // assumed to contain a release barrier
758 #if DISPATCH_USE_OS_SEMAPHORE_CACHE
759 return _os_semaphore_signal(sema
);
761 semaphore_t s4
= (semaphore_t
)sema
;
762 kern_return_t kr
= semaphore_signal(s4
);
763 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
765 sem_t s4
= (sem_t
)sema
;
766 int ret
= sem_post(&s4
);
767 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
770 ret
= ReleaseSemaphore((HANDLE
)sema
, 1, NULL
);
771 dispatch_assume(ret
);
773 #error "No supported semaphore type"
778 _dispatch_thread_semaphore_wait(_dispatch_thread_semaphore_t sema
)
780 // assumed to contain an acquire barrier
781 #if DISPATCH_USE_OS_SEMAPHORE_CACHE
782 return _os_semaphore_wait(sema
);
784 semaphore_t s4
= (semaphore_t
)sema
;
787 kr
= semaphore_wait(s4
);
788 } while (slowpath(kr
== KERN_ABORTED
));
789 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
791 sem_t s4
= (sem_t
)sema
;
795 } while (slowpath(ret
!= 0));
796 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
800 wait_result
= WaitForSingleObject((HANDLE
)sema
, INFINITE
);
801 } while (wait_result
!= WAIT_OBJECT_0
);
803 #error "No supported semaphore type"