]> git.saurik.com Git - apple/libpthread.git/blob - src/pthread_dependency.c
3836f15988500b679fa81b512c880384cc233d59
[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 #include "dependency_private.h"
27 #include <sys/ulock.h>
28
29 #define PREREQUISITE_FULFILLED (~0u)
30
31 PTHREAD_NOEXPORT
32 void _pthread_dependency_fulfill_slow(pthread_dependency_t *pr, uint32_t old);
33
34 OS_ALWAYS_INLINE
35 static inline mach_port_t
36 _pthread_dependency_self(void)
37 {
38 void *v = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF);
39 return (mach_port_t)(uintptr_t)v;
40 }
41
42 void
43 pthread_dependency_init_np(pthread_dependency_t *pr, pthread_t pth,
44 pthread_dependency_attr_t *attrs)
45 {
46 if (attrs) *(volatile char *)attrs;
47 *pr = (pthread_dependency_t)PTHREAD_DEPENDENCY_INITIALIZER_NP(pth);
48 }
49
50 OS_NOINLINE
51 void
52 _pthread_dependency_fulfill_slow(pthread_dependency_t *pr, uint32_t old)
53 {
54 if (old == PREREQUISITE_FULFILLED) {
55 PTHREAD_CLIENT_CRASH(0, "Fufilling pthread_dependency_t twice");
56 }
57 if (os_unlikely(old != _pthread_dependency_self())) {
58 PTHREAD_CLIENT_CRASH(old, "Fulfilled a dependency "
59 "not owned by current thread");
60 }
61
62 int ret = __ulock_wake(UL_UNFAIR_LOCK | ULF_NO_ERRNO, &pr->__pdep_opaque1, 0);
63 switch (-ret) {
64 case 0:
65 case ENOENT:
66 return;
67 default:
68 PTHREAD_INTERNAL_CRASH(-ret, "__ulock_wake() failed");
69 }
70 }
71
72
73 void
74 pthread_dependency_fulfill_np(pthread_dependency_t *pr, void *value)
75 {
76 uint32_t old;
77
78 pr->__pdep_opaque2 = (uint64_t)(uintptr_t)value;
79 old = os_atomic_xchg(&pr->__pdep_opaque1, PREREQUISITE_FULFILLED, release);
80
81 if (old != 0) _pthread_dependency_fulfill_slow(pr, old);
82 }
83
84 void *
85 pthread_dependency_wait_np(pthread_dependency_t *pr)
86 {
87 if (os_atomic_cmpxchg(&pr->__pdep_opaque1, 0, pr->__pdep_owner, relaxed)) {
88 int ret;
89 again:
90 ret = __ulock_wait(UL_UNFAIR_LOCK | ULF_NO_ERRNO, &pr->__pdep_opaque1,
91 pr->__pdep_owner, 0);
92 switch (-ret) {
93 case EFAULT:
94 case EINTR:
95 case 0:
96 if (pr->__pdep_opaque1 == pr->__pdep_owner) goto again;
97 break;
98 case EOWNERDEAD:
99 PTHREAD_CLIENT_CRASH(pr->__pdep_owner, "Waiting on orphaned dependency");
100 default:
101 PTHREAD_CLIENT_CRASH(-ret, "__ulock_wait() failed");
102 }
103 }
104
105 uint32_t cur = os_atomic_load(&pr->__pdep_opaque1, acquire);
106 if (cur == PREREQUISITE_FULFILLED) {
107 return (void *)(uintptr_t)pr->__pdep_opaque2;
108 }
109 PTHREAD_CLIENT_CRASH(cur, "Corrupted pthread_dependency_t");
110 }
111