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
);
97 #pragma mark dispatch_semaphore_t
100 _dispatch_semaphore_init(long value
, dispatch_object_t dou
)
102 dispatch_semaphore_t dsema
= dou
._dsema
;
104 dsema
->do_next
= (dispatch_semaphore_t
)DISPATCH_OBJECT_LISTLESS
;
105 dsema
->do_targetq
= _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT
,
107 dsema
->dsema_value
= value
;
108 dsema
->dsema_orig
= value
;
110 int ret
= sem_init(&dsema
->dsema_sem
, 0, 0);
111 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
116 dispatch_semaphore_create(long value
)
118 dispatch_semaphore_t dsema
;
120 // If the internal value is negative, then the absolute of the value is
121 // equal to the number of waiting threads. Therefore it is bogus to
122 // initialize the semaphore with a negative value.
127 dsema
= (dispatch_semaphore_t
)_dispatch_alloc(DISPATCH_VTABLE(semaphore
),
128 sizeof(struct dispatch_semaphore_s
) -
129 sizeof(dsema
->dsema_notify_head
) -
130 sizeof(dsema
->dsema_notify_tail
));
131 _dispatch_semaphore_init(value
, dsema
);
137 _dispatch_semaphore_create_port(semaphore_t
*s4
)
145 _dispatch_safe_fork
= false;
147 // lazily allocate the semaphore port
150 // 1) Switch to a doubly-linked FIFO in user-space.
151 // 2) User-space timers for the timeout.
152 // 3) Use the per-thread semaphore port.
154 while ((kr
= semaphore_create(mach_task_self(), &tmp
,
155 SYNC_POLICY_FIFO
, 0))) {
156 DISPATCH_VERIFY_MIG(kr
);
157 _dispatch_temporary_resource_shortage();
160 if (!dispatch_atomic_cmpxchg(s4
, 0, tmp
, relaxed
)) {
161 kr
= semaphore_destroy(mach_task_self(), tmp
);
162 DISPATCH_VERIFY_MIG(kr
);
163 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
168 _dispatch_semaphore_create_handle(HANDLE
*s4
)
176 // lazily allocate the semaphore port
178 while (!dispatch_assume(tmp
= CreateSemaphore(NULL
, 0, LONG_MAX
, NULL
))) {
179 _dispatch_temporary_resource_shortage();
182 if (!dispatch_atomic_cmpxchg(s4
, 0, tmp
)) {
189 _dispatch_semaphore_dispose(dispatch_object_t dou
)
191 dispatch_semaphore_t dsema
= dou
._dsema
;
193 if (dsema
->dsema_value
< dsema
->dsema_orig
) {
194 DISPATCH_CLIENT_CRASH(
195 "Semaphore/group object deallocated while in use");
200 if (dsema
->dsema_port
) {
201 kr
= semaphore_destroy(mach_task_self(), dsema
->dsema_port
);
202 DISPATCH_VERIFY_MIG(kr
);
203 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
205 dsema
->dsema_port
= MACH_PORT_DEAD
;
207 int ret
= sem_destroy(&dsema
->dsema_sem
);
208 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
210 if (dsema
->dsema_handle
) {
211 CloseHandle(dsema
->dsema_handle
);
217 _dispatch_semaphore_debug(dispatch_object_t dou
, char *buf
, size_t bufsiz
)
219 dispatch_semaphore_t dsema
= dou
._dsema
;
222 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
, "%s[%p] = { ",
223 dx_kind(dsema
), dsema
);
224 offset
+= _dispatch_object_debug_attr(dsema
, &buf
[offset
], bufsiz
- offset
);
226 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
, "port = 0x%u, ",
229 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
,
230 "value = %ld, orig = %ld }", dsema
->dsema_value
, dsema
->dsema_orig
);
236 _dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema
)
238 // Before dsema_sent_ksignals is incremented we can rely on the reference
239 // held by the waiter. However, once this value is incremented the waiter
240 // may return between the atomic increment and the semaphore_signal(),
241 // therefore an explicit reference must be held in order to safely access
242 // dsema after the atomic increment.
243 _dispatch_retain(dsema
);
245 #if USE_MACH_SEM || USE_POSIX_SEM
246 (void)dispatch_atomic_inc2o(dsema
, dsema_sent_ksignals
, relaxed
);
250 _dispatch_semaphore_create_port(&dsema
->dsema_port
);
251 kern_return_t kr
= semaphore_signal(dsema
->dsema_port
);
252 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
254 int ret
= sem_post(&dsema
->dsema_sem
);
255 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
257 _dispatch_semaphore_create_handle(&dsema
->dsema_handle
);
258 int ret
= ReleaseSemaphore(dsema
->dsema_handle
, 1, NULL
);
259 dispatch_assume(ret
);
262 _dispatch_release(dsema
);
267 dispatch_semaphore_signal(dispatch_semaphore_t dsema
)
269 long value
= dispatch_atomic_inc2o(dsema
, dsema_value
, release
);
270 if (fastpath(value
> 0)) {
273 if (slowpath(value
== LONG_MIN
)) {
274 DISPATCH_CLIENT_CRASH("Unbalanced call to dispatch_semaphore_signal()");
276 return _dispatch_semaphore_signal_slow(dsema
);
281 _dispatch_semaphore_wait_slow(dispatch_semaphore_t dsema
,
282 dispatch_time_t timeout
)
287 mach_timespec_t _timeout
;
290 struct timespec _timeout
;
299 #if USE_MACH_SEM || USE_POSIX_SEM
301 // Mach semaphores appear to sometimes spuriously wake up. Therefore,
302 // we keep a parallel count of the number of times a Mach semaphore is
303 // signaled (6880961).
304 orig
= dsema
->dsema_sent_ksignals
;
306 if (dispatch_atomic_cmpxchgvw2o(dsema
, dsema_sent_ksignals
, orig
,
307 orig
- 1, &orig
, relaxed
)) {
314 _dispatch_semaphore_create_port(&dsema
->dsema_port
);
316 _dispatch_semaphore_create_handle(&dsema
->dsema_handle
);
319 // From xnu/osfmk/kern/sync_sema.c:
320 // wait_semaphore->count = -1; /* we don't keep an actual count */
322 // The code above does not match the documentation, and that fact is
323 // not surprising. The documented semantics are clumsy to use in any
324 // practical way. The above hack effectively tricks the rest of the
325 // Mach semaphore logic to behave like the libdispatch algorithm.
331 uint64_t nsec
= _dispatch_timeout(timeout
);
332 _timeout
.tv_sec
= (typeof(_timeout
.tv_sec
))(nsec
/ NSEC_PER_SEC
);
333 _timeout
.tv_nsec
= (typeof(_timeout
.tv_nsec
))(nsec
% NSEC_PER_SEC
);
334 kr
= slowpath(semaphore_timedwait(dsema
->dsema_port
, _timeout
));
335 } while (kr
== KERN_ABORTED
);
337 if (kr
!= KERN_OPERATION_TIMED_OUT
) {
338 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
343 uint64_t nsec
= _dispatch_timeout(timeout
);
344 _timeout
.tv_sec
= (typeof(_timeout
.tv_sec
))(nsec
/ NSEC_PER_SEC
);
345 _timeout
.tv_nsec
= (typeof(_timeout
.tv_nsec
))(nsec
% NSEC_PER_SEC
);
346 ret
= slowpath(sem_timedwait(&dsema
->dsema_sem
, &_timeout
));
347 } while (ret
== -1 && errno
== EINTR
);
349 if (ret
== -1 && errno
!= ETIMEDOUT
) {
350 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
354 nsec
= _dispatch_timeout(timeout
);
355 msec
= (DWORD
)(nsec
/ (uint64_t)1000000);
356 resolution
= _push_timer_resolution(msec
);
357 wait_result
= WaitForSingleObject(dsema
->dsema_handle
, msec
);
358 _pop_timer_resolution(resolution
);
359 if (wait_result
!= WAIT_TIMEOUT
) {
363 // Fall through and try to undo what the fast path did to
364 // dsema->dsema_value
365 case DISPATCH_TIME_NOW
:
366 orig
= dsema
->dsema_value
;
368 if (dispatch_atomic_cmpxchgvw2o(dsema
, dsema_value
, orig
, orig
+ 1,
371 return KERN_OPERATION_TIMED_OUT
;
372 #elif USE_POSIX_SEM || USE_WIN32_SEM
378 // Another thread called semaphore_signal().
379 // Fall through and drain the wakeup.
380 case DISPATCH_TIME_FOREVER
:
383 kr
= semaphore_wait(dsema
->dsema_port
);
384 } while (kr
== KERN_ABORTED
);
385 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
388 ret
= sem_wait(&dsema
->dsema_sem
);
390 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
392 WaitForSingleObject(dsema
->dsema_handle
, INFINITE
);
396 #if USE_MACH_SEM || USE_POSIX_SEM
404 dispatch_semaphore_wait(dispatch_semaphore_t dsema
, dispatch_time_t timeout
)
406 long value
= dispatch_atomic_dec2o(dsema
, dsema_value
, acquire
);
407 if (fastpath(value
>= 0)) {
410 return _dispatch_semaphore_wait_slow(dsema
, timeout
);
414 #pragma mark dispatch_group_t
416 DISPATCH_ALWAYS_INLINE
417 static inline dispatch_group_t
418 _dispatch_group_create_with_count(long count
)
420 dispatch_group_t dg
= (dispatch_group_t
)_dispatch_alloc(
421 DISPATCH_VTABLE(group
), sizeof(struct dispatch_semaphore_s
));
422 _dispatch_semaphore_init(LONG_MAX
- count
, dg
);
424 dispatch_atomic_store2o((dispatch_semaphore_t
)dg
, do_ref_cnt
, 1,
425 relaxed
); // <rdar://problem/22318411>
431 dispatch_group_create(void)
433 return _dispatch_group_create_with_count(0);
437 _dispatch_group_create_and_enter(void)
439 return _dispatch_group_create_with_count(1);
443 dispatch_group_enter(dispatch_group_t dg
)
445 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)dg
;
446 long value
= dispatch_atomic_dec_orig2o(dsema
, dsema_value
, acquire
);
447 if (value
== LONG_MAX
) {
448 return _dispatch_retain(dg
); // <rdar://problem/22318411>
450 if (slowpath(value
<= 0)) {
451 DISPATCH_CLIENT_CRASH(
452 "Too many nested calls to dispatch_group_enter()");
458 _dispatch_group_wake(dispatch_semaphore_t dsema
, bool needs_release
)
460 dispatch_continuation_t next
, head
, tail
= NULL
, dc
;
463 head
= dispatch_atomic_xchg2o(dsema
, dsema_notify_head
, NULL
, relaxed
);
465 // snapshot before anything is notified/woken <rdar://problem/8554546>
466 tail
= dispatch_atomic_xchg2o(dsema
, dsema_notify_tail
, NULL
, relaxed
);
468 rval
= (long)dispatch_atomic_xchg2o(dsema
, dsema_group_waiters
, 0, relaxed
);
470 // wake group waiters
472 _dispatch_semaphore_create_port(&dsema
->dsema_port
);
474 kern_return_t kr
= semaphore_signal(dsema
->dsema_port
);
475 DISPATCH_GROUP_VERIFY_KR(kr
);
479 int ret
= sem_post(&dsema
->dsema_sem
);
480 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
483 _dispatch_semaphore_create_handle(&dsema
->dsema_handle
);
485 ret
= ReleaseSemaphore(dsema
->dsema_handle
, rval
, NULL
);
486 dispatch_assume(ret
);
488 #error "No supported semaphore type"
492 // async group notify blocks
494 next
= fastpath(head
->do_next
);
495 if (!next
&& head
!= tail
) {
496 _dispatch_wait_until(next
= fastpath(head
->do_next
));
498 dispatch_queue_t dsn_queue
= (dispatch_queue_t
)head
->dc_data
;
499 dc
= _dispatch_continuation_free_cacheonly(head
);
500 dispatch_async_f(dsn_queue
, head
->dc_ctxt
, head
->dc_func
);
501 _dispatch_release(dsn_queue
);
503 _dispatch_continuation_free_to_cache_limit(dc
);
505 } while ((head
= next
));
506 _dispatch_release(dsema
);
509 _dispatch_release(dsema
); // <rdar://problem/22318411>
515 dispatch_group_leave(dispatch_group_t dg
)
517 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)dg
;
518 long value
= dispatch_atomic_inc2o(dsema
, dsema_value
, release
);
519 if (slowpath(value
< 0)) {
520 DISPATCH_CLIENT_CRASH("Unbalanced call to dispatch_group_leave()");
522 if (slowpath(value
== LONG_MAX
)) {
523 return (void)_dispatch_group_wake(dsema
, true);
529 _dispatch_group_wait_slow(dispatch_semaphore_t dsema
, dispatch_time_t timeout
)
534 mach_timespec_t _timeout
;
536 #elif USE_POSIX_SEM // KVV
537 struct timespec _timeout
;
539 #elif USE_WIN32_SEM // KVV
547 // check before we cause another signal to be sent by incrementing
548 // dsema->dsema_group_waiters
549 value
= dispatch_atomic_load2o(dsema
, dsema_value
, seq_cst
); // 19296565
550 if (value
== LONG_MAX
) {
551 return _dispatch_group_wake(dsema
, false);
553 // Mach semaphores appear to sometimes spuriously wake up. Therefore,
554 // we keep a parallel count of the number of times a Mach semaphore is
555 // signaled (6880961).
556 (void)dispatch_atomic_inc2o(dsema
, dsema_group_waiters
, relaxed
);
557 // check the values again in case we need to wake any threads
558 value
= dispatch_atomic_load2o(dsema
, dsema_value
, seq_cst
); // 19296565
559 if (value
== LONG_MAX
) {
560 return _dispatch_group_wake(dsema
, false);
564 _dispatch_semaphore_create_port(&dsema
->dsema_port
);
566 _dispatch_semaphore_create_handle(&dsema
->dsema_handle
);
569 // From xnu/osfmk/kern/sync_sema.c:
570 // wait_semaphore->count = -1; /* we don't keep an actual count */
572 // The code above does not match the documentation, and that fact is
573 // not surprising. The documented semantics are clumsy to use in any
574 // practical way. The above hack effectively tricks the rest of the
575 // Mach semaphore logic to behave like the libdispatch algorithm.
581 uint64_t nsec
= _dispatch_timeout(timeout
);
582 _timeout
.tv_sec
= (typeof(_timeout
.tv_sec
))(nsec
/ NSEC_PER_SEC
);
583 _timeout
.tv_nsec
= (typeof(_timeout
.tv_nsec
))(nsec
% NSEC_PER_SEC
);
584 kr
= slowpath(semaphore_timedwait(dsema
->dsema_port
, _timeout
));
585 } while (kr
== KERN_ABORTED
);
587 if (kr
!= KERN_OPERATION_TIMED_OUT
) {
588 DISPATCH_GROUP_VERIFY_KR(kr
);
593 uint64_t nsec
= _dispatch_timeout(timeout
);
594 _timeout
.tv_sec
= (typeof(_timeout
.tv_sec
))(nsec
/ NSEC_PER_SEC
);
595 _timeout
.tv_nsec
= (typeof(_timeout
.tv_nsec
))(nsec
% NSEC_PER_SEC
);
596 ret
= slowpath(sem_timedwait(&dsema
->dsema_sem
, &_timeout
));
597 } while (ret
== -1 && errno
== EINTR
);
599 if (!(ret
== -1 && errno
== ETIMEDOUT
)) {
600 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
604 nsec
= _dispatch_timeout(timeout
);
605 msec
= (DWORD
)(nsec
/ (uint64_t)1000000);
606 resolution
= _push_timer_resolution(msec
);
607 wait_result
= WaitForSingleObject(dsema
->dsema_handle
, msec
);
608 _pop_timer_resolution(resolution
);
609 if (wait_result
!= WAIT_TIMEOUT
) {
613 // Fall through and try to undo the earlier change to
614 // dsema->dsema_group_waiters
615 case DISPATCH_TIME_NOW
:
616 orig
= dsema
->dsema_group_waiters
;
618 if (dispatch_atomic_cmpxchgvw2o(dsema
, dsema_group_waiters
, orig
,
619 orig
- 1, &orig
, relaxed
)) {
621 return KERN_OPERATION_TIMED_OUT
;
622 #elif USE_POSIX_SEM || USE_WIN32_SEM
628 // Another thread called semaphore_signal().
629 // Fall through and drain the wakeup.
630 case DISPATCH_TIME_FOREVER
:
633 kr
= semaphore_wait(dsema
->dsema_port
);
634 } while (kr
== KERN_ABORTED
);
635 DISPATCH_GROUP_VERIFY_KR(kr
);
638 ret
= sem_wait(&dsema
->dsema_sem
);
639 } while (ret
== -1 && errno
== EINTR
);
640 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
642 WaitForSingleObject(dsema
->dsema_handle
, INFINITE
);
650 dispatch_group_wait(dispatch_group_t dg
, dispatch_time_t timeout
)
652 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)dg
;
654 if (dsema
->dsema_value
== LONG_MAX
) {
659 return KERN_OPERATION_TIMED_OUT
;
660 #elif USE_POSIX_SEM || USE_WIN32_SEM
665 return _dispatch_group_wait_slow(dsema
, timeout
);
670 dispatch_group_notify_f(dispatch_group_t dg
, dispatch_queue_t dq
, void *ctxt
,
671 void (*func
)(void *))
673 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)dg
;
674 dispatch_continuation_t prev
, dsn
= _dispatch_continuation_alloc();
675 dsn
->do_vtable
= (void *)DISPATCH_OBJ_ASYNC_BIT
;
680 _dispatch_retain(dq
);
681 prev
= dispatch_atomic_xchg2o(dsema
, dsema_notify_tail
, dsn
, release
);
682 if (fastpath(prev
)) {
685 _dispatch_retain(dg
);
686 dispatch_atomic_store2o(dsema
, dsema_notify_head
, dsn
, seq_cst
);
687 // seq_cst with atomic store to notify_head <rdar://problem/11750916>
688 if (dispatch_atomic_load2o(dsema
, dsema_value
, seq_cst
) == LONG_MAX
) {
689 _dispatch_group_wake(dsema
, false);
696 dispatch_group_notify(dispatch_group_t dg
, dispatch_queue_t dq
,
699 dispatch_group_notify_f(dg
, dq
, _dispatch_Block_copy(db
),
700 _dispatch_call_block_and_release
);
705 #pragma mark _dispatch_thread_semaphore_t
707 _dispatch_thread_semaphore_t
708 _dispatch_thread_semaphore_create(void)
710 _dispatch_safe_fork
= false;
711 #if DISPATCH_USE_OS_SEMAPHORE_CACHE
712 return _os_semaphore_create();
716 while (slowpath(kr
= semaphore_create(mach_task_self(), &s4
,
717 SYNC_POLICY_FIFO
, 0))) {
718 DISPATCH_VERIFY_MIG(kr
);
719 _dispatch_temporary_resource_shortage();
724 int ret
= sem_init(&s4
, 0, 0);
725 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
729 while (!dispatch_assume(tmp
= CreateSemaphore(NULL
, 0, LONG_MAX
, NULL
))) {
730 _dispatch_temporary_resource_shortage();
732 return (_dispatch_thread_semaphore_t
)tmp
;
734 #error "No supported semaphore type"
739 _dispatch_thread_semaphore_dispose(_dispatch_thread_semaphore_t sema
)
741 #if DISPATCH_USE_OS_SEMAPHORE_CACHE
742 return _os_semaphore_dispose(sema
);
744 semaphore_t s4
= (semaphore_t
)sema
;
745 kern_return_t kr
= semaphore_destroy(mach_task_self(), s4
);
746 DISPATCH_VERIFY_MIG(kr
);
747 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
749 sem_t s4
= (sem_t
)sema
;
750 int ret
= sem_destroy(&s4
);
751 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
753 // XXX: signal the semaphore?
755 success
= CloseHandle((HANDLE
)sema
);
756 dispatch_assume(success
);
758 #error "No supported semaphore type"
763 _dispatch_thread_semaphore_signal(_dispatch_thread_semaphore_t sema
)
765 // assumed to contain a release barrier
766 #if DISPATCH_USE_OS_SEMAPHORE_CACHE
767 return _os_semaphore_signal(sema
);
769 semaphore_t s4
= (semaphore_t
)sema
;
770 kern_return_t kr
= semaphore_signal(s4
);
771 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
773 sem_t s4
= (sem_t
)sema
;
774 int ret
= sem_post(&s4
);
775 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
778 ret
= ReleaseSemaphore((HANDLE
)sema
, 1, NULL
);
779 dispatch_assume(ret
);
781 #error "No supported semaphore type"
786 _dispatch_thread_semaphore_wait(_dispatch_thread_semaphore_t sema
)
788 // assumed to contain an acquire barrier
789 #if DISPATCH_USE_OS_SEMAPHORE_CACHE
790 return _os_semaphore_wait(sema
);
792 semaphore_t s4
= (semaphore_t
)sema
;
795 kr
= semaphore_wait(s4
);
796 } while (slowpath(kr
== KERN_ABORTED
));
797 DISPATCH_SEMAPHORE_VERIFY_KR(kr
);
799 sem_t s4
= (sem_t
)sema
;
803 } while (slowpath(ret
!= 0));
804 DISPATCH_SEMAPHORE_VERIFY_RET(ret
);
808 wait_result
= WaitForSingleObject((HANDLE
)sema
, INFINITE
);
809 } while (wait_result
!= WAIT_OBJECT_0
);
811 #error "No supported semaphore type"