]> git.saurik.com Git - apple/libpthread.git/blob - src/pthread_dependency.c
libpthread-454.100.8.tar.gz
[apple/libpthread.git] / src / pthread_dependency.c
1 /*
2 * Copyright (c) 2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "resolver.h"
25 #include "internal.h"
26
27 #define PREREQUISITE_FULFILLED (~0u)
28
29 #if !VARIANT_DYLD
30 void
31 pthread_dependency_init_np(pthread_dependency_t *pr, pthread_t pth,
32 pthread_dependency_attr_t *attrs)
33 {
34 if (attrs) *(volatile char *)attrs;
35 *pr = (pthread_dependency_t)PTHREAD_DEPENDENCY_INITIALIZER_NP(pth);
36 }
37
38 OS_NOINLINE
39 void
40 _pthread_dependency_fulfill_slow(pthread_dependency_t *pr, uint32_t old)
41 {
42 if (old == PREREQUISITE_FULFILLED) {
43 PTHREAD_CLIENT_CRASH(0, "Fufilling pthread_dependency_t twice");
44 }
45 if (os_unlikely(old != _pthread_mach_thread_self_direct())) {
46 PTHREAD_CLIENT_CRASH(old, "Fulfilled a dependency "
47 "not owned by current thread");
48 }
49
50 int ret = __ulock_wake(UL_UNFAIR_LOCK | ULF_NO_ERRNO, &pr->__pdep_opaque1, 0);
51 switch (-ret) {
52 case 0:
53 case ENOENT:
54 return;
55 default:
56 PTHREAD_INTERNAL_CRASH(-ret, "__ulock_wake() failed");
57 }
58 }
59
60
61 PTHREAD_NOEXPORT_VARIANT
62 void
63 pthread_dependency_fulfill_np(pthread_dependency_t *pr, void *value)
64 {
65 uint32_t old;
66
67 pr->__pdep_opaque2 = (uint64_t)(uintptr_t)value;
68 old = os_atomic_xchg(&pr->__pdep_opaque1, PREREQUISITE_FULFILLED, release);
69
70 if (old != 0) _pthread_dependency_fulfill_slow(pr, old);
71 }
72
73 PTHREAD_NOEXPORT_VARIANT
74 void *
75 pthread_dependency_wait_np(pthread_dependency_t *pr)
76 {
77 if (os_atomic_cmpxchg(&pr->__pdep_opaque1, 0, pr->__pdep_owner, relaxed)) {
78 int ret;
79 again:
80 ret = __ulock_wait(UL_UNFAIR_LOCK | ULF_NO_ERRNO, &pr->__pdep_opaque1,
81 pr->__pdep_owner, 0);
82 switch (-ret) {
83 case EFAULT:
84 case EINTR:
85 case 0:
86 if (pr->__pdep_opaque1 == pr->__pdep_owner) goto again;
87 break;
88 case EOWNERDEAD:
89 PTHREAD_CLIENT_CRASH(pr->__pdep_owner, "Waiting on orphaned dependency");
90 default:
91 PTHREAD_CLIENT_CRASH(-ret, "__ulock_wait() failed");
92 }
93 }
94
95 uint32_t cur = os_atomic_load(&pr->__pdep_opaque1, acquire);
96 if (cur == PREREQUISITE_FULFILLED) {
97 return (void *)(uintptr_t)pr->__pdep_opaque2;
98 }
99 PTHREAD_CLIENT_CRASH(cur, "Corrupted pthread_dependency_t");
100 }
101
102 PTHREAD_NOEXPORT_VARIANT void*
103 _pthread_atomic_xchg_ptr(void **p, void *v)
104 {
105 return os_atomic_xchg(p, v, seq_cst);
106 }
107
108 PTHREAD_NOEXPORT_VARIANT uint32_t
109 _pthread_atomic_xchg_uint32_relaxed(uint32_t *p, uint32_t v)
110 {
111 return os_atomic_xchg(p, v, relaxed);
112 }
113
114 #endif // !VARIANT_DYLD