Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
/*
 * Copyright (c) 2000-2017 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */

#ifndef _PTHREAD_PRIORITY_PRIVATE_H_
#define _PTHREAD_PRIORITY_PRIVATE_H_

#if KERNEL
#define PTHREAD_EXPOSE_LAYOUT 1
#else
#include <TargetConditionals.h>
#if TARGET_OS_SIMULATOR
#define PTHREAD_EXPOSE_LAYOUT 0
#else
#define PTHREAD_EXPOSE_LAYOUT 1
#endif /* TARGET_OS_SIMULATOR */
#endif

/*!
 * @typedef pthread_priority_t
 *
 * @abstract
 * pthread_priority_t is an on opaque integer that is guaranteed to be ordered
 * such that combations of QoS classes and relative priorities are ordered
 * numerically, according to their combined priority.
 *
 * <b>xnu, pthread & libdispatch flags</b>
 *
 * @const _PTHREAD_PRIORITY_OVERCOMMIT_FLAG
 * The thread this priority is applied to is overcommit (affects the workqueue
 * creation policy for this priority).
 *
 * @const _PTHREAD_PRIORITY_COOPERATIVE_FLAG
 * Used to convey that a thread is part of the cooperative pool. This is used
 * both outgoing form kernel and incoming into kernel
 *
 * @const _PTHREAD_PRIORITY_THREAD_TYPE_MASK
 * The set of bits that encode information about the thread type - whether it is
 * overcommit, non-overcommit or cooperative
 *
 * @const _PTHREAD_PRIORITY_FALLBACK_FLAG
 * Indicates that this priority is is used only when incoming events have no
 * priority at all. It is merely used as a fallback (hence the name) instead of
 * a floor.
 *
 * This is usually used with QOS_CLASS_DEFAULT and a 0 relative priority.
 *
 * @const _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG
 * The event manager flag indicates that this thread/request is for a event
 * manager thread.  There can only ever be one event manager thread at a time
 * and it is brought up at the highest of all event manager priorities pthread
 * knows about.
 *
 * @const _PTHREAD_PRIORITY_OVERRIDE_QOS_FLAG
 * This flag indicates that the bits extracted using
 * _PTHREAD_PRIORITY_QOS_CLASS_MASK represent { QoS override, req QoS } instead
 * of just req QoS. This is only currently only used as input to the kernel as
 * part of pthread_set_properties_self(). The override field here represents the
 * dispatch workqueue override.
 *
 * @const _PTHREAD_PRIORITY_SCHED_PRI_FLAG
 * @const _PTHREAD_PRIORITY_SCHED_PRI_MASK
 * This flag indicates that the bits extracted using
 * _PTHREAD_PRIORITY_SCHED_PRI_MASK represent a scheduler priority instead of
 * a {qos, relative priority} pair.
 *
 * This flag is used by the pthread kext to indicate to libdispatch that the
 * event manager queue priority is a scheduling priority and not a QoS.  When
 * the manager thread's priority is updated due to creation of pthread root
 * queues, libdispatch passed a pthread_priority_t in to kernel with this flag
 * to specify the new sched pri of manager. This flag is never used as an input
 * by anything else and is why it can perform a double duty with
 * _PTHREAD_PRIORITY_ROOTQUEUE_FLAG.
 *
 * @const _PTHREAD_PRIORITY_NEEDS_UNBIND_FLAG
 * This flag is used for the priority of event delivery threads to indicate
 * to libdispatch that this thread is bound to a kqueue.
 *
 * <b>dispatch only flags</b>
 *
 * @const _PTHREAD_PRIORITY_INHERIT_FLAG
 * This flag is meaningful to libdispatch only and has no meaning for the
 * kernel and/or pthread.
 *
 * @const _PTHREAD_PRIORITY_ROOTQUEUE_FLAG
 * This flag is meaningful to libdispatch only and has no meaning for the
 * kernel and/or pthread.
 *
 * @const _PTHREAD_PRIORITY_ENFORCE_FLAG
 * This flag is used to indicate that this priority should be prefered for work
 * submited asynchronously over the intrinsic priority of the queue/thread the
 * work is submitted to.
 *
 *
 * pthread_priority_t encoding - outgoing from kernel:
 *
 * Regular:
 *                flags                    req QoS class           Rel pri
 * |---------------------------------|--------------------|--------------------|
 *              22 - 31                      8-21                 0-7
 *
 * With _PTHREAD_PRIORITY_SCHED_PRI_FLAG:
 *
 *               flags                  unused         sched priority
 * |---------------------------------|----------|------------------------------|
 *              22 - 31                 16-21             0-15
 *
 * pthread_priority_t encoding - incoming to kernel via various syscalls:
 *
 * Regular:
 *
 *                flags                    req QoS class           Rel pri
 * |---------------------------------|--------------------|--------------------|
 *              22 - 31                      8-21                 0-7
 *
 * With _PTHREAD_PRIORITY_OVERRIDE_QOS_FLAG:
 *
 *              flags                  QoS ovr   QoS class       Rel pri
 * |---------------------------------|---------|----------|--------------------|
 *              22 - 31                 14-21      8-13            0-7
 *
 * With _PTHREAD_PRIORITY_SCHED_PRI_FLAG:
 *
 *               flags                  unused         sched priority
 * |---------------------------------|----------|------------------------------|
 *              22 - 31                 16-21             0-15
 */
