2 * Copyright (c) 2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 #include "dependency_private.h"
27 #include <sys/ulock.h>
29 #define PREREQUISITE_FULFILLED (~0u)
32 void _pthread_dependency_fulfill_slow(pthread_dependency_t
*pr
, uint32_t old
);
35 static inline mach_port_t
36 _pthread_dependency_self(void)
38 void *v
= _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF
);
39 return (mach_port_t
)(uintptr_t)v
;
43 pthread_dependency_init_np(pthread_dependency_t
*pr
, pthread_t pth
,
44 pthread_dependency_attr_t
*attrs
)
46 if (attrs
) *(volatile char *)attrs
;
47 *pr
= (pthread_dependency_t
)PTHREAD_DEPENDENCY_INITIALIZER_NP(pth
);
52 _pthread_dependency_fulfill_slow(pthread_dependency_t
*pr
, uint32_t old
)
54 if (old
== PREREQUISITE_FULFILLED
) {
55 PTHREAD_CLIENT_CRASH(0, "Fufilling pthread_dependency_t twice");
57 if (os_unlikely(old
!= _pthread_dependency_self())) {
58 PTHREAD_CLIENT_CRASH(old
, "Fulfilled a dependency "
59 "not owned by current thread");
62 int ret
= __ulock_wake(UL_UNFAIR_LOCK
| ULF_NO_ERRNO
, &pr
->__pdep_opaque1
, 0);
68 PTHREAD_INTERNAL_CRASH(-ret
, "__ulock_wake() failed");
74 pthread_dependency_fulfill_np(pthread_dependency_t
*pr
, void *value
)
78 pr
->__pdep_opaque2
= (uint64_t)(uintptr_t)value
;
79 old
= os_atomic_xchg(&pr
->__pdep_opaque1
, PREREQUISITE_FULFILLED
, release
);
81 if (old
!= 0) _pthread_dependency_fulfill_slow(pr
, old
);
85 pthread_dependency_wait_np(pthread_dependency_t
*pr
)
87 if (os_atomic_cmpxchg(&pr
->__pdep_opaque1
, 0, pr
->__pdep_owner
, relaxed
)) {
90 ret
= __ulock_wait(UL_UNFAIR_LOCK
| ULF_NO_ERRNO
, &pr
->__pdep_opaque1
,
96 if (pr
->__pdep_opaque1
== pr
->__pdep_owner
) goto again
;
99 PTHREAD_CLIENT_CRASH(pr
->__pdep_owner
, "Waiting on orphaned dependency");
101 PTHREAD_CLIENT_CRASH(-ret
, "__ulock_wait() failed");
105 uint32_t cur
= os_atomic_load(&pr
->__pdep_opaque1
, acquire
);
106 if (cur
== PREREQUISITE_FULFILLED
) {
107 return (void *)(uintptr_t)pr
->__pdep_opaque2
;
109 PTHREAD_CLIENT_CRASH(cur
, "Corrupted pthread_dependency_t");