2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #ifndef _SYS_PTHREAD_INTERNAL_H_
30 #define _SYS_PTHREAD_INTERNAL_H_
33 #include <stdatomic.h>
34 #include <kern/thread_call.h>
35 #include <kern/kcdata.h>
36 #include <sys/pthread_shims.h>
37 #include <sys/queue.h>
38 #include <sys/proc_info.h>
41 #define PTHREAD_INLINE_RMW_ATOMICS 0
43 #define PTHREAD_INLINE_RMW_ATOMICS 1
47 #include "kern/synch_internal.h"
48 #include "kern/workqueue_internal.h"
49 #include "kern/kern_trace.h"
50 #include "pthread/qos.h"
51 #include "private/qos_private.h"
53 /* pthread userspace SPI feature checking, these constants are returned from bsdthread_register,
54 * as a bitmask, to inform userspace of the supported feature set. Old releases of OS X return
55 * from this call either zero or -1, allowing us to return a positive number for feature bits.
57 #define PTHREAD_FEATURE_DISPATCHFUNC 0x01 /* same as WQOPS_QUEUE_NEWSPISUPP, checks for dispatch function support */
58 #define PTHREAD_FEATURE_FINEPRIO 0x02 /* are fine grained prioirities available */
59 #define PTHREAD_FEATURE_BSDTHREADCTL 0x04 /* is the bsdthread_ctl syscall available */
60 #define PTHREAD_FEATURE_SETSELF 0x08 /* is the BSDTHREAD_CTL_SET_SELF command of bsdthread_ctl available */
61 #define PTHREAD_FEATURE_QOS_MAINTENANCE 0x10 /* is QOS_CLASS_MAINTENANCE available */
62 #define PTHREAD_FEATURE_RESERVED 0x20 /* burnt, shipped in OSX 10.11 & iOS 9 with partial kevent delivery support */
63 #define PTHREAD_FEATURE_KEVENT 0x40 /* supports direct kevent delivery */
64 #define PTHREAD_FEATURE_WORKLOOP 0x80 /* supports workloops */
65 #define PTHREAD_FEATURE_QOS_DEFAULT 0x40000000 /* the kernel supports QOS_CLASS_DEFAULT */
67 /* pthread bsdthread_ctl sysctl commands */
68 #define BSDTHREAD_CTL_SET_QOS 0x10 /* bsdthread_ctl(BSDTHREAD_CTL_SET_QOS, thread_port, tsd_entry_addr, 0) */
69 #define BSDTHREAD_CTL_GET_QOS 0x20 /* bsdthread_ctl(BSDTHREAD_CTL_GET_QOS, thread_port, 0, 0) */
70 #define BSDTHREAD_CTL_QOS_OVERRIDE_START 0x40 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_START, thread_port, priority, 0) */
71 #define BSDTHREAD_CTL_QOS_OVERRIDE_END 0x80 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_END, thread_port, 0, 0) */
72 #define BSDTHREAD_CTL_SET_SELF 0x100 /* bsdthread_ctl(BSDTHREAD_CTL_SET_SELF, priority, voucher, flags) */
73 #define BSDTHREAD_CTL_QOS_OVERRIDE_RESET 0x200 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_RESET, 0, 0, 0) */
74 #define BSDTHREAD_CTL_QOS_OVERRIDE_DISPATCH 0x400 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_DISPATCH, thread_port, priority, 0) */
75 #define BSDTHREAD_CTL_QOS_DISPATCH_ASYNCHRONOUS_OVERRIDE_ADD 0x401 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_DISPATCH_ASYNCHRONOUS_OVERRIDE_ADD, thread_port, priority, resource) */
76 #define BSDTHREAD_CTL_QOS_DISPATCH_ASYNCHRONOUS_OVERRIDE_RESET 0x402 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_DISPATCH_ASYNCHRONOUS_OVERRIDE_RESET, 0|1 (?reset_all), resource, 0) */
77 #define BSDTHREAD_CTL_QOS_MAX_PARALLELISM 0x800 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_MAX_PARALLELISM, priority, flags, 0) */
79 /* qos_class_t is mapped into one of these bits in the bitfield, this mapping now exists here because
80 * libdispatch requires the QoS class mask of the pthread_priority_t to be a bitfield.
82 #define __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE 0x20
83 #define __PTHREAD_PRIORITY_CBIT_USER_INITIATED 0x10
84 #define __PTHREAD_PRIORITY_CBIT_DEFAULT 0x8
85 #define __PTHREAD_PRIORITY_CBIT_UTILITY 0x4
86 #define __PTHREAD_PRIORITY_CBIT_BACKGROUND 0x2
87 #define __PTHREAD_PRIORITY_CBIT_MAINTENANCE 0x1
88 #define __PTHREAD_PRIORITY_CBIT_UNSPECIFIED 0x0
91 _pthread_qos_class_to_thread_qos(qos_class_t qos
)
94 case QOS_CLASS_USER_INTERACTIVE
: return THREAD_QOS_USER_INTERACTIVE
;
95 case QOS_CLASS_USER_INITIATED
: return THREAD_QOS_USER_INITIATED
;
96 case QOS_CLASS_DEFAULT
: return THREAD_QOS_LEGACY
;
97 case QOS_CLASS_UTILITY
: return THREAD_QOS_UTILITY
;
98 case QOS_CLASS_BACKGROUND
: return THREAD_QOS_BACKGROUND
;
99 case QOS_CLASS_MAINTENANCE
: return THREAD_QOS_MAINTENANCE
;
100 default: return THREAD_QOS_UNSPECIFIED
;
104 static inline pthread_priority_t
105 _pthread_priority_make_newest(qos_class_t qc
, int rel
, unsigned long flags
)
107 pthread_priority_t cls
;
109 case QOS_CLASS_USER_INTERACTIVE
: cls
= __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE
; break;
110 case QOS_CLASS_USER_INITIATED
: cls
= __PTHREAD_PRIORITY_CBIT_USER_INITIATED
; break;
111 case QOS_CLASS_DEFAULT
: cls
= __PTHREAD_PRIORITY_CBIT_DEFAULT
; break;
112 case QOS_CLASS_UTILITY
: cls
= __PTHREAD_PRIORITY_CBIT_UTILITY
; break;
113 case QOS_CLASS_BACKGROUND
: cls
= __PTHREAD_PRIORITY_CBIT_BACKGROUND
; break;
114 case QOS_CLASS_MAINTENANCE
: cls
= __PTHREAD_PRIORITY_CBIT_MAINTENANCE
; break;
115 case QOS_CLASS_UNSPECIFIED
:
117 cls
= __PTHREAD_PRIORITY_CBIT_UNSPECIFIED
;
118 rel
= 1; // results in priority bits == 0 <rdar://problem/16184900>
122 pthread_priority_t p
=
123 (flags
& _PTHREAD_PRIORITY_FLAGS_MASK
) |
124 ((cls
<< _PTHREAD_PRIORITY_QOS_CLASS_SHIFT
) & _PTHREAD_PRIORITY_QOS_CLASS_MASK
) |
125 (((uint8_t)rel
- 1) & _PTHREAD_PRIORITY_PRIORITY_MASK
);
130 static inline qos_class_t
131 _pthread_priority_get_qos_newest(pthread_priority_t priority
)
134 switch ((priority
& _PTHREAD_PRIORITY_QOS_CLASS_MASK
) >> _PTHREAD_PRIORITY_QOS_CLASS_SHIFT
) {
135 case __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE
: qc
= QOS_CLASS_USER_INTERACTIVE
; break;
136 case __PTHREAD_PRIORITY_CBIT_USER_INITIATED
: qc
= QOS_CLASS_USER_INITIATED
; break;
137 case __PTHREAD_PRIORITY_CBIT_DEFAULT
: qc
= QOS_CLASS_DEFAULT
; break;
138 case __PTHREAD_PRIORITY_CBIT_UTILITY
: qc
= QOS_CLASS_UTILITY
; break;
139 case __PTHREAD_PRIORITY_CBIT_BACKGROUND
: qc
= QOS_CLASS_BACKGROUND
; break;
140 case __PTHREAD_PRIORITY_CBIT_MAINTENANCE
: qc
= QOS_CLASS_MAINTENANCE
; break;
141 case __PTHREAD_PRIORITY_CBIT_UNSPECIFIED
:
142 default: qc
= QOS_CLASS_UNSPECIFIED
; break;
147 #define _pthread_priority_get_relpri(priority) \
148 ((int8_t)((priority & _PTHREAD_PRIORITY_PRIORITY_MASK) >> _PTHREAD_PRIORITY_PRIORITY_SHIFT) + 1)
150 #define _pthread_priority_get_flags(priority) \
151 (priority & _PTHREAD_PRIORITY_FLAGS_MASK)
153 #define _pthread_priority_split_newest(priority, qos, relpri) \
154 ({ qos = _pthread_priority_get_qos_newest(priority); \
155 relpri = (qos == QOS_CLASS_UNSPECIFIED) ? 0 : \
156 _pthread_priority_get_relpri(priority); \
159 #define _PTHREAD_QOS_PARALLELISM_COUNT_LOGICAL 0x1
160 #define _PTHREAD_QOS_PARALLELISM_REALTIME 0x2
162 /* userspace <-> kernel registration struct, for passing data to/from the kext during main thread init. */
163 struct _pthread_registration_data
{
165 * version == sizeof(struct _pthread_registration_data)
167 * The structure can only grow, so we use its size as the version.
168 * Userspace initializes this to the size of its structure and the kext
169 * will copy out the version that was actually consumed.
171 * n.b. you must make sure the size of this structure isn't LP64-dependent
175 uint64_t dispatch_queue_offset
; /* copy-in */
176 uint64_t /* pthread_priority_t */ main_qos
; /* copy-out */
177 uint32_t tsd_offset
; /* copy-in */
178 uint32_t return_to_kernel_offset
; /* copy-in */
179 uint32_t mach_thread_self_offset
; /* copy-in */
180 } __attribute__ ((packed
));
184 /* The set of features, from the feature bits above, that we support. */
185 #define PTHREAD_FEATURE_SUPPORTED ( \
186 PTHREAD_FEATURE_DISPATCHFUNC | \
187 PTHREAD_FEATURE_FINEPRIO | \
188 PTHREAD_FEATURE_BSDTHREADCTL | \
189 PTHREAD_FEATURE_SETSELF | \
190 PTHREAD_FEATURE_QOS_MAINTENANCE | \
191 PTHREAD_FEATURE_QOS_DEFAULT | \
192 PTHREAD_FEATURE_KEVENT | \
193 PTHREAD_FEATURE_WORKLOOP )
195 extern pthread_callbacks_t pthread_kern
;
197 struct ksyn_waitq_element
{
198 TAILQ_ENTRY(ksyn_waitq_element
) kwe_list
; /* link to other list members */
199 void * kwe_kwqqueue
; /* queue blocked on */
200 uint32_t kwe_state
; /* state */
201 uint32_t kwe_lockseq
; /* the sequence of the entry */
202 uint32_t kwe_count
; /* upper bound on number of matches still pending */
203 uint32_t kwe_psynchretval
; /* thread retval */
204 void *kwe_uth
; /* uthread */
205 uint64_t kwe_tid
; /* tid of waiter */
207 typedef struct ksyn_waitq_element
* ksyn_waitq_element_t
;
209 pthread_priority_t
thread_qos_get_pthread_priority(int qos
) __attribute__((const));
210 int thread_qos_get_class_index(int qos
) __attribute__((const));
211 int pthread_priority_get_thread_qos(pthread_priority_t priority
) __attribute__((const));
212 int pthread_priority_get_class_index(pthread_priority_t priority
) __attribute__((const));
213 pthread_priority_t
class_index_get_pthread_priority(int index
) __attribute__((const));
214 int class_index_get_thread_qos(int index
) __attribute__((const));
215 int qos_class_get_class_index(int qos
) __attribute__((const));
217 #define PTH_DEFAULT_STACKSIZE 512*1024
218 #define MAX_PTHREAD_SIZE 64*1024
220 /* exported from the kernel but not present in any headers. */
221 extern thread_t
port_name_to_thread(mach_port_name_t port_name
);
223 /* function declarations for pthread_kext.c */
224 void pthread_init(void);
225 void psynch_zoneinit(void);
226 void _pth_proc_hashinit(proc_t p
);
227 void _pth_proc_hashdelete(proc_t p
);
228 void pth_global_hashinit(void);
229 void psynch_wq_cleanup(void*, void*);
231 void _pthread_init(void);
232 int _fill_procworkqueue(proc_t p
, struct proc_workqueueinfo
* pwqinfo
);
233 uint32_t _get_pwq_state_kdp(proc_t p
);
234 void _workqueue_exit(struct proc
*p
);
235 void _workqueue_mark_exiting(struct proc
*p
);
236 void _workqueue_thread_yielded(void);
237 sched_call_t
_workqueue_get_sched_callback(void);
239 int _bsdthread_create(struct proc
*p
, user_addr_t user_func
, user_addr_t user_funcarg
, user_addr_t user_stack
, user_addr_t user_pthread
, uint32_t flags
, user_addr_t
*retval
);
240 int _bsdthread_register(struct proc
*p
, user_addr_t threadstart
, user_addr_t wqthread
, int pthsize
, user_addr_t dummy_value
, user_addr_t targetconc_ptr
, uint64_t dispatchqueue_offset
, int32_t *retval
);
241 int _bsdthread_terminate(struct proc
*p
, user_addr_t stackaddr
, size_t size
, uint32_t kthport
, uint32_t sem
, int32_t *retval
);
242 int _bsdthread_ctl_set_qos(struct proc
*p
, user_addr_t cmd
, mach_port_name_t kport
, user_addr_t tsd_priority_addr
, user_addr_t arg3
, int *retval
);
243 int _bsdthread_ctl_set_self(struct proc
*p
, user_addr_t cmd
, pthread_priority_t priority
, mach_port_name_t voucher
, _pthread_set_flags_t flags
, int *retval
);
244 int _bsdthread_ctl_qos_override_start(struct proc
*p
, user_addr_t cmd
, mach_port_name_t kport
, pthread_priority_t priority
, user_addr_t resource
, int *retval
);
245 int _bsdthread_ctl_qos_override_end(struct proc
*p
, user_addr_t cmd
, mach_port_name_t kport
, user_addr_t resource
, user_addr_t arg3
, int *retval
);
246 int _bsdthread_ctl_qos_override_dispatch(struct proc __unused
*p
, user_addr_t __unused cmd
, mach_port_name_t kport
, pthread_priority_t priority
, user_addr_t arg3
, int __unused
*retval
);
247 int _bsdthread_ctl_qos_override_reset(struct proc __unused
*p
, user_addr_t __unused cmd
, user_addr_t arg1
, user_addr_t arg2
, user_addr_t arg3
, int __unused
*retval
);
248 int _bsdthread_ctl_qos_dispatch_asynchronous_override_add(struct proc __unused
*p
, user_addr_t __unused cmd
, mach_port_name_t kport
, pthread_priority_t priority
, user_addr_t resource
, int __unused
*retval
);
249 int _bsdthread_ctl_qos_dispatch_asynchronous_override_reset(struct proc __unused
*p
, user_addr_t __unused cmd
, int reset_all
, user_addr_t resource
, user_addr_t arg3
, int __unused
*retval
);
250 int _bsdthread_ctl(struct proc
*p
, user_addr_t cmd
, user_addr_t arg1
, user_addr_t arg2
, user_addr_t arg3
, int *retval
);
251 int _thread_selfid(__unused
struct proc
*p
, uint64_t *retval
);
252 int _workq_kernreturn(struct proc
*p
, int options
, user_addr_t item
, int arg2
, int arg3
, int32_t *retval
);
253 int _workq_open(struct proc
*p
, int32_t *retval
);
255 int _psynch_mutexwait(proc_t p
, user_addr_t mutex
, uint32_t mgen
, uint32_t ugen
, uint64_t tid
, uint32_t flags
, uint32_t * retval
);
256 int _psynch_mutexdrop(proc_t p
, user_addr_t mutex
, uint32_t mgen
, uint32_t ugen
, uint64_t tid
, uint32_t flags
, uint32_t * retval
);
257 int _psynch_cvbroad(proc_t p
, user_addr_t cv
, uint64_t cvlsgen
, uint64_t cvudgen
, uint32_t flags
, user_addr_t mutex
, uint64_t mugen
, uint64_t tid
, uint32_t *retval
);
258 int _psynch_cvsignal(proc_t p
, user_addr_t cv
, uint64_t cvlsgen
, uint32_t cvugen
, int thread_port
, user_addr_t mutex
, uint64_t mugen
, uint64_t tid
, uint32_t flags
, uint32_t * retval
);
259 int _psynch_cvwait(proc_t p
, user_addr_t cv
, uint64_t cvlsgen
, uint32_t cvugen
, user_addr_t mutex
, uint64_t mugen
, uint32_t flags
, int64_t sec
, uint32_t nsec
, uint32_t * retval
);
260 int _psynch_cvclrprepost(proc_t p
, user_addr_t cv
, uint32_t cvgen
, uint32_t cvugen
, uint32_t cvsgen
, uint32_t prepocnt
, uint32_t preposeq
, uint32_t flags
, int *retval
);
261 int _psynch_rw_longrdlock(proc_t p
, user_addr_t rwlock
, uint32_t lgenval
, uint32_t ugenval
, uint32_t rw_wc
, int flags
, uint32_t * retval
);
262 int _psynch_rw_rdlock(proc_t p
, user_addr_t rwlock
, uint32_t lgenval
, uint32_t ugenval
, uint32_t rw_wc
, int flags
, uint32_t *retval
);
263 int _psynch_rw_unlock(proc_t p
, user_addr_t rwlock
, uint32_t lgenval
, uint32_t ugenval
, uint32_t rw_wc
, int flags
, uint32_t *retval
);
264 int _psynch_rw_wrlock(proc_t p
, user_addr_t rwlock
, uint32_t lgenval
, uint32_t ugenval
, uint32_t rw_wc
, int flags
, uint32_t *retval
);
265 int _psynch_rw_yieldwrlock(proc_t p
, user_addr_t rwlock
, uint32_t lgenval
, uint32_t ugenval
, uint32_t rw_wc
, int flags
, uint32_t *retval
);
267 void _pthread_find_owner(thread_t thread
, struct stackshot_thread_waitinfo
*waitinfo
);
268 void * _pthread_get_thread_kwq(thread_t thread
);
270 extern lck_grp_attr_t
*pthread_lck_grp_attr
;
271 extern lck_grp_t
*pthread_lck_grp
;
272 extern lck_attr_t
*pthread_lck_attr
;
273 extern lck_mtx_t
*pthread_list_mlock
;
274 extern thread_call_t psynch_thcall
;
276 struct uthread
* current_uthread(void);
278 #define WORKQ_REQTHREADS_THREADREQ 0x1
279 #define WORKQ_REQTHREADS_NOEMERGENCY 0x2
281 // Call for the kernel's kevent system to request threads. A list of QoS/event
282 // counts should be provided, sorted by flags and then QoS class. If the
283 // identity of the thread to handle the request is known, it will be returned.
284 // If a new thread must be created, NULL will be returned.
285 thread_t
_workq_reqthreads(struct proc
*p
, int requests_count
,
286 workq_reqthreads_req_t requests
);
288 // Resolve a pthread_priority_t to a QoS/relative pri
289 integer_t
_thread_qos_from_pthread_priority(unsigned long pri
, unsigned long *flags
);
290 // Clear out extraneous flags/pri info for putting in voucher
291 pthread_priority_t
_pthread_priority_canonicalize(pthread_priority_t pri
, boolean_t for_propagation
);
293 boolean_t
_workq_thread_has_been_unbound(thread_t th
, int qos_class
);
295 int workq_kern_threadreq(struct proc
*p
, workq_threadreq_t req
,
296 enum workq_threadreq_type
, unsigned long priority
, int flags
);
298 int workq_kern_threadreq_modify(struct proc
*p
, workq_threadreq_t req
,
299 enum workq_threadreq_op operation
,
300 unsigned long arg1
, unsigned long arg2
);
304 #endif /* _SYS_PTHREAD_INTERNAL_H_ */