typedef unsigned long pthread_priority_t;

#define _PTHREAD_PRIORITY_OVERCOMMIT_FLAG               0x80000000u
#define _PTHREAD_PRIORITY_INHERIT_FLAG                  0x40000000u /* dispatch only */
#define _PTHREAD_PRIORITY_ROOTQUEUE_FLAG                0x20000000u /* dispatch only */
#define _PTHREAD_PRIORITY_SCHED_PRI_FLAG                0x20000000u
#define _PTHREAD_PRIORITY_ENFORCE_FLAG                  0x10000000u /* dispatch only */
#define _PTHREAD_PRIORITY_FALLBACK_FLAG                 0x04000000u
#define _PTHREAD_PRIORITY_COOPERATIVE_FLAG              0x08000000u
#define _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG            0x02000000u
#define _PTHREAD_PRIORITY_NEEDS_UNBIND_FLAG             0x01000000u
#define _PTHREAD_PRIORITY_DEFAULTQUEUE_FLAG             _PTHREAD_PRIORITY_FALLBACK_FLAG // compat
#define _PTHREAD_PRIORITY_OVERRIDE_QOS_FLAG             0x00800000u

#define _PTHREAD_PRIORITY_THREAD_TYPE_MASK              (_PTHREAD_PRIORITY_COOPERATIVE_FLAG | _PTHREAD_PRIORITY_OVERCOMMIT_FLAG)

#if PTHREAD_EXPOSE_LAYOUT || defined(__PTHREAD_EXPOSE_INTERNALS__)
// Masks for encoding of pthread priority
#define _PTHREAD_PRIORITY_FLAGS_MASK                    0xff000000u

#define _PTHREAD_PRIORITY_SCHED_PRI_MASK                0x0000ffffu

#define _PTHREAD_PRIORITY_QOS_CLASS_MASK                0x003fff00u
#define _PTHREAD_PRIORITY_QOS_CLASS_SHIFT               (8ull)
#define _PTHREAD_PRIORITY_VALID_QOS_CLASS_MASK          0x00003f00u
#define _PTHREAD_PRIORITY_VALID_OVERRIDE_QOS_MASK       0x003fc000u
#define _PTHREAD_PRIORITY_QOS_OVERRIDE_SHIFT            (14ull)

#define _PTHREAD_PRIORITY_PRIORITY_MASK                 0x000000ffu
#define _PTHREAD_PRIORITY_PRIORITY_SHIFT                (0)
#endif /* PTHREAD_EXPOSE_LAYOUT */

