2 * Copyright (c) 2019 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@
24 #ifndef __LIBPTHREAD_INLINE_INTERNAL_H__
25 #define __LIBPTHREAD_INLINE_INTERNAL_H__
28 * @file inline_internal.h
31 * This file exposes inline helpers that are generally useful in libpthread.
34 #define PTHREAD_INTERNAL_CRASH(c, x) OS_BUG_INTERNAL(c, "LIBPTHREAD", x)
35 #define PTHREAD_CLIENT_CRASH(c, x) OS_BUG_CLIENT(c, "LIBPTHREAD", x)
37 #define PTHREAD_DEBUG_ASSERT(b) \
39 if (os_unlikely(!(b))) { \
40 PTHREAD_INTERNAL_CRASH(0, "Assertion failed: " #b); \
44 #define PTHREAD_DEBUG_ASSERT(b) ((void)0)
47 #pragma mark _pthread_mutex_check_signature
51 _pthread_mutex_check_signature_fast(pthread_mutex_t
*mutex
)
53 return (mutex
->sig
== _PTHREAD_MUTEX_SIG_fast
);
58 _pthread_mutex_check_signature(const pthread_mutex_t
*mutex
)
60 // TODO: PTHREAD_STRICT candidate
61 return ((mutex
->sig
& _PTHREAD_MUTEX_SIG_MASK
) == _PTHREAD_MUTEX_SIG_CMP
);
66 _pthread_mutex_check_signature_init(const pthread_mutex_t
*mutex
)
68 return ((mutex
->sig
& _PTHREAD_MUTEX_SIG_init_MASK
) ==
69 _PTHREAD_MUTEX_SIG_init_CMP
);
72 #pragma mark pthread mutex accessors
76 _pthread_mutex_uses_ulock(pthread_mutex_t
*mutex
)
78 return mutex
->mtxopts
.options
.ulock
;
81 #pragma mark _pthread_rwlock_check_signature
85 _pthread_rwlock_check_signature(const pthread_rwlock_t
*rwlock
)
87 return (rwlock
->sig
== _PTHREAD_RWLOCK_SIG
);
92 _pthread_rwlock_check_signature_init(const pthread_rwlock_t
*rwlock
)
94 return (rwlock
->sig
== _PTHREAD_RWLOCK_SIG_init
);
97 #pragma mark unfair lock wrappers
99 #define _PTHREAD_LOCK_INITIALIZER OS_UNFAIR_LOCK_INIT
100 #define _PTHREAD_LOCK_OPTIONS \
101 (OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION | OS_UNFAIR_LOCK_ADAPTIVE_SPIN)
105 _pthread_lock_init(os_unfair_lock_t lock
)
107 *lock
= _PTHREAD_LOCK_INITIALIZER
;
110 OS_OVERLOADABLE OS_ALWAYS_INLINE
112 _pthread_lock_lock(os_unfair_lock_t lock
)
114 #if OS_UNFAIR_LOCK_INLINE
115 os_unfair_lock_lock_with_options_inline(lock
, _PTHREAD_LOCK_OPTIONS
);
117 os_unfair_lock_lock_with_options(lock
, _PTHREAD_LOCK_OPTIONS
);
121 OS_OVERLOADABLE OS_ALWAYS_INLINE
123 _pthread_lock_lock(os_unfair_lock_t lock
, mach_port_t mts
)
125 #if OS_UNFAIR_LOCK_INLINE
126 os_unfair_lock_lock_no_tsd_inline(lock
, _PTHREAD_LOCK_OPTIONS
, mts
);
128 os_unfair_lock_lock_no_tsd(lock
, _PTHREAD_LOCK_OPTIONS
, mts
);
132 OS_OVERLOADABLE OS_ALWAYS_INLINE
134 _pthread_lock_unlock(os_unfair_lock_t lock
)
136 #if OS_UNFAIR_LOCK_INLINE
137 os_unfair_lock_unlock_inline(lock
);
139 os_unfair_lock_unlock(lock
);
143 OS_OVERLOADABLE OS_ALWAYS_INLINE
145 _pthread_lock_unlock(os_unfair_lock_t lock
, mach_port_t mts
)
147 #if OS_UNFAIR_LOCK_INLINE
148 os_unfair_lock_unlock_no_tsd_inline(lock
, mts
);
150 os_unfair_lock_unlock_no_tsd(lock
, mts
);
154 #pragma mark pthread accessors
156 // Internal references to pthread_self() use TSD slot 0 directly.
157 #define pthread_self() _pthread_self_direct()
159 // Internal references to errno use TSD slot 1 directly.
161 #define errno (*_pthread_errno_address_direct())
163 #define _pthread_tsd_slot(th, name) \
164 (*(_PTHREAD_TSD_SLOT_##name##_TYPE *)(uintptr_t *)&(th)->tsd[_PTHREAD_TSD_SLOT_##name])
168 _pthread_validate_signature(pthread_t thread
)
170 pthread_t th
= (pthread_t
)(thread
->sig
^ _pthread_ptr_munge_token
);
171 #if __has_feature(ptrauth_calls)
172 th
= ptrauth_auth_data(th
, ptrauth_key_process_dependent_data
,
173 ptrauth_string_discriminator("pthread.signature"));
175 if (os_unlikely(th
!= thread
)) {
176 /* OS_REASON_LIBSYSTEM_CODE_PTHREAD_CORRUPTION == 4 */
177 abort_with_reason(OS_REASON_LIBSYSTEM
, 4, "pthread_t was corrupted", 0);
183 _pthread_init_signature(pthread_t thread
)
185 pthread_t th
= thread
;
186 #if __has_feature(ptrauth_calls)
187 th
= ptrauth_sign_unauthenticated(th
, ptrauth_key_process_dependent_data
,
188 ptrauth_string_discriminator("pthread.signature"));
190 thread
->sig
= (uintptr_t)th
^ _pthread_ptr_munge_token
;
194 * ALWAYS called without list lock and return with list lock held on success
196 * This weird calling convention exists because this function will sometimes
197 * drop the lock, and it's best callers don't have to remember this.
201 _pthread_validate_thread_and_list_lock(pthread_t thread
)
204 if (thread
== NULL
) return false;
205 _pthread_lock_lock(&_pthread_list_lock
);
206 TAILQ_FOREACH(p
, &__pthread_head
, tl_plist
) {
207 if (p
!= thread
) continue;
208 _pthread_validate_signature(p
);
211 _pthread_lock_unlock(&_pthread_list_lock
);
218 _pthread_is_valid(pthread_t thread
, mach_port_t
*portp
)
220 mach_port_t kport
= MACH_PORT_NULL
;
223 if (thread
== pthread_self()) {
224 _pthread_validate_signature(thread
);
226 kport
= _pthread_tsd_slot(thread
, MACH_THREAD_SELF
);
227 } else if (!_pthread_validate_thread_and_list_lock(thread
)) {
230 kport
= _pthread_tsd_slot(thread
, MACH_THREAD_SELF
);
232 _pthread_lock_unlock(&_pthread_list_lock
);
241 OS_ALWAYS_INLINE OS_CONST
242 static inline pthread_globals_t
243 _pthread_globals(void)
245 return os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_PTHREAD
,
246 sizeof(struct pthread_globals_s
), NULL
);
249 #endif // __LIBPTHREAD_INLINE_INTERNAL_H__