]>
Commit | Line | Data |
---|---|---|
214d78a2 A |
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" | |
214d78a2 A |
26 | |
27 | #define PREREQUISITE_FULFILLED (~0u) | |
28 | ||
c1f56ec9 | 29 | #if !VARIANT_DYLD |
214d78a2 A |
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 | } | |
c1f56ec9 | 45 | if (os_unlikely(old != _pthread_mach_thread_self_direct())) { |
214d78a2 A |
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 | ||
c1f56ec9 | 61 | PTHREAD_NOEXPORT_VARIANT |
214d78a2 A |
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 | ||
c1f56ec9 | 73 | PTHREAD_NOEXPORT_VARIANT |
214d78a2 A |
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: | |
c6e5f90c | 84 | case EINTR: |
214d78a2 | 85 | case 0: |
c6e5f90c | 86 | if (pr->__pdep_opaque1 == pr->__pdep_owner) goto again; |
214d78a2 A |
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 | ||
c1f56ec9 A |
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 |