#if PRIVATE
#if XNU_KERNEL_PRIVATE && !defined(__PTHREAD_EXPOSE_INTERNALS__)
#define __PTHREAD_EXPOSE_INTERNALS__ 1
#endif // XNU_KERNEL_PRIVATE
#ifdef __PTHREAD_EXPOSE_INTERNALS__
/*
 * This exposes the encoding used for pthread_priority_t
 * and is meant to be used by pthread and XNU only
 */
#include <mach/thread_policy.h> // THREAD_QOS_*
#include <stdbool.h>

// pthread_priority_t's type is unfortunately 64bits on LP64
// so we use this type for people who need to store it in structs
typedef unsigned int pthread_priority_compact_t;

__attribute__((always_inline, const))
static inline bool
_pthread_priority_has_qos(pthread_priority_t pp)
{
	return (pp & (_PTHREAD_PRIORITY_SCHED_PRI_FLAG |
	       _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG)) == 0 &&
	       (pp & _PTHREAD_PRIORITY_VALID_QOS_CLASS_MASK) != 0;
}

__attribute__((always_inline, const))
static inline bool
_pthread_priority_has_sched_pri(pthread_priority_t pp)
{
	return pp & _PTHREAD_PRIORITY_SCHED_PRI_FLAG;
}

__attribute__((always_inline, const))
static inline bool
_pthread_priority_has_override_qos(pthread_priority_t pp)
{
	return (pp & (_PTHREAD_PRIORITY_SCHED_PRI_FLAG |
	       _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG)) == 0 &&
	       (pp & _PTHREAD_PRIORITY_OVERRIDE_QOS_FLAG) != 0 &&
	       (pp & _PTHREAD_PRIORITY_VALID_OVERRIDE_QOS_MASK) != 0;
}

__attribute__((always_inline, const))
static inline pthread_priority_compact_t
_pthread_priority_make_from_thread_qos(thread_qos_t qos, int relpri,
    unsigned long flags)
{
	pthread_priority_compact_t pp = (flags & _PTHREAD_PRIORITY_FLAGS_MASK);
	if (qos && qos < THREAD_QOS_LAST) {
		pp |= (1 << (_PTHREAD_PRIORITY_QOS_CLASS_SHIFT + qos - 1));
		pp |= ((uint8_t)relpri - 1) & _PTHREAD_PRIORITY_PRIORITY_MASK;
	}
	return pp;
}

__attribute__((always_inline, const))
static inline pthread_priority_compact_t
_pthread_priority_make_from_sched_pri(int sched_pri, unsigned long flags)
{
	pthread_priority_compact_t pp = (flags & _PTHREAD_PRIORITY_FLAGS_MASK);
	pp |= _PTHREAD_PRIORITY_SCHED_PRI_FLAG;
	pp |= (pthread_priority_compact_t) sched_pri;

	return pp;
}

__attribute__((always_inline, const))
static inline pthread_priority_compact_t
_pthread_priority_make_from_thread_qos_and_override(thread_qos_t req_qos,
    int relpri, thread_qos_t override_qos, unsigned long flags)
{
	pthread_priority_compact_t pp;
	pp = _pthread_priority_make_from_thread_qos(req_qos, relpri, flags);

	if (override_qos && override_qos < THREAD_QOS_LAST) {
		pp |= (1 << (_PTHREAD_PRIORITY_QOS_OVERRIDE_SHIFT + (override_qos - 1)));
		pp |= _PTHREAD_PRIORITY_OVERRIDE_QOS_FLAG;
	}

	return pp;
}

__attribute__((always_inline, const))
static inline pthread_priority_compact_t
_pthread_event_manager_priority(void)
{
	return _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG;
}

__attribute__((always_inline, const))
static inline pthread_priority_compact_t
_pthread_unspecified_priority(void)
{
	return _pthread_priority_make_from_thread_qos(THREAD_QOS_UNSPECIFIED, 0, 0);
}

__attribute__((always_inline, const))
static inline pthread_priority_compact_t
_pthread_default_priority(unsigned long flags)
{
	return _pthread_priority_make_from_thread_qos(THREAD_QOS_LEGACY, 0, flags);
}

__attribute__((always_inline, const))
static inline thread_qos_t
_pthread_priority_thread_qos_fast(pthread_priority_t pp)
{
	pp &= _PTHREAD_PRIORITY_VALID_QOS_CLASS_MASK;
	pp >>= _PTHREAD_PRIORITY_QOS_CLASS_SHIFT;
	return (thread_qos_t)__builtin_ffs((int)pp);
}

__attribute__((always_inline, const))
static inline thread_qos_t
_pthread_priority_thread_override_qos_fast(pthread_priority_t pp)
{
	pp &= _PTHREAD_PRIORITY_VALID_OVERRIDE_QOS_MASK;
	pp >>= _PTHREAD_PRIORITY_QOS_OVERRIDE_SHIFT;
	return (thread_qos_t)__builtin_ffs((int)pp);
}

__attribute__((always_inline, const))
static inline int
_pthread_priority_sched_pri_fast(pthread_priority_t pp)
{
	return pp & _PTHREAD_PRIORITY_SCHED_PRI_MASK;
}

__attribute__((always_inline, const))
static inline thread_qos_t
_pthread_priority_thread_qos(pthread_priority_t pp)
{
	if (_pthread_priority_has_qos(pp)) {
		return _pthread_priority_thread_qos_fast(pp);
	}
	return THREAD_QOS_UNSPECIFIED;
}

__attribute__((always_inline, const))
static inline thread_qos_t
_pthread_priority_thread_override_qos(pthread_priority_t pp)
{
	if (_pthread_priority_has_override_qos(pp)) {
		return _pthread_priority_thread_override_qos_fast(pp);
	}
	return THREAD_QOS_UNSPECIFIED;
}

__attribute__((always_inline, const))
static inline int
_pthread_priority_sched_pri(pthread_priority_t pp)
{
	if (_pthread_priority_has_sched_pri(pp)) {
		return _pthread_priority_sched_pri_fast(pp);
	}

	return 0;
}

__attribute__((always_inline, const))
static inline int
_pthread_priority_relpri(pthread_priority_t pp)
{
	if (_pthread_priority_has_qos(pp)) {
		pp &= _PTHREAD_PRIORITY_PRIORITY_MASK;
		pp >>= _PTHREAD_PRIORITY_PRIORITY_SHIFT;
		return (int8_t)pp + 1;
	}
	return 0;
}

__attribute__((always_inline, const))
static inline bool
_pthread_priority_is_overcommit(pthread_priority_t pp)
{
	return pp & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG;
}

__attribute__((always_inline, const))
static inline bool
_pthread_priority_is_cooperative(pthread_priority_t pp)
{
	return pp & _PTHREAD_PRIORITY_COOPERATIVE_FLAG;
}

__attribute__((always_inline, const))
static inline bool
_pthread_priority_is_nonovercommit(pthread_priority_t pp)
{
	return !_pthread_priority_is_cooperative(pp) && !_pthread_priority_is_overcommit(pp);
}

#if XNU_KERNEL_PRIVATE
// Interfaces only used by the kernel and not implemented in userspace.

/*
 * Keep managerness, overcomitness and fallback, discard other flags.
 * Normalize and validate QoS/relpri
 */
__attribute__((const))
pthread_priority_compact_t
_pthread_priority_normalize(pthread_priority_t pp);

/*
 * Keep managerness, discard other flags.
 * Normalize and validate QoS/relpri
 */
__attribute__((const))
pthread_priority_compact_t
_pthread_priority_normalize_for_ipc(pthread_priority_t pp);

/*
 * Keep the flags from base_pp and return the priority with the maximum priority
 * of base_pp and _pthread_priority_make_from_thread_qos(qos, 0, 0)
 */
__attribute__((const))
pthread_priority_compact_t
_pthread_priority_combine(pthread_priority_t base_pp, thread_qos_t qos);


#endif // XNU_KERNEL_PRIVATE
#endif // __PTHREAD_EXPOSE_INTERNALS__
#endif // PRIVATE
#endif // _PTHREAD_PRIORITY_PRIVATE_H_