2 * Copyright (c) 2013 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
23 #if VOUCHER_USE_MACH_VOUCHER
25 #include <mach/mach_voucher.h>
28 #ifndef VM_MEMORY_GENEALOGY
29 #define VM_MEMORY_GENEALOGY 78
32 #ifndef VOUCHER_ATM_COLLECT_THRESHOLD
33 #define VOUCHER_ATM_COLLECT_THRESHOLD 1
35 #define VATM_COLLECT_THRESHOLD_VALUE(t) (((t) - 1) * 2)
36 static uint64_t volatile _voucher_atm_generation
;
38 typedef struct _voucher_atm_s
*_voucher_atm_t
;
40 static void _voucher_activity_atfork_child(void);
41 static _voucher_activity_t
_voucher_activity_copy_from_mach_voucher(
42 mach_voucher_t kv
, voucher_activity_id_t va_id
);
43 static inline _voucher_activity_t
_voucher_activity_retain(
44 _voucher_activity_t act
);
45 static inline void _voucher_activity_release(_voucher_activity_t act
);
46 static void _voucher_activity_remove(_voucher_activity_t act
);
47 static inline _voucher_atm_t
_voucher_atm_retain(_voucher_atm_t vatm
);
48 static inline void _voucher_atm_release(_voucher_atm_t vatm
);
51 #pragma mark voucher_t
54 OS_OBJECT_OBJC_CLASS_DECL(voucher
);
55 #define VOUCHER_CLASS OS_OBJECT_OBJC_CLASS(voucher)
57 const _os_object_class_s _voucher_class
= {
58 ._os_obj_xref_dispose
= (void(*)(_os_object_t
))_voucher_xref_dispose
,
59 ._os_obj_dispose
= (void(*)(_os_object_t
))_voucher_dispose
,
61 #define VOUCHER_CLASS &_voucher_class
64 static const voucher_activity_trace_id_t _voucher_activity_trace_id_release
=
65 (voucher_activity_trace_id_t
)voucher_activity_tracepoint_type_release
<<
66 _voucher_activity_trace_id_type_shift
;
67 static const unsigned int _voucher_max_activities
= 16;
69 DISPATCH_ALWAYS_INLINE
71 _voucher_recipes_init(mach_voucher_attr_recipe_data_t
*recipes
,
72 mach_voucher_attr_content_size_t bits_size
)
74 static const mach_voucher_attr_recipe_data_t base_recipe
= {
75 .key
= MACH_VOUCHER_ATTR_KEY_ALL
,
76 .command
= MACH_VOUCHER_ATTR_COPY
,
78 _voucher_recipes_base(recipes
) = base_recipe
;
79 static const mach_voucher_attr_recipe_data_t atm_recipe
= {
80 .key
= MACH_VOUCHER_ATTR_KEY_ATM
,
81 .command
= MACH_VOUCHER_ATTR_COPY
,
83 _voucher_recipes_atm(recipes
) = atm_recipe
;
84 static const mach_voucher_attr_recipe_data_t bits_recipe
= {
85 .key
= MACH_VOUCHER_ATTR_KEY_USER_DATA
,
86 .command
= MACH_VOUCHER_ATTR_USER_DATA_STORE
,
88 _voucher_recipes_bits(recipes
) = bits_recipe
;
89 if (!bits_size
) return;
90 _voucher_recipes_bits(recipes
).content_size
= bits_size
;
91 *_voucher_recipes_magic(recipes
) = _voucher_magic_v1
;
94 static inline voucher_t
95 _voucher_alloc(unsigned int activities
, pthread_priority_t priority
,
96 mach_voucher_attr_recipe_size_t extra
)
98 if (activities
> _voucher_max_activities
) {
99 activities
= _voucher_max_activities
;
102 size_t voucher_size
, recipes_size
;
103 mach_voucher_attr_content_size_t bits_size
;
104 recipes_size
= (priority
||activities
||extra
) ? _voucher_recipes_size() : 0;
105 bits_size
= recipes_size
? _voucher_bits_size(activities
) : 0;
106 voucher_size
= sizeof(voucher_s
) + recipes_size
+ bits_size
+ extra
;
107 voucher
= (voucher_t
)_os_object_alloc_realized(VOUCHER_CLASS
, voucher_size
);
108 #if VOUCHER_ENABLE_RECIPE_OBJECTS
109 voucher
->v_recipe_extra_size
= extra
;
110 voucher
->v_recipe_extra_offset
= voucher_size
- extra
;
112 dispatch_assert(!extra
);
114 voucher
->v_has_priority
= priority
? 1 : 0;
115 voucher
->v_activities
= activities
;
116 if (!recipes_size
) return voucher
;
117 _voucher_recipes_init(voucher
->v_recipes
, bits_size
);
118 *_voucher_priority(voucher
) = (_voucher_priority_t
)priority
;
119 _dispatch_voucher_debug("alloc", voucher
);
123 #if VOUCHER_ENABLE_RECIPE_OBJECTS
125 voucher_create(voucher_recipe_t recipe
)
127 // TODO: capture current activities or current kvoucher ?
128 mach_voucher_attr_recipe_size_t extra
= recipe
? recipe
->vr_size
: 0;
129 voucher_t voucher
= _voucher_alloc(0, 0, extra
);
131 memcpy(_voucher_extra_recipes(voucher
), recipe
->vr_data
, extra
);
138 voucher_adopt(voucher_t voucher
)
140 return _voucher_adopt(voucher
);
146 return _voucher_copy();
150 voucher_copy_without_importance(void)
152 return _voucher_copy_without_importance();
156 voucher_retain(voucher_t voucher
)
158 return _voucher_retain(voucher
);
162 voucher_release(voucher_t voucher
)
164 return _voucher_release(voucher
);
168 _voucher_thread_cleanup(void *voucher
)
170 _voucher_swap(voucher
, NULL
);
173 DISPATCH_CACHELINE_ALIGN
174 static TAILQ_HEAD(, voucher_s
) _vouchers
[VL_HASH_SIZE
];
175 #define _vouchers_head(kv) (&_vouchers[VL_HASH((kv))])
176 static os_lock_handoff_s _vouchers_lock
= OS_LOCK_HANDOFF_INIT
;
177 #define _vouchers_lock_lock() os_lock_lock(&_vouchers_lock)
178 #define _vouchers_lock_unlock() os_lock_unlock(&_vouchers_lock)
181 _voucher_find_and_retain(mach_voucher_t kv
)
184 if (!kv
) return NULL
;
185 _vouchers_lock_lock();
186 TAILQ_FOREACH(v
, _vouchers_head(kv
), v_list
) {
187 if (v
->v_ipc_kvoucher
== kv
) {
188 int xref_cnt
= dispatch_atomic_inc2o(v
, os_obj_xref_cnt
, relaxed
);
189 _dispatch_voucher_debug("retain -> %d", v
, xref_cnt
+ 1);
190 if (slowpath(xref_cnt
< 0)) {
191 _dispatch_voucher_debug("overrelease", v
);
192 DISPATCH_CRASH("Voucher overrelease");
195 // resurrection: raced with _voucher_remove
196 (void)dispatch_atomic_inc2o(v
, os_obj_ref_cnt
, relaxed
);
201 _vouchers_lock_unlock();
206 _voucher_insert(voucher_t v
)
208 mach_voucher_t kv
= v
->v_ipc_kvoucher
;
210 _vouchers_lock_lock();
211 if (slowpath(_TAILQ_IS_ENQUEUED(v
, v_list
))) {
212 _dispatch_voucher_debug("corruption", v
);
213 DISPATCH_CRASH("Voucher corruption");
215 TAILQ_INSERT_TAIL(_vouchers_head(kv
), v
, v_list
);
216 _vouchers_lock_unlock();
220 _voucher_remove(voucher_t v
)
222 mach_voucher_t kv
= v
->v_ipc_kvoucher
;
223 if (!_TAILQ_IS_ENQUEUED(v
, v_list
)) return;
224 _vouchers_lock_lock();
226 _dispatch_voucher_debug("corruption", v
);
227 DISPATCH_CRASH("Voucher corruption");
229 // check for resurrection race with _voucher_find_and_retain
230 if (dispatch_atomic_load2o(v
, os_obj_xref_cnt
, seq_cst
) < 0 &&
231 _TAILQ_IS_ENQUEUED(v
, v_list
)) {
232 TAILQ_REMOVE(_vouchers_head(kv
), v
, v_list
);
233 _TAILQ_MARK_NOT_ENQUEUED(v
, v_list
);
234 v
->v_list
.tqe_next
= (void*)~0ull;
236 _vouchers_lock_unlock();
240 _voucher_dealloc_mach_voucher(mach_voucher_t kv
)
242 _dispatch_kvoucher_debug("dealloc", kv
);
243 _dispatch_voucher_debug_machport(kv
);
244 kern_return_t kr
= mach_voucher_deallocate(kv
);
245 DISPATCH_VERIFY_MIG(kr
);
246 (void)dispatch_assume_zero(kr
);
249 static inline kern_return_t
250 _voucher_create_mach_voucher(const mach_voucher_attr_recipe_data_t
*recipes
,
251 size_t recipes_size
, mach_voucher_t
*kvp
)
254 mach_port_t mhp
= _dispatch_get_mach_host_port();
255 mach_voucher_t kv
= MACH_VOUCHER_NULL
;
256 mach_voucher_attr_raw_recipe_array_t kvr
;
257 mach_voucher_attr_recipe_size_t kvr_size
;
258 kvr
= (mach_voucher_attr_raw_recipe_array_t
)recipes
;
259 kvr_size
= (mach_voucher_attr_recipe_size_t
)recipes_size
;
260 kr
= host_create_mach_voucher(mhp
, kvr
, kvr_size
, &kv
);
261 DISPATCH_VERIFY_MIG(kr
);
263 _dispatch_kvoucher_debug("create", kv
);
264 _dispatch_voucher_debug_machport(kv
);
270 #if __has_include(<bank/bank_types.h>) && !defined(VOUCHER_USE_ATTR_BANK)
271 #include <bank/bank_types.h>
272 #define VOUCHER_USE_ATTR_BANK 1
273 mach_voucher_t _voucher_default_task_mach_voucher
;
277 _voucher_task_mach_voucher_init(void* ctxt DISPATCH_UNUSED
)
279 #if VOUCHER_USE_ATTR_BANK
282 static const mach_voucher_attr_recipe_data_t task_create_recipe
= {
283 .key
= MACH_VOUCHER_ATTR_KEY_BANK
,
284 .command
= MACH_VOUCHER_ATTR_BANK_CREATE
,
286 kr
= _voucher_create_mach_voucher(&task_create_recipe
,
287 sizeof(task_create_recipe
), &kv
);
288 if (dispatch_assume_zero(kr
)) {
289 DISPATCH_CLIENT_CRASH("Could not create task mach voucher");
291 _voucher_default_task_mach_voucher
= kv
;
292 _voucher_task_mach_voucher
= kv
;
297 voucher_replace_default_voucher(void)
299 #if VOUCHER_USE_ATTR_BANK
300 (void)_voucher_get_task_mach_voucher(); // initalize task mach voucher
301 mach_voucher_t kv
, tkv
= MACH_VOUCHER_NULL
;
302 voucher_t v
= _voucher_get();
303 if (v
&& v
->v_kvoucher
) {
305 kv
= v
->v_ipc_kvoucher
? v
->v_ipc_kvoucher
: v
->v_kvoucher
;
306 const mach_voucher_attr_recipe_data_t task_copy_recipe
= {
307 .key
= MACH_VOUCHER_ATTR_KEY_BANK
,
308 .command
= MACH_VOUCHER_ATTR_COPY
,
309 .previous_voucher
= kv
,
311 kr
= _voucher_create_mach_voucher(&task_copy_recipe
,
312 sizeof(task_copy_recipe
), &tkv
);
313 if (dispatch_assume_zero(kr
)) {
314 tkv
= MACH_VOUCHER_NULL
;
317 if (!tkv
) tkv
= _voucher_default_task_mach_voucher
;
318 kv
= dispatch_atomic_xchg(&_voucher_task_mach_voucher
, tkv
, relaxed
);
319 if (kv
&& kv
!= _voucher_default_task_mach_voucher
) {
320 _voucher_dealloc_mach_voucher(kv
);
322 _dispatch_voucher_debug("kvoucher[0x%08x] replace default voucher", v
, tkv
);
326 static inline _voucher_atm_t
327 _voucher_get_atm(voucher_t voucher
)
330 vatm
= voucher
&& voucher
->v_atm
? voucher
->v_atm
: _voucher_task_atm
;
334 static inline mach_voucher_t
335 _voucher_get_atm_mach_voucher(voucher_t voucher
)
337 _voucher_atm_t vatm
= _voucher_get_atm(voucher
);
338 mach_voucher_t kv
= vatm
? vatm
->vatm_kvoucher
: MACH_VOUCHER_NULL
;
343 _voucher_get_mach_voucher(voucher_t voucher
)
345 if (!voucher
) return MACH_VOUCHER_NULL
;
346 if (voucher
->v_ipc_kvoucher
) return voucher
->v_ipc_kvoucher
;
347 mach_voucher_t kvb
= voucher
->v_kvoucher
;
348 if (!kvb
) kvb
= _voucher_get_task_mach_voucher();
349 if (!voucher
->v_has_priority
&& !voucher
->v_activities
&&
350 !_voucher_extra_size(voucher
)) {
354 mach_voucher_t kv
, kvo
;
355 _voucher_base_recipe(voucher
).previous_voucher
= kvb
;
356 _voucher_atm_recipe(voucher
).previous_voucher
=
357 _voucher_get_atm_mach_voucher(voucher
);
358 kr
= _voucher_create_mach_voucher(voucher
->v_recipes
,
359 _voucher_recipes_size() + _voucher_extra_size(voucher
) +
360 _voucher_bits_recipe(voucher
).content_size
, &kv
);
361 if (dispatch_assume_zero(kr
) || !kv
){
362 return MACH_VOUCHER_NULL
;
364 if (!dispatch_atomic_cmpxchgv2o(voucher
, v_ipc_kvoucher
, MACH_VOUCHER_NULL
,
365 kv
, &kvo
, relaxed
)) {
366 _voucher_dealloc_mach_voucher(kv
);
369 if (kv
== voucher
->v_kvoucher
) {
370 // if v_kvoucher == v_ipc_kvoucher we keep only one reference
371 _voucher_dealloc_mach_voucher(kv
);
373 _voucher_insert(voucher
);
374 _dispatch_voucher_debug("kvoucher[0x%08x] create", voucher
, kv
);
380 _voucher_create_mach_voucher_with_priority(voucher_t voucher
,
381 pthread_priority_t priority
)
383 if (priority
== _voucher_get_priority(voucher
)) {
384 return MACH_VOUCHER_NULL
; // caller will use _voucher_get_mach_voucher
387 mach_voucher_t kv
, kvb
= voucher
? voucher
->v_kvoucher
: MACH_VOUCHER_NULL
;
388 if (!kvb
) kvb
= _voucher_get_task_mach_voucher();
389 mach_voucher_attr_recipe_data_t
*recipes
;
390 size_t recipes_size
= _voucher_recipes_size();
391 if (voucher
&& (voucher
->v_has_priority
|| voucher
->v_activities
||
392 _voucher_extra_size(voucher
))) {
393 recipes_size
+= _voucher_bits_recipe(voucher
).content_size
+
394 _voucher_extra_size(voucher
);
395 recipes
= alloca(recipes_size
);
396 memcpy(recipes
, voucher
->v_recipes
, recipes_size
);
397 _voucher_recipes_atm(recipes
).previous_voucher
=
398 _voucher_get_atm_mach_voucher(voucher
);
400 mach_voucher_attr_content_size_t bits_size
= _voucher_bits_size(0);
401 recipes_size
+= bits_size
;
402 recipes
= alloca(recipes_size
);
403 _voucher_recipes_init(recipes
, bits_size
);
405 _voucher_recipes_base(recipes
).previous_voucher
= kvb
;
406 *_voucher_recipes_priority(recipes
) = (_voucher_priority_t
)priority
;
407 kr
= _voucher_create_mach_voucher(recipes
, recipes_size
, &kv
);
408 if (dispatch_assume_zero(kr
) || !kv
){
409 return MACH_VOUCHER_NULL
;
411 _dispatch_kvoucher_debug("create with priority from voucher[%p]", kv
,
417 _voucher_create_with_mach_voucher(mach_voucher_t kv
)
419 if (!kv
) return NULL
;
422 mach_voucher_attr_recipe_t vr
;
424 mach_voucher_attr_recipe_size_t kvr_size
= 0;
425 const mach_voucher_attr_recipe_data_t redeem_recipe
[] = {
427 .key
= MACH_VOUCHER_ATTR_KEY_ALL
,
428 .command
= MACH_VOUCHER_ATTR_COPY
,
429 .previous_voucher
= kv
,
431 #if VOUCHER_USE_ATTR_BANK
433 .key
= MACH_VOUCHER_ATTR_KEY_BANK
,
434 .command
= MACH_VOUCHER_ATTR_REDEEM
,
438 kr
= _voucher_create_mach_voucher(redeem_recipe
, sizeof(redeem_recipe
),
440 if (!dispatch_assume_zero(kr
)) {
441 _voucher_dealloc_mach_voucher(kv
);
443 _dispatch_voucher_debug_machport(kv
);
446 voucher_t v
= _voucher_find_and_retain(rkv
);
448 _dispatch_voucher_debug("kvoucher[0x%08x] find with 0x%08x", v
, rkv
,kv
);
449 _voucher_dealloc_mach_voucher(rkv
);
452 vr_size
= sizeof(*vr
) + _voucher_bits_size(_voucher_max_activities
);
453 vr
= alloca(vr_size
);
455 kvr_size
= (mach_voucher_attr_recipe_size_t
)vr_size
;
456 kr
= mach_voucher_extract_attr_recipe(rkv
,
457 MACH_VOUCHER_ATTR_KEY_USER_DATA
, (void*)vr
, &kvr_size
);
458 DISPATCH_VERIFY_MIG(kr
);
459 if (dispatch_assume_zero(kr
)) kvr_size
= 0;
461 mach_voucher_attr_content_size_t content_size
= vr
->content_size
;
462 uint8_t *content
= vr
->content
;
463 bool valid
= false, has_priority
= false;
464 unsigned int activities
= 0;
465 if (kvr_size
>= sizeof(*vr
) + sizeof(_voucher_magic_t
)) {
466 valid
= (*(_voucher_magic_t
*)content
== _voucher_magic_v1
);
467 content
+= sizeof(_voucher_magic_t
);
468 content_size
-= sizeof(_voucher_magic_t
);
471 has_priority
= (content_size
>= sizeof(_voucher_priority_t
));
472 activities
= has_priority
? (content_size
- sizeof(_voucher_priority_t
))
473 / sizeof(voucher_activity_id_t
) : 0;
475 pthread_priority_t priority
= 0;
477 priority
= (pthread_priority_t
)*(_voucher_priority_t
*)content
;
478 content
+= sizeof(_voucher_priority_t
);
479 content_size
-= sizeof(_voucher_priority_t
);
481 voucher_activity_id_t va_id
= 0, va_base_id
= 0;
482 _voucher_activity_t act
= NULL
;
483 _voucher_atm_t vatm
= NULL
;
485 va_id
= *(voucher_activity_id_t
*)content
;
486 act
= _voucher_activity_copy_from_mach_voucher(rkv
, va_id
);
487 if (!act
&& _voucher_activity_default
) {
489 // default to _voucher_activity_default base activity
490 va_base_id
= _voucher_activity_default
->va_id
;
491 } else if (act
&& act
->va_id
!= va_id
) {
493 va_base_id
= act
->va_id
;
496 vatm
= _voucher_atm_retain(act
->va_atm
);
499 v
= _voucher_alloc(activities
, priority
, 0);
502 voucher_activity_id_t
*activity_ids
= _voucher_activity_ids(v
);
503 if (activities
&& va_base_id
) {
504 *activity_ids
++ = va_base_id
;
508 memcpy(activity_ids
, content
, content_size
);
510 v
->v_ipc_kvoucher
= v
->v_kvoucher
= rkv
;
512 _dispatch_voucher_debug("kvoucher[0x%08x] create with 0x%08x", v
, rkv
, kv
);
517 _voucher_create_with_priority_and_mach_voucher(voucher_t ov
,
518 pthread_priority_t priority
, mach_voucher_t kv
)
520 if (priority
== _voucher_get_priority(ov
)) {
521 if (kv
) _voucher_dealloc_mach_voucher(kv
);
522 return ov
? _voucher_retain(ov
) : NULL
;
524 voucher_t v
= _voucher_find_and_retain(kv
);
526 _dispatch_voucher_debug("kvoucher[0x%08x] find", v
, kv
);
527 _voucher_dealloc_mach_voucher(kv
);
530 unsigned int activities
= ov
? ov
->v_activities
: 0;
531 mach_voucher_attr_recipe_size_t extra
= ov
? _voucher_extra_size(ov
) : 0;
532 v
= _voucher_alloc(activities
, priority
, extra
);
534 memcpy(_voucher_extra_recipes(v
), _voucher_extra_recipes(ov
), extra
);
537 if (ov
->v_activity
) {
538 v
->v_activity
= _voucher_activity_retain(ov
->v_activity
);
539 v
->v_atm
= _voucher_atm_retain(ov
->v_atm
);
541 memcpy(_voucher_activity_ids(v
), _voucher_activity_ids(ov
),
542 activities
* sizeof(voucher_activity_id_t
));
545 v
->v_ipc_kvoucher
= v
->v_kvoucher
= kv
;
547 _dispatch_voucher_debug("kvoucher[0x%08x] create with priority from "
548 "voucher[%p]", v
, kv
, ov
);
549 _dispatch_voucher_debug_machport(kv
);
550 } else if (ov
&& ov
->v_kvoucher
) {
551 voucher_t kvb
= ov
->v_kvbase
? ov
->v_kvbase
: ov
;
552 v
->v_kvbase
= _voucher_retain(kvb
);
553 v
->v_kvoucher
= kvb
->v_kvoucher
;
559 _voucher_create_without_importance(voucher_t ov
)
561 // Nothing to do unless the old voucher has a kernel voucher. If it
562 // doesn't, it can't have any importance, now or in the future.
563 if (!ov
) return NULL
;
564 // TODO: 17487167: track presence of importance attribute
565 if (!ov
->v_kvoucher
) return _voucher_retain(ov
);
567 mach_voucher_t kv
, okv
;
568 // Copy kernel voucher, removing importance.
569 okv
= ov
->v_ipc_kvoucher
? ov
->v_ipc_kvoucher
: ov
->v_kvoucher
;
570 const mach_voucher_attr_recipe_data_t importance_remove_recipe
[] = {
572 .key
= MACH_VOUCHER_ATTR_KEY_ALL
,
573 .command
= MACH_VOUCHER_ATTR_COPY
,
574 .previous_voucher
= okv
,
577 .key
= MACH_VOUCHER_ATTR_KEY_IMPORTANCE
,
578 .command
= MACH_VOUCHER_ATTR_REMOVE
,
581 kr
= _voucher_create_mach_voucher(importance_remove_recipe
,
582 sizeof(importance_remove_recipe
), &kv
);
583 if (dispatch_assume_zero(kr
) || !kv
){
584 if (ov
->v_ipc_kvoucher
) return NULL
;
585 kv
= MACH_VOUCHER_NULL
;
588 _voucher_dealloc_mach_voucher(kv
);
589 return _voucher_retain(ov
);
591 voucher_t v
= _voucher_find_and_retain(kv
);
592 if (v
&& ov
->v_ipc_kvoucher
) {
593 _dispatch_voucher_debug("kvoucher[0x%08x] find without importance "
594 "from voucher[%p]", v
, kv
, ov
);
595 _voucher_dealloc_mach_voucher(kv
);
598 voucher_t kvbase
= v
;
599 // Copy userspace contents
600 unsigned int activities
= ov
->v_activities
;
601 pthread_priority_t priority
= _voucher_get_priority(ov
);
602 mach_voucher_attr_recipe_size_t extra
= _voucher_extra_size(ov
);
603 v
= _voucher_alloc(activities
, priority
, extra
);
605 memcpy(_voucher_extra_recipes(v
), _voucher_extra_recipes(ov
), extra
);
608 if (ov
->v_activity
) {
609 v
->v_activity
= _voucher_activity_retain(ov
->v_activity
);
610 v
->v_atm
= _voucher_atm_retain(ov
->v_atm
);
612 memcpy(_voucher_activity_ids(v
), _voucher_activity_ids(ov
),
613 activities
* sizeof(voucher_activity_id_t
));
616 if (ov
->v_ipc_kvoucher
) {
617 v
->v_ipc_kvoucher
= kv
;
620 v
->v_kvbase
= kvbase
;
621 _voucher_dealloc_mach_voucher(kv
); // borrow base reference
624 _dispatch_voucher_debug("kvoucher[0x%08x] create without importance "
625 "from voucher[%p]", v
, kv
, ov
);
631 _voucher_create_accounting_voucher(voucher_t ov
)
633 // Nothing to do unless the old voucher has a kernel voucher. If it does
634 // doesn't, it can't have any accounting attributes.
635 if (!ov
|| !ov
->v_kvoucher
) return NULL
;
636 kern_return_t kr
= KERN_SUCCESS
;
637 mach_voucher_t okv
, kv
= MACH_VOUCHER_NULL
;
638 okv
= ov
->v_ipc_kvoucher
? ov
->v_ipc_kvoucher
: ov
->v_kvoucher
;
639 #if VOUCHER_USE_ATTR_BANK
640 const mach_voucher_attr_recipe_data_t accounting_copy_recipe
= {
641 .key
= MACH_VOUCHER_ATTR_KEY_BANK
,
642 .command
= MACH_VOUCHER_ATTR_COPY
,
643 .previous_voucher
= okv
,
645 kr
= _voucher_create_mach_voucher(&accounting_copy_recipe
,
646 sizeof(accounting_copy_recipe
), &kv
);
648 if (dispatch_assume_zero(kr
) || !kv
){
651 voucher_t v
= _voucher_find_and_retain(kv
);
653 _dispatch_voucher_debug("kvoucher[0x%08x] find accounting voucher "
654 "from voucher[%p]", v
, kv
, ov
);
655 _voucher_dealloc_mach_voucher(kv
);
658 v
= _voucher_alloc(0, 0, 0);
659 v
->v_ipc_kvoucher
= v
->v_kvoucher
= kv
;
661 v
->v_kvbase
= _voucher_retain(ov
);
662 _voucher_dealloc_mach_voucher(kv
); // borrow base reference
665 _dispatch_voucher_debug("kvoucher[0x%08x] create accounting voucher "
666 "from voucher[%p]", v
, kv
, ov
);
671 voucher_create_with_mach_msg(mach_msg_header_t
*msg
)
673 voucher_t v
= _voucher_create_with_mach_voucher(_voucher_mach_msg_get(msg
));
674 _voucher_activity_trace_msg(v
, msg
, receive
);
678 #ifndef MACH_VOUCHER_IMPORTANCE_ATTR_DROP_EXTERNAL
679 #define MACH_VOUCHER_IMPORTANCE_ATTR_DROP_EXTERNAL 2
683 voucher_decrement_importance_count4CF(voucher_t v
)
685 if (!v
|| !v
->v_kvoucher
) return;
686 // TODO: 17487167: track presence of importance attribute
688 mach_voucher_t kv
= v
->v_ipc_kvoucher
? v
->v_ipc_kvoucher
: v
->v_kvoucher
;
690 mach_voucher_attr_content_t kvc_in
= (mach_voucher_attr_content_t
)&dec
;
691 mach_voucher_attr_content_size_t kvc_in_size
= sizeof(dec
);
692 mach_voucher_attr_content_t kvc_out
= NULL
;
693 mach_voucher_attr_content_size_t kvc_out_size
= 0;
695 uint32_t count
= UINT32_MAX
;
696 kvc_out
= (mach_voucher_attr_content_t
)&count
;
697 kvc_out_size
= sizeof(count
);
699 kr
= mach_voucher_attr_command(kv
, MACH_VOUCHER_ATTR_KEY_IMPORTANCE
,
700 MACH_VOUCHER_IMPORTANCE_ATTR_DROP_EXTERNAL
, kvc_in
, kvc_in_size
,
701 kvc_out
, &kvc_out_size
);
702 DISPATCH_VERIFY_MIG(kr
);
704 _dispatch_voucher_debug("kvoucher[0x%08x] decrement importance count to %u:"
705 " %s - 0x%x", v
, kv
, count
, mach_error_string(kr
), kr
);
707 if (kr
!= KERN_INVALID_ARGUMENT
&&
708 dispatch_assume_zero(kr
) == KERN_FAILURE
) {
709 // TODO: 17487167: skip KERN_INVALID_ARGUMENT check
710 DISPATCH_CLIENT_CRASH("Voucher importance count underflow");
714 #if VOUCHER_ENABLE_GET_MACH_VOUCHER
716 voucher_get_mach_voucher(voucher_t voucher
)
718 return _voucher_get_mach_voucher(voucher
);
723 _voucher_xref_dispose(voucher_t voucher
)
725 _dispatch_voucher_debug("xref_dispose", voucher
);
726 _voucher_remove(voucher
);
727 return _os_object_release_internal_inline((_os_object_t
)voucher
);
731 _voucher_dispose(voucher_t voucher
)
733 _dispatch_voucher_debug("dispose", voucher
);
734 if (slowpath(_TAILQ_IS_ENQUEUED(voucher
, v_list
))) {
735 _dispatch_voucher_debug("corruption", voucher
);
736 DISPATCH_CRASH("Voucher corruption");
738 voucher
->v_list
.tqe_next
= DISPATCH_OBJECT_LISTLESS
;
739 if (voucher
->v_ipc_kvoucher
) {
740 if (voucher
->v_ipc_kvoucher
!= voucher
->v_kvoucher
) {
741 _voucher_dealloc_mach_voucher(voucher
->v_ipc_kvoucher
);
743 voucher
->v_ipc_kvoucher
= MACH_VOUCHER_NULL
;
745 if (voucher
->v_kvoucher
) {
746 if (!voucher
->v_kvbase
) {
747 _voucher_dealloc_mach_voucher(voucher
->v_kvoucher
);
749 voucher
->v_kvoucher
= MACH_VOUCHER_NULL
;
751 if (voucher
->v_kvbase
) {
752 _voucher_release(voucher
->v_kvbase
);
753 voucher
->v_kvbase
= NULL
;
755 if (voucher
->v_activity
) {
756 _voucher_activity_release(voucher
->v_activity
);
757 voucher
->v_activity
= NULL
;
759 if (voucher
->v_atm
) {
760 _voucher_atm_release(voucher
->v_atm
);
761 voucher
->v_atm
= NULL
;
763 voucher
->v_has_priority
= 0;
764 voucher
->v_activities
= 0;
765 #if VOUCHER_ENABLE_RECIPE_OBJECTS
766 voucher
->v_recipe_extra_size
= 0;
767 voucher
->v_recipe_extra_offset
= 0;
769 return _os_object_dealloc((_os_object_t
)voucher
);
773 _voucher_atfork_child(void)
775 _voucher_activity_atfork_child();
776 _dispatch_thread_setspecific(dispatch_voucher_key
, NULL
);
777 _voucher_task_mach_voucher_pred
= 0;
778 _voucher_task_mach_voucher
= MACH_VOUCHER_NULL
;
780 // TODO: voucher/activity inheritance on fork ?
784 #pragma mark _voucher_init
787 voucher_mach_msg_set(mach_msg_header_t
*msg
)
789 voucher_t v
= _voucher_get();
790 bool clear_voucher
= _voucher_mach_msg_set(msg
, v
);
791 if (clear_voucher
) _voucher_activity_trace_msg(v
, msg
, send
);
792 return clear_voucher
;
796 voucher_mach_msg_clear(mach_msg_header_t
*msg
)
798 (void)_voucher_mach_msg_clear(msg
, false);
801 voucher_mach_msg_state_t
802 voucher_mach_msg_adopt(mach_msg_header_t
*msg
)
804 mach_voucher_t kv
= _voucher_mach_msg_get(msg
);
805 if (!kv
) return VOUCHER_MACH_MSG_STATE_UNCHANGED
;
806 voucher_t v
= _voucher_create_with_mach_voucher(kv
);
807 _voucher_activity_trace_msg(v
, msg
, receive
);
808 return (voucher_mach_msg_state_t
)_voucher_adopt(v
);
812 voucher_mach_msg_revert(voucher_mach_msg_state_t state
)
814 if (state
== VOUCHER_MACH_MSG_STATE_UNCHANGED
) return;
815 _voucher_replace((voucher_t
)state
);
818 #if DISPATCH_USE_LIBKERNEL_VOUCHER_INIT
819 #include <_libkernel_init.h>
821 static const struct _libkernel_voucher_functions _voucher_libkernel_functions
=
824 .voucher_mach_msg_set
= voucher_mach_msg_set
,
825 .voucher_mach_msg_clear
= voucher_mach_msg_clear
,
826 .voucher_mach_msg_adopt
= voucher_mach_msg_adopt
,
827 .voucher_mach_msg_revert
= voucher_mach_msg_revert
,
831 _voucher_libkernel_init(void)
833 kern_return_t kr
= __libkernel_voucher_init(&_voucher_libkernel_functions
);
834 dispatch_assert(!kr
);
837 #define _voucher_libkernel_init()
843 _voucher_libkernel_init();
846 for (i
= 0; i
< VL_HASH_SIZE
; i
++) {
847 TAILQ_INIT(&_vouchers
[i
]);
849 voucher_activity_mode_t mode
;
850 mode
= DISPATCH_DEBUG
? voucher_activity_mode_debug
851 : voucher_activity_mode_release
;
852 e
= getenv("OS_ACTIVITY_MODE");
854 if (strcmp(e
, "release") == 0) {
855 mode
= voucher_activity_mode_release
;
856 } else if (strcmp(e
, "debug") == 0) {
857 mode
= voucher_activity_mode_debug
;
858 } else if (strcmp(e
, "stream") == 0) {
859 mode
= voucher_activity_mode_stream
;
860 } else if (strcmp(e
, "disable") == 0) {
861 mode
= voucher_activity_mode_disable
;
864 _voucher_activity_mode
= mode
;
865 if (_voucher_activity_disabled()) return;
867 // default task activity
868 bool default_task_activity
= DISPATCH_DEBUG
;
869 e
= getenv("LIBDISPATCH_DEFAULT_TASK_ACTIVITY");
870 if (e
) default_task_activity
= atoi(e
);
871 if (default_task_activity
) {
872 (void)voucher_activity_start(_voucher_activity_trace_id_release
, 0);
877 #pragma mark _voucher_activity_lock_s
879 DISPATCH_ALWAYS_INLINE
881 _voucher_activity_lock_init(_voucher_activity_lock_s
*lock
) {
882 static const os_lock_handoff_s _os_lock_handoff_init
= OS_LOCK_HANDOFF_INIT
;
883 *lock
= _os_lock_handoff_init
;
886 DISPATCH_ALWAYS_INLINE
888 _voucher_activity_lock_lock(_voucher_activity_lock_s
*lock
) {
889 return os_lock_lock(lock
);
892 DISPATCH_ALWAYS_INLINE
894 _voucher_activity_lock_unlock(_voucher_activity_lock_s
*lock
) {
895 return os_lock_unlock(lock
);
899 #pragma mark _voucher_activity_heap
901 #if __has_extension(c_static_assert)
902 _Static_assert(sizeof(struct _voucher_activity_tracepoint_s
) == 64,
903 "Tracepoint too large");
904 _Static_assert(sizeof(struct _voucher_activity_buffer_header_s
) <=
905 sizeof(struct _voucher_activity_tracepoint_s
),
906 "Buffer header too large");
908 _Static_assert(offsetof(struct _voucher_activity_s
, va_buffers_lock
) % 64 == 0,
909 "Bad activity padding");
910 _Static_assert(sizeof(struct _voucher_atm_s
) <= 128,
913 _Static_assert(sizeof(struct _voucher_atm_s
) <= 64,
916 _Static_assert(sizeof(_voucher_activity_buffer_t
) ==
917 sizeof(struct {char x
[_voucher_activity_buffer_size
];}),
919 _Static_assert(sizeof(struct _voucher_activity_metadata_s
) <=
920 sizeof(struct _voucher_activity_metadata_opaque_s
),
921 "Metadata too large");
922 _Static_assert(sizeof(_voucher_activity_bitmap_t
) % 64 == 0,
923 "Bad metadata bitmap size");
926 #define va_buffers_lock(va) (&(va)->va_buffers_lock)
927 #define vatm_activities(vatm) (&(vatm)->vatm_activities)
928 #define vam_atms_lock() (&_voucher_activity_heap->vam_atms_lock)
929 #define vam_activities_lock() (&_voucher_activity_heap->vam_activities_lock)
930 #define vam_atms(hash) (&_voucher_activity_heap->vam_atms[hash])
931 #define vam_activities(hash) (&_voucher_activity_heap->vam_activities[hash])
932 #define vam_buffer_bitmap() (_voucher_activity_heap->vam_buffer_bitmap)
933 #define vam_pressure_locked_bitmap() \
934 (_voucher_activity_heap->vam_pressure_locked_bitmap)
935 #define vam_buffer(i) ((void*)((char*)_voucher_activity_heap + \
936 (i) * _voucher_activity_buffer_size))
938 static _voucher_activity_t
_voucher_activity_create_with_atm(
939 _voucher_atm_t vatm
, voucher_activity_id_t va_id
,
940 voucher_activity_trace_id_t trace_id
, uint64_t location
,
941 _voucher_activity_buffer_header_t buffer
);
942 static _voucher_atm_t
_voucher_atm_create(mach_voucher_t kv
, atm_aid_t atm_id
);
943 static void _voucher_activity_firehose_wait(_voucher_activity_t act
,
944 _voucher_activity_buffer_header_t buffer
);
946 DISPATCH_ALWAYS_INLINE
947 static inline uint32_t
948 _voucher_default_activity_buffer_limit()
950 #if 0 // FIXME: tune buffer chain sizes
951 switch (_voucher_activity_mode
) {
952 case voucher_activity_mode_debug
:
953 case voucher_activity_mode_stream
:
954 // High-profile modes: Default activity can use 1/32nd of the heap
955 // (twice as much as non-default activities)
956 return MAX(_voucher_activity_buffers_per_heap
/ 32, 3) - 1;
959 // Low-profile modes: Default activity can use a total of 4 buffers.
963 DISPATCH_ALWAYS_INLINE
964 static inline uint32_t
965 _voucher_activity_buffer_limit()
967 #if 0 // FIXME: tune buffer chain sizes
968 switch (_voucher_activity_mode
) {
969 case voucher_activity_mode_debug
:
970 case voucher_activity_mode_stream
:
971 // High-profile modes: 64 activities, each of which can use 1/64th
972 // of the entire heap.
973 return MAX(_voucher_activity_buffers_per_heap
/ 64, 2) - 1;
976 // Low-profile modes: Each activity can use a total of 2 buffers.
980 // The two functions above return the number of *additional* buffers activities
981 // may allocate, hence the gymnastics with - 1.
983 DISPATCH_ALWAYS_INLINE
984 static inline uint32_t
985 _voucher_heap_buffer_limit()
987 switch (_voucher_activity_mode
) {
988 case voucher_activity_mode_debug
:
989 case voucher_activity_mode_stream
:
990 // High-profile modes: Use it all.
991 return _voucher_activity_buffers_per_heap
;
993 #if TARGET_OS_EMBEDDED
994 // Low-profile modes: 3 activities, each of which can use 2Â buffers;
995 // plus the default activity, which can use 3; plus 3 buffers of overhead.
998 // Low-profile modes: 13 activities, each of which can use 4 buffers;
999 // plus the default activity, which can use 8; plus 3 buffers of overhead.
1004 #define NO_BITS_WERE_UNSET (UINT_MAX)
1006 DISPATCH_ALWAYS_INLINE
1007 static inline size_t
1008 _voucher_activity_bitmap_set_first_unset_bit_upto(
1009 _voucher_activity_bitmap_t
volatile bitmap
,
1010 unsigned int max_index
)
1012 dispatch_assert(max_index
!= 0);
1013 unsigned int index
= NO_BITS_WERE_UNSET
, max_map
, max_bit
, i
;
1014 max_map
= max_index
/ _voucher_activity_bits_per_bitmap_base_t
;
1015 max_map
= MIN(max_map
, _voucher_activity_bitmaps_per_heap
- 1);
1016 max_bit
= max_index
% _voucher_activity_bits_per_bitmap_base_t
;
1017 for (i
= 0; i
< max_map
; i
++) {
1018 index
= dispatch_atomic_set_first_bit(&bitmap
[i
], UINT_MAX
);
1019 if (fastpath(index
< NO_BITS_WERE_UNSET
)) {
1020 return index
+ i
* _voucher_activity_bits_per_bitmap_base_t
;
1023 index
= dispatch_atomic_set_first_bit(&bitmap
[i
], max_bit
);
1024 if (fastpath(index
< NO_BITS_WERE_UNSET
)) {
1025 return index
+ i
* _voucher_activity_bits_per_bitmap_base_t
;
1030 DISPATCH_ALWAYS_INLINE DISPATCH_UNUSED
1031 static inline size_t
1032 _voucher_activity_bitmap_set_first_unset_bit(
1033 _voucher_activity_bitmap_t
volatile bitmap
)
1035 return _voucher_activity_bitmap_set_first_unset_bit_upto(bitmap
, UINT_MAX
);
1038 DISPATCH_ALWAYS_INLINE
1040 _voucher_activity_bitmap_clear_bit(
1041 _voucher_activity_bitmap_t
volatile bitmap
, size_t index
)
1043 size_t i
= index
/ _voucher_activity_bits_per_bitmap_base_t
;
1044 _voucher_activity_bitmap_base_t mask
= ((typeof(mask
))1) <<
1045 (index
% _voucher_activity_bits_per_bitmap_base_t
);
1046 if (slowpath((bitmap
[i
] & mask
) == 0)) {
1047 DISPATCH_CRASH("Corruption: failed to clear bit exclusively");
1049 (void)dispatch_atomic_and(&bitmap
[i
], ~mask
, release
);
1052 _voucher_activity_metadata_t _voucher_activity_heap
;
1053 static dispatch_once_t _voucher_activity_heap_pred
;
1056 _voucher_activity_heap_init(void *ctxt DISPATCH_UNUSED
)
1058 if (_voucher_activity_disabled()) return;
1060 mach_vm_size_t vm_size
= _voucher_activity_buffer_size
*
1061 _voucher_activity_buffers_per_heap
;
1062 mach_vm_address_t vm_addr
= vm_page_size
;
1063 while (slowpath(kr
= mach_vm_map(mach_task_self(), &vm_addr
, vm_size
,
1064 0, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_GENEALOGY
),
1065 MEMORY_OBJECT_NULL
, 0, FALSE
, VM_PROT_DEFAULT
, VM_PROT_ALL
,
1066 VM_INHERIT_NONE
))) {
1067 if (kr
!= KERN_NO_SPACE
) {
1068 (void)dispatch_assume_zero(kr
);
1069 _voucher_activity_mode
= voucher_activity_mode_disable
;
1072 _dispatch_temporary_resource_shortage();
1073 vm_addr
= vm_page_size
;
1075 _voucher_activity_metadata_t heap
;
1076 task_trace_memory_info_data_t trace_memory_info
= {
1077 .user_memory_address
= vm_addr
,
1078 .buffer_size
= vm_size
,
1080 kr
= task_set_info(mach_task_self(), TASK_TRACE_MEMORY_INFO
,
1081 (task_info_t
)&trace_memory_info
, TASK_TRACE_MEMORY_INFO_COUNT
);
1082 DISPATCH_VERIFY_MIG(kr
);
1084 if (kr
!= KERN_NOT_SUPPORTED
) (void)dispatch_assume_zero(kr
);
1085 kr
= mach_vm_deallocate(mach_task_self(), vm_addr
, vm_size
);
1086 (void)dispatch_assume_zero(kr
);
1087 _voucher_activity_mode
= voucher_activity_mode_disable
;
1090 heap
= (void*)vm_addr
;
1091 heap
->vasm_baseaddr
= (void*)vm_addr
;
1092 heap
->vam_buffer_bitmap
[0] = 0x7; // first three buffers are reserved
1094 for (i
= 0; i
< _voucher_activity_hash_size
; i
++) {
1095 TAILQ_INIT(&heap
->vam_activities
[i
]);
1096 TAILQ_INIT(&heap
->vam_atms
[i
]);
1098 _voucher_activity_lock_init(&heap
->vam_atms_lock
);
1099 _voucher_activity_lock_init(&heap
->vam_activities_lock
);
1100 _voucher_activity_heap
= heap
;
1102 _voucher_atm_t vatm
= _voucher_atm_create(0, 0);
1103 dispatch_assert(vatm
->vatm_kvoucher
);
1104 _voucher_atm_retain(vatm
);
1106 _voucher_activity_buffer_header_t buffer
= vam_buffer(2); // reserved index
1107 // consumes vatm reference:
1108 _voucher_activity_t va
= _voucher_activity_create_with_atm(vatm
, 0, 0, 0,
1110 dispatch_assert(va
);
1111 va
->va_buffer_limit
= _voucher_default_activity_buffer_limit();
1112 _voucher_activity_default
= va
;
1113 _voucher_task_atm
= vatm
;
1117 _voucher_activity_atfork_child(void)
1119 _voucher_activity_heap_pred
= 0;
1120 _voucher_activity_heap
= NULL
; // activity heap is VM_INHERIT_NONE
1121 _voucher_activity_default
= NULL
;
1125 voucher_activity_get_metadata_buffer(size_t *length
)
1127 dispatch_once_f(&_voucher_activity_heap_pred
, NULL
,
1128 _voucher_activity_heap_init
);
1129 if (_voucher_activity_disabled()) {
1133 *length
= sizeof(_voucher_activity_heap
->vam_client_metadata
);
1134 return _voucher_activity_heap
->vam_client_metadata
;
1137 static _voucher_activity_buffer_hook_t _voucher_activity_buffer_hook
;
1140 voucher_activity_buffer_hook_install_4libtrace(
1141 _voucher_activity_buffer_hook_t hook
)
1143 if (dispatch_atomic_cmpxchg(&_voucher_activity_buffer_hook
, NULL
,
1144 (void*)hook
, release
)) return;
1145 DISPATCH_CLIENT_CRASH("_voucher_activity_buffer_hook_install_4libtrace " \
1146 "called more than once");
1149 #if DISPATCH_DEBUG && DISPATCH_VOUCHER_ACTIVITY_DEBUG
1150 #define VOUCHER_ACTIVITY_BUFFER_DEBUG(reason, buffer) \
1151 _dispatch_debug("activity buffer %s (%p)", #reason, buffer)
1153 #define VOUCHER_ACTIVITY_BUFFER_DEBUG(reason, buffer)
1156 #define VOUCHER_ACTIVITY_BUFFER_HOOK_CALLOUT(reason, buffer) \
1157 if (buffer) { VOUCHER_ACTIVITY_BUFFER_DEBUG(reason, buffer); \
1158 if (slowpath(_voucher_activity_buffer_hook)) { \
1159 _voucher_activity_buffer_hook( \
1160 _voucher_activity_buffer_hook_reason_##reason, (buffer)); \
1163 DISPATCH_ALWAYS_INLINE
1164 static inline _voucher_activity_buffer_header_t
1165 _voucher_activity_heap_buffer_alloc(void)
1167 _voucher_activity_buffer_header_t buffer
= NULL
;
1169 index
= _voucher_activity_bitmap_set_first_unset_bit_upto(
1170 vam_buffer_bitmap(), _voucher_heap_buffer_limit() - 1);
1171 if (index
< NO_BITS_WERE_UNSET
) {
1172 buffer
= vam_buffer(index
);
1174 #if DISPATCH_DEBUG && DISPATCH_VOUCHER_ACTIVITY_DEBUG
1175 _dispatch_debug("activity heap alloc %zd (%p)", index
, buffer
);
1180 DISPATCH_ALWAYS_INLINE
1182 _voucher_activity_heap_buffer_free(_voucher_activity_buffer_header_t buffer
)
1184 buffer
->vabh_flags
= _voucher_activity_trace_flag_buffer_empty
;
1185 size_t index
= (size_t)((char*)buffer
- (char*)_voucher_activity_heap
) /
1186 _voucher_activity_buffer_size
;
1187 #if DISPATCH_DEBUG && DISPATCH_VOUCHER_ACTIVITY_DEBUG
1188 _dispatch_debug("activity heap free %zd (%p)", index
, buffer
);
1190 _voucher_activity_bitmap_clear_bit(vam_buffer_bitmap(), index
);
1193 #define _voucher_activity_heap_can_madvise() \
1194 (PAGE_SIZE == _voucher_activity_buffer_size) // <rdar://17445544>
1196 DISPATCH_ALWAYS_INLINE
1198 _voucher_activity_heap_madvise(size_t bitmap_num
, unsigned int start
,
1201 size_t base
= bitmap_num
* _voucher_activity_bits_per_bitmap_base_t
;
1203 #if DISPATCH_VOUCHER_ACTIVITY_DEBUG
1204 _dispatch_debug("activity heap madvise %zd (%p) -> %zd (%p)", base
+ start
,
1205 vam_buffer(base
+ start
), base
+ start
+ len
,
1206 vam_buffer(base
+ start
+ len
));
1208 dispatch_assert(!(len
* _voucher_activity_buffer_size
% vm_page_size
));
1209 const uint64_t pattern
= 0xFACEFACEFACEFACE;
1210 _voucher_activity_buffer_header_t buffer
= vam_buffer(base
+ start
);
1211 for (unsigned int i
= 0; i
< len
; i
++, buffer
++) {
1212 memset_pattern8((char*)buffer
+ sizeof(buffer
->vabh_flags
), &pattern
,
1213 _voucher_activity_buffer_size
- sizeof(buffer
->vabh_flags
));
1216 (void)dispatch_assume_zero(madvise(vam_buffer(base
+ start
),
1217 len
* _voucher_activity_buffer_size
, MADV_FREE
));
1220 DISPATCH_ALWAYS_INLINE
1222 _voucher_activity_heap_madvise_contiguous(size_t bitmap_num
,
1223 _voucher_activity_bitmap_base_t bits
)
1225 // TODO: x86 has fast ctz; arm has fast clz; haswell has fast ctz
1226 dispatch_assert(_voucher_activity_heap_can_madvise());
1229 } else if (~bits
== 0) {
1230 _voucher_activity_heap_madvise(bitmap_num
, 0,
1231 _voucher_activity_bits_per_bitmap_base_t
);
1232 } else while (bits
!= 0) {
1233 unsigned int start
= (typeof(start
))__builtin_ctzl(bits
), len
;
1234 typeof(bits
) inverse
= ~bits
>> start
;
1236 len
= (typeof(len
))__builtin_ctzl(inverse
);
1238 len
= _voucher_activity_bits_per_bitmap_base_t
- start
;
1240 typeof(bits
) mask
= ((((typeof(bits
))1) << len
) - 1) << start
;
1242 _voucher_activity_heap_madvise(bitmap_num
, start
, len
);
1247 _voucher_activity_heap_pressure_warn(void)
1249 if (!_voucher_activity_heap_can_madvise() || !_voucher_activity_heap
) {
1252 volatile _voucher_activity_bitmap_base_t
*bitmap
, *pressure_locked_bitmap
;
1253 bitmap
= vam_buffer_bitmap();
1254 pressure_locked_bitmap
= vam_pressure_locked_bitmap();
1256 // number of bitmaps needed to map the current buffer limit =
1257 // ceil(buffer limit / bits per bitmap)
1258 size_t nbuffers
= _voucher_heap_buffer_limit();
1259 size_t nbitmaps_quot
= nbuffers
/ _voucher_activity_bits_per_bitmap_base_t
;
1260 size_t nbitmaps_rem
= nbuffers
% _voucher_activity_bits_per_bitmap_base_t
;
1261 size_t nbitmaps
= nbitmaps_quot
+ ((nbitmaps_rem
== 0) ? 0 : 1);
1263 for (size_t i
= 0; i
< nbitmaps
; i
++) {
1264 _voucher_activity_bitmap_base_t got_bits
;
1265 got_bits
= dispatch_atomic_or_orig(&bitmap
[i
], ~((typeof(bitmap
[i
]))0),
1267 got_bits
= ~got_bits
; // Now 1 means 'acquired this one, madvise it'
1268 _voucher_activity_heap_madvise_contiguous(i
, got_bits
);
1269 pressure_locked_bitmap
[i
] |= got_bits
;
1274 _voucher_activity_heap_pressure_normal(void)
1276 if (!_voucher_activity_heap_can_madvise() || !_voucher_activity_heap
) {
1279 volatile _voucher_activity_bitmap_base_t
*bitmap
, *pressure_locked_bitmap
;
1280 bitmap
= vam_buffer_bitmap();
1281 pressure_locked_bitmap
= vam_pressure_locked_bitmap();
1282 for (size_t i
= 0; i
< _voucher_activity_bitmaps_per_heap
; i
++) {
1283 _voucher_activity_bitmap_base_t free_bits
= pressure_locked_bitmap
[i
];
1284 pressure_locked_bitmap
[i
] = 0;
1285 if (free_bits
!= 0) {
1286 (void)dispatch_atomic_and(&bitmap
[i
], ~free_bits
, release
);
1291 DISPATCH_ALWAYS_INLINE
1293 _voucher_activity_buffer_init(_voucher_activity_t act
,
1294 _voucher_activity_buffer_header_t buffer
, bool initial
)
1296 _voucher_activity_tracepoint_t vat
= (_voucher_activity_tracepoint_t
)buffer
;
1297 _voucher_activity_tracepoint_init_with_id(vat
, act
->va_trace_id
,
1298 act
->va_location
, !initial
);
1299 buffer
->vabh_flags
= _voucher_activity_trace_flag_buffer_header
|
1300 _voucher_activity_trace_flag_activity
|
1301 (initial
? _voucher_activity_trace_flag_start
: 0);
1302 buffer
->vabh_activity_id
= act
->va_id
;
1303 buffer
->vabh_pos
.vabp_atomic_pos
= 0;
1304 buffer
->vabh_pos
.vabp_pos
.vabp_next_tracepoint_idx
= 1;
1307 static _voucher_activity_buffer_header_t
1308 _voucher_activity_buffer_alloc_slow(_voucher_activity_t act
,
1309 _voucher_activity_buffer_header_t current
)
1311 _voucher_activity_buffer_header_t buffer
;
1312 _voucher_activity_lock_lock(va_buffers_lock(act
)); // TODO: revisit locking
1313 buffer
= act
->va_current_buffer
;
1314 if (buffer
!= current
) {
1315 _voucher_activity_lock_unlock(va_buffers_lock(act
));
1318 buffer
= TAILQ_FIRST(&act
->va_buffers
);
1319 if (buffer
!= TAILQ_LAST(&act
->va_buffers
,
1320 _voucher_activity_buffer_list_s
)) {
1321 TAILQ_REMOVE(&act
->va_buffers
, buffer
, vabh_list
);
1322 TAILQ_INSERT_TAIL(&act
->va_buffers
, buffer
, vabh_list
);
1324 _voucher_activity_lock_unlock(va_buffers_lock(act
));
1325 if (_voucher_activity_buffer_is_full(buffer
)) {
1326 _voucher_activity_firehose_wait(act
, buffer
);
1328 if (dispatch_atomic_cmpxchgv2o(act
, va_current_buffer
, current
, buffer
,
1329 ¤t
, release
)) {
1330 if (_voucher_activity_buffer_mark_full(current
)) {
1331 _voucher_activity_firehose_push(act
, current
);
1333 _dispatch_voucher_activity_debug("buffer reuse %p", act
, buffer
);
1340 static _voucher_activity_buffer_header_t
1341 _voucher_activity_buffer_alloc(_voucher_activity_t act
,
1342 _voucher_activity_buffer_header_t current
)
1344 _voucher_activity_buffer_header_t buffer
= NULL
;
1345 if (act
->va_buffer_count
< act
->va_buffer_limit
) {
1346 buffer
= _voucher_activity_heap_buffer_alloc();
1347 if (buffer
&& dispatch_atomic_inc2o(act
, va_buffer_count
, relaxed
) >
1348 act
->va_buffer_limit
) {
1349 dispatch_atomic_dec2o(act
, va_buffer_count
, relaxed
);
1350 _voucher_activity_heap_buffer_free(buffer
);
1354 if (!buffer
) return _voucher_activity_buffer_alloc_slow(act
, current
);
1355 _voucher_activity_buffer_init(act
, buffer
, false);
1356 if (dispatch_atomic_cmpxchgv2o(act
, va_current_buffer
, current
, buffer
,
1357 ¤t
, release
)) {
1358 _voucher_activity_lock_lock(va_buffers_lock(act
));
1359 TAILQ_INSERT_TAIL(&act
->va_buffers
, buffer
, vabh_list
);
1360 _voucher_activity_lock_unlock(va_buffers_lock(act
));
1361 if (_voucher_activity_buffer_mark_full(current
)) {
1362 _voucher_activity_firehose_push(act
, current
);
1364 _dispatch_voucher_activity_debug("buffer alloc %p", act
, buffer
);
1366 dispatch_atomic_dec2o(act
, va_buffer_count
, relaxed
);
1367 _voucher_activity_heap_buffer_free(buffer
);
1374 #pragma mark _voucher_activity_t
1376 #define _voucher_activity_ordered_insert(_act, head, field) do { \
1377 typeof(_act) _vai; \
1378 TAILQ_FOREACH(_vai, (head), field) { \
1379 if (_act->va_id < _vai->va_id) break; \
1382 TAILQ_INSERT_BEFORE(_vai, _act, field); \
1384 TAILQ_INSERT_TAIL((head), _act, field); \
1387 static void _voucher_activity_dispose(_voucher_activity_t act
);
1388 static _voucher_atm_t
_voucher_atm_copy(atm_aid_t atm_id
);
1389 static inline void _voucher_atm_release(_voucher_atm_t vatm
);
1390 static atm_aid_t
_voucher_mach_voucher_get_atm_id(mach_voucher_t kv
);
1392 DISPATCH_ALWAYS_INLINE
1394 _voucher_activity_try_retain(_voucher_activity_t act
)
1396 // not using _os_object_refcnt* because we don't need barriers:
1397 // activities are immutable and are in a hash table with a lock
1398 int use_cnt
= dispatch_atomic_inc2o(act
, va_refcnt
, relaxed
);
1399 _dispatch_voucher_activity_debug("retain -> %d", act
, use_cnt
+ 1);
1400 if (slowpath(use_cnt
< 0)) {
1401 _dispatch_voucher_activity_debug("overrelease", act
);
1402 DISPATCH_CRASH("Activity overrelease");
1407 DISPATCH_ALWAYS_INLINE
1408 static inline _voucher_activity_t
1409 _voucher_activity_retain(_voucher_activity_t act
)
1411 if (slowpath(!_voucher_activity_try_retain(act
))) {
1412 _dispatch_voucher_activity_debug("resurrection", act
);
1413 DISPATCH_CRASH("Activity resurrection");
1418 DISPATCH_ALWAYS_INLINE
1420 _voucher_activity_release(_voucher_activity_t act
)
1422 // not using _os_object_refcnt* because we don't need barriers:
1423 // activities are immutable and are in a hash table with a lock
1424 int use_cnt
= dispatch_atomic_dec2o(act
, va_refcnt
, relaxed
);
1425 _dispatch_voucher_activity_debug("release -> %d", act
, use_cnt
+ 1);
1426 if (fastpath(use_cnt
>= 0)) {
1429 if (slowpath(use_cnt
< -1)) {
1430 _dispatch_voucher_activity_debug("overrelease", act
);
1431 DISPATCH_CRASH("Activity overrelease");
1433 _voucher_activity_remove(act
);
1434 _voucher_activity_dispose(act
);
1437 static _voucher_activity_t
1438 _voucher_activity_find_and_retain(voucher_activity_id_t va_id
, uint32_t hash
)
1440 // not using _os_object_refcnt* because we don't need barriers:
1441 // activities are immutable and are in a hash table with a lock
1443 // assumes vam_activities_lock held
1444 _voucher_activity_t act
;
1445 TAILQ_FOREACH(act
, vam_activities(hash
), va_list) {
1446 if (act
->va_id
== va_id
) {
1447 if (fastpath(_voucher_activity_try_retain(act
))) {
1451 // <rdar://problem/20468375> disallow resurrection
1452 dispatch_atomic_dec2o(act
, va_refcnt
, relaxed
);
1453 _dispatch_voucher_activity_debug("undo resurrection", act
);
1459 static _voucher_activity_t
1460 _voucher_activity_copy_from_id(voucher_activity_id_t va_id
)
1462 uint32_t hash
= VACTID_HASH(va_id
);
1463 _voucher_activity_lock_lock(vam_activities_lock());
1464 _voucher_activity_t act
= _voucher_activity_find_and_retain(va_id
, hash
);
1466 _dispatch_voucher_activity_debug("copy from id 0x%llx", act
, va_id
);
1468 _voucher_activity_lock_unlock(vam_activities_lock());
1472 static _voucher_activity_t
1473 _voucher_activity_try_insert(_voucher_activity_t act_new
)
1475 voucher_activity_id_t va_id
= act_new
->va_id
;
1476 uint32_t hash
= VACTID_HASH(va_id
);
1477 _voucher_activity_lock_lock(vam_activities_lock());
1478 _voucher_activity_t act
= _voucher_activity_find_and_retain(va_id
, hash
);
1480 _dispatch_voucher_activity_debug("try insert: failed (%p)", act
,act_new
);
1482 if (slowpath(_TAILQ_IS_ENQUEUED(act_new
, va_list))) {
1483 _dispatch_voucher_activity_debug("corruption", act_new
);
1484 DISPATCH_CRASH("Activity corruption");
1486 TAILQ_INSERT_TAIL(vam_activities(hash
), act_new
, va_list);
1487 _dispatch_voucher_activity_debug("try insert: succeeded", act_new
);
1489 _voucher_activity_lock_unlock(vam_activities_lock());
1494 _voucher_activity_remove(_voucher_activity_t act
)
1496 voucher_activity_id_t va_id
= act
->va_id
;
1497 uint32_t hash
= VACTID_HASH(va_id
);
1499 _voucher_activity_lock_lock(vam_activities_lock());
1500 if (slowpath(!va_id
|| !_TAILQ_IS_ENQUEUED(act
, va_list))) {
1501 _dispatch_voucher_activity_debug("corruption", act
);
1502 DISPATCH_CRASH("Activity corruption");
1504 TAILQ_REMOVE(vam_activities(hash
), act
, va_list);
1505 _TAILQ_MARK_NOT_ENQUEUED(act
, va_list);
1506 act
->va_list.tqe_next
= (void*)~0ull;
1507 _dispatch_voucher_activity_debug("remove", act
);
1508 _voucher_activity_lock_unlock(vam_activities_lock());
1511 static _voucher_activity_t
1512 _voucher_activity_create_with_atm(_voucher_atm_t vatm
,
1513 voucher_activity_id_t va_id
, voucher_activity_trace_id_t trace_id
,
1514 uint64_t location
, _voucher_activity_buffer_header_t buffer
)
1516 if (!buffer
) buffer
= _voucher_activity_heap_buffer_alloc();
1518 _dispatch_voucher_atm_debug("no buffer", vatm
);
1519 _voucher_atm_release(vatm
); // consume vatm reference
1522 _voucher_activity_t act
= _dispatch_calloc(1ul,
1523 sizeof(struct _voucher_activity_s
));
1525 act
->va_trace_id
= trace_id
? trace_id
: _voucher_activity_trace_id_release
;
1526 act
->va_location
= location
;
1527 act
->va_buffer_limit
= _voucher_activity_buffer_limit();
1528 TAILQ_INIT(&act
->va_buffers
);
1529 act
->va_current_buffer
= buffer
;
1530 act
->va_atm
= vatm
; // transfer vatm reference
1531 _voucher_activity_lock_init(va_buffers_lock(act
));
1532 if (dispatch_assume_zero(pthread_mutex_init(&act
->va_mutex
, NULL
)) ||
1533 dispatch_assume_zero(pthread_cond_init(&act
->va_cond
, NULL
))) {
1534 DISPATCH_CLIENT_CRASH("Could not initialize activity");
1536 _TAILQ_MARK_NOT_ENQUEUED(act
, va_list);
1537 _TAILQ_MARK_NOT_ENQUEUED(act
, va_atm_list
);
1538 _TAILQ_MARK_NOT_ENQUEUED(act
, va_atm_used_list
);
1540 _voucher_activity_buffer_init(act
, buffer
, true);
1541 TAILQ_INSERT_TAIL(&act
->va_buffers
, buffer
, vabh_list
);
1542 _voucher_activity_t actx
= _voucher_activity_try_insert(act
);
1544 _voucher_activity_dispose(act
);
1547 _dispatch_voucher_activity_debug("create", act
);
1552 _voucher_activity_dispose(_voucher_activity_t act
)
1554 _dispatch_voucher_activity_debug("dispose", act
);
1555 _voucher_atm_release(act
->va_atm
);
1556 if (slowpath(_TAILQ_IS_ENQUEUED(act
, va_list))) {
1557 _dispatch_voucher_activity_debug("corruption", act
);
1558 DISPATCH_CRASH("Activity corruption");
1560 act
->va_list.tqe_next
= DISPATCH_OBJECT_LISTLESS
;
1561 dispatch_assert(!_TAILQ_IS_ENQUEUED(act
, va_atm_list
));
1562 dispatch_assert(!_TAILQ_IS_ENQUEUED(act
, va_atm_used_list
));
1563 _voucher_activity_buffer_header_t buffer
, tmp
;
1564 TAILQ_FOREACH_SAFE(buffer
, &act
->va_buffers
, vabh_list
, tmp
) {
1565 if (buffer
->vabh_pos
.vabp_pos
.vabp_next_tracepoint_idx
> 1) {
1566 dispatch_assert(_voucher_activity_buffer_mark_full(buffer
));
1567 _voucher_activity_firehose_push(act
, buffer
);
1569 TAILQ_REMOVE(&act
->va_buffers
, buffer
, vabh_list
);
1570 _dispatch_voucher_activity_debug("buffer free %p", act
, buffer
);
1571 _voucher_activity_heap_buffer_free(buffer
);
1573 (void)dispatch_assume_zero(pthread_mutex_destroy(&act
->va_mutex
));
1574 (void)dispatch_assume_zero(pthread_cond_destroy(&act
->va_cond
));
1580 _voucher_activity_firehose_push(_voucher_activity_t act
,
1581 _voucher_activity_buffer_header_t buffer
)
1583 if (dispatch_assume_zero(pthread_mutex_lock(&act
->va_mutex
))) {
1584 DISPATCH_CLIENT_CRASH("Activity corruption: mutex_lock");
1586 _dispatch_voucher_activity_debug("firehose push %p", act
, buffer
);
1587 // TODO: call firehose_push
1588 VOUCHER_ACTIVITY_BUFFER_HOOK_CALLOUT(full
, buffer
);
1589 _voucher_activity_buffer_init(act
, buffer
, false);
1590 if (dispatch_assume_zero(pthread_cond_broadcast(&act
->va_cond
))) {
1591 DISPATCH_CLIENT_CRASH("Activity corruption: cond_broadcast");
1593 if (dispatch_assume_zero(pthread_mutex_unlock(&act
->va_mutex
))) {
1594 DISPATCH_CLIENT_CRASH("Activity corruption: mutex_unlock");
1600 _voucher_activity_firehose_wait(_voucher_activity_t act
,
1601 _voucher_activity_buffer_header_t buffer
)
1603 if (dispatch_assume_zero(pthread_mutex_lock(&act
->va_mutex
))) {
1604 DISPATCH_CLIENT_CRASH("Activity corruption: mutex_lock");
1606 while (_voucher_activity_buffer_is_full(buffer
)) {
1607 _dispatch_voucher_activity_debug("firehose wait %p", act
, buffer
);
1608 if (dispatch_assume_zero(pthread_cond_wait(&act
->va_cond
,
1610 DISPATCH_CLIENT_CRASH("Activity corruption: cond_wait");
1613 if (dispatch_assume_zero(pthread_mutex_unlock(&act
->va_mutex
))) {
1614 DISPATCH_CLIENT_CRASH("Activity corruption: mutex_unlock");
1618 static _voucher_activity_t
1619 _voucher_activity_copy_from_mach_voucher(mach_voucher_t kv
,
1620 voucher_activity_id_t va_id
)
1622 dispatch_once_f(&_voucher_activity_heap_pred
, NULL
,
1623 _voucher_activity_heap_init
);
1624 if (_voucher_activity_disabled()) return NULL
;
1625 _voucher_activity_t act
= NULL
;
1626 if (dispatch_assume(va_id
)) {
1627 if ((act
= _voucher_activity_copy_from_id(va_id
))) return act
;
1629 atm_aid_t atm_id
= _voucher_mach_voucher_get_atm_id(kv
);
1630 if (!dispatch_assume(atm_id
)) return NULL
;
1631 _voucher_activity_buffer_header_t buffer
;
1632 buffer
= _voucher_activity_heap_buffer_alloc();
1633 if (!buffer
) return NULL
;
1634 _dispatch_kvoucher_debug("atm copy/create from <%lld>", kv
, atm_id
);
1635 _voucher_atm_t vatm
= _voucher_atm_copy(atm_id
);
1636 if (!vatm
) vatm
= _voucher_atm_create(kv
, atm_id
);
1638 _voucher_activity_heap_buffer_free(buffer
);
1641 // consumes vatm reference:
1642 act
= _voucher_activity_create_with_atm(vatm
, va_id
, 0, 0, buffer
);
1643 _dispatch_voucher_activity_debug("copy from kvoucher[0x%08x]", act
, kv
);
1648 #pragma mark _voucher_atm_t
1650 static void _voucher_atm_remove(_voucher_atm_t vatm
);
1651 static void _voucher_atm_dispose(_voucher_atm_t vatm
, bool unregister
);
1653 DISPATCH_ALWAYS_INLINE
1655 _voucher_atm_try_retain(_voucher_atm_t vatm
)
1657 // not using _os_object_refcnt* because we don't need barriers:
1658 // vouchers atm are immutable and are in a hash table with a lock
1660 // assumes vam_atms_lock held
1661 int refcnt
= dispatch_atomic_inc2o(vatm
, vatm_refcnt
, relaxed
);
1662 _dispatch_voucher_atm_debug("retain -> %d", vatm
, refcnt
+ 1);
1663 if (slowpath(refcnt
< 0)) {
1664 _dispatch_voucher_atm_debug("overrelease", vatm
);
1665 DISPATCH_CRASH("ATM overrelease");
1670 DISPATCH_ALWAYS_INLINE
1671 static inline _voucher_atm_t
1672 _voucher_atm_retain(_voucher_atm_t vatm
)
1674 if (slowpath(!_voucher_atm_try_retain(vatm
))) {
1675 _dispatch_voucher_atm_debug("resurrection", vatm
);
1676 DISPATCH_CRASH("ATM resurrection");
1681 DISPATCH_ALWAYS_INLINE
1683 _voucher_atm_release(_voucher_atm_t vatm
)
1685 // not using _os_object_refcnt* because we don't need barriers:
1686 // vouchers atm are immutable are into a hash table with a lock
1687 int refcnt
= dispatch_atomic_dec2o(vatm
, vatm_refcnt
, relaxed
);
1688 _dispatch_voucher_atm_debug("release -> %d", vatm
, refcnt
+ 1);
1689 if (fastpath(refcnt
>= 0)) {
1692 if (slowpath(refcnt
< -1)) {
1693 _dispatch_voucher_atm_debug("overrelease", vatm
);
1694 DISPATCH_CRASH("ATM overrelease");
1696 _voucher_atm_remove(vatm
);
1697 _voucher_atm_dispose(vatm
, true);
1700 static _voucher_atm_t
1701 _voucher_atm_find_and_retain(atm_aid_t atm_id
, uint32_t hash
)
1703 // not using _os_object_refcnt* because we don't need barriers:
1704 // vouchers atm are immutable are into a hash table with a lock
1706 // assumes vam_atms_lock held
1707 _voucher_atm_t vatm
;
1708 TAILQ_FOREACH(vatm
, vam_atms(hash
), vatm_list
){
1709 if (vatm
->vatm_id
== atm_id
) {
1710 if (fastpath(_voucher_atm_try_retain(vatm
))) {
1714 // <rdar://problem/20468375> disallow resurrection
1715 dispatch_atomic_dec2o(vatm
, vatm_refcnt
, relaxed
);
1716 _dispatch_voucher_atm_debug("undo resurrection", vatm
);
1722 static _voucher_atm_t
1723 _voucher_atm_copy(atm_aid_t atm_id
)
1725 uint32_t hash
= VATMID_HASH(atm_id
);
1726 _voucher_activity_lock_lock(vam_atms_lock());
1727 _voucher_atm_t vatm
= _voucher_atm_find_and_retain(atm_id
, hash
);
1729 _dispatch_voucher_atm_debug("copy", vatm
);
1731 _voucher_activity_lock_unlock(vam_atms_lock());
1735 static _voucher_atm_t
1736 _voucher_atm_try_insert(_voucher_atm_t vatm_new
)
1738 atm_aid_t atm_id
= vatm_new
->vatm_id
;
1739 uint32_t hash
= VATMID_HASH(atm_id
);
1740 _voucher_activity_lock_lock(vam_atms_lock());
1741 _voucher_atm_t vatm
= _voucher_atm_find_and_retain(atm_id
, hash
);
1743 _dispatch_voucher_atm_debug("try insert: failed (%p)", vatm
, vatm_new
);
1745 if (slowpath(_TAILQ_IS_ENQUEUED(vatm_new
, vatm_list
))) {
1746 _dispatch_voucher_atm_debug("corruption", vatm_new
);
1747 DISPATCH_CRASH("ATM corruption");
1749 TAILQ_INSERT_TAIL(vam_atms(hash
), vatm_new
, vatm_list
);
1750 _dispatch_voucher_atm_debug("try insert: succeeded", vatm_new
);
1752 _voucher_activity_lock_unlock(vam_atms_lock());
1757 _voucher_atm_remove(_voucher_atm_t vatm
)
1759 atm_aid_t atm_id
= vatm
->vatm_id
;
1760 uint32_t hash
= VATMID_HASH(atm_id
);
1762 _voucher_activity_lock_lock(vam_atms_lock());
1763 if (slowpath(!atm_id
|| !_TAILQ_IS_ENQUEUED(vatm
, vatm_list
))) {
1764 _dispatch_voucher_atm_debug("corruption", vatm
);
1765 DISPATCH_CRASH("ATM corruption");
1767 TAILQ_REMOVE(vam_atms(hash
), vatm
, vatm_list
);
1768 _TAILQ_MARK_NOT_ENQUEUED(vatm
, vatm_list
);
1769 vatm
->vatm_list
.tqe_next
= (void*)~0ull;
1770 _dispatch_voucher_atm_debug("remove", vatm
);
1771 _voucher_activity_lock_unlock(vam_atms_lock());
1776 _voucher_atm_fault(mach_voucher_attr_command_t kvc_cmd
)
1778 mach_voucher_t kv
= _voucher_get_atm_mach_voucher(_voucher_get());
1781 mach_atm_subaid_t subaid
= 0;
1782 voucher_t v
= _voucher_get();
1784 unsigned int activities
= v
->v_activities
;
1785 voucher_activity_id_t
*activity_ids
= _voucher_activity_ids(v
);
1787 subaid
= activity_ids
[0];
1792 mach_voucher_attr_content_t kvc_in
= (mach_voucher_attr_content_t
)&subaid
;
1793 mach_voucher_attr_content_size_t kvc_in_size
= sizeof(mach_atm_subaid_t
);
1794 mach_voucher_attr_content_t kvc_out
= (mach_voucher_attr_content_t
)&subaid
;
1795 mach_voucher_attr_content_size_t kvc_out_size
= sizeof(mach_atm_subaid_t
);
1796 kr
= mach_voucher_attr_command(kv
, MACH_VOUCHER_ATTR_KEY_ATM
,
1797 kvc_cmd
, kvc_in
, kvc_in_size
, kvc_out
, &kvc_out_size
);
1798 DISPATCH_VERIFY_MIG(kr
);
1799 (void)dispatch_assume_zero(kr
);
1803 _voucher_mach_voucher_get_atm_id(mach_voucher_t kv
)
1806 atm_aid_t atm_id
= 0;
1807 mach_voucher_attr_content_t kvc
= (mach_voucher_attr_content_t
)&atm_id
;
1808 mach_voucher_attr_content_size_t kvc_size
= sizeof(atm_id
);
1809 kr
= mach_voucher_extract_attr_content(kv
, MACH_VOUCHER_ATTR_KEY_ATM
, kvc
,
1811 DISPATCH_VERIFY_MIG(kr
);
1812 (void)dispatch_assume_zero(kr
);
1816 static mach_voucher_t
1817 _voucher_atm_mach_voucher_create(atm_aid_t
*atm_id_ptr
)
1821 static const mach_voucher_attr_recipe_data_t atm_create_recipe
= {
1822 .key
= MACH_VOUCHER_ATTR_KEY_ATM
,
1823 .command
= MACH_VOUCHER_ATTR_ATM_CREATE
,
1825 kr
= _voucher_create_mach_voucher(&atm_create_recipe
,
1826 sizeof(atm_create_recipe
), &kv
);
1827 if (dispatch_assume_zero(kr
)) {
1828 DISPATCH_CLIENT_CRASH("Could not create ATM mach voucher");
1830 atm_aid_t atm_id
= _voucher_mach_voucher_get_atm_id(kv
);
1831 if (!dispatch_assume(atm_id
)) {
1832 DISPATCH_CLIENT_CRASH("Could not extract ATM ID");
1834 _dispatch_kvoucher_debug("atm create <%lld>", kv
, atm_id
);
1835 *atm_id_ptr
= atm_id
;
1839 static mach_voucher_t
1840 _voucher_atm_mach_voucher_copy(mach_voucher_t akv
)
1844 const mach_voucher_attr_recipe_data_t atm_copy_recipe
= {
1845 .key
= MACH_VOUCHER_ATTR_KEY_ATM
,
1846 .command
= MACH_VOUCHER_ATTR_COPY
,
1847 .previous_voucher
= akv
,
1849 kr
= _voucher_create_mach_voucher(&atm_copy_recipe
,
1850 sizeof(atm_copy_recipe
), &kv
);
1851 if (dispatch_assume_zero(kr
)) {
1852 DISPATCH_CLIENT_CRASH("Could not copy ATM mach voucher");
1854 _dispatch_kvoucher_debug("copy atm voucher from [0x%08x]", kv
, akv
);
1859 _voucher_atm_register(_voucher_atm_t vatm
)
1861 mach_voucher_t kv
= vatm
->vatm_kvoucher
;
1865 dispatch_atomic_inc(&_voucher_atm_generation
, relaxed
);
1866 _dispatch_voucher_atm_debug("atm register %lld", vatm
, gen
);
1867 mach_voucher_attr_content_t kvc_in
= (mach_voucher_attr_content_t
)&gen
;
1868 mach_voucher_attr_content_size_t kvc_in_size
= sizeof(gen
);
1869 mach_voucher_attr_content_t kvc_out
= NULL
;
1870 mach_voucher_attr_content_size_t kvc_out_size
= 0;
1871 kr
= mach_voucher_attr_command(kv
, MACH_VOUCHER_ATTR_KEY_ATM
,
1872 ATM_ACTION_REGISTER
, kvc_in
, kvc_in_size
, kvc_out
,
1874 DISPATCH_VERIFY_MIG(kr
);
1876 DISPATCH_CLIENT_CRASH("Could not register ATM ID");
1878 vatm
->vatm_generation
= gen
;
1879 _dispatch_voucher_atm_debug("atm registered %lld", vatm
,
1880 vatm
->vatm_generation
);
1884 _voucher_atm_unregister(_voucher_atm_t vatm
)
1886 _dispatch_voucher_atm_debug("atm unregister %lld", vatm
,
1887 vatm
->vatm_generation
);
1888 mach_voucher_t kv
= vatm
->vatm_kvoucher
;
1889 dispatch_assert(kv
);
1891 atm_guard_t gen
= vatm
->vatm_generation
;
1892 mach_voucher_attr_content_t kvc_in
= (mach_voucher_attr_content_t
)&gen
;
1893 mach_voucher_attr_content_size_t kvc_in_size
= sizeof(gen
);
1894 mach_voucher_attr_content_t kvc_out
= NULL
;
1895 mach_voucher_attr_content_size_t kvc_out_size
= 0;
1896 kr
= mach_voucher_attr_command(kv
, MACH_VOUCHER_ATTR_KEY_ATM
,
1897 ATM_ACTION_UNREGISTER
, kvc_in
, kvc_in_size
, kvc_out
, &kvc_out_size
);
1898 DISPATCH_VERIFY_MIG(kr
);
1899 if (kr
&& kr
!= KERN_INVALID_VALUE
) {
1900 (void)dispatch_assume_zero(kr
);
1902 _dispatch_voucher_atm_debug("atm unregistered %lld", vatm
,
1903 vatm
->vatm_generation
);
1906 static _voucher_atm_t
1907 _voucher_atm_create(mach_voucher_t kv
, atm_aid_t atm_id
)
1909 _voucher_atm_t vatm
= _dispatch_calloc(1ul, sizeof(struct _voucher_atm_s
));
1910 kv
= kv
? _voucher_atm_mach_voucher_copy(kv
) :
1911 _voucher_atm_mach_voucher_create(&atm_id
);
1912 vatm
->vatm_kvoucher
= kv
;
1913 vatm
->vatm_id
= atm_id
;
1914 _voucher_atm_t vatmx
= _voucher_atm_try_insert(vatm
);
1916 _voucher_atm_dispose(vatm
, false);
1919 _voucher_atm_register(vatm
);
1921 _dispatch_voucher_atm_debug("create with kvoucher[0x%08x]", vatm
, kv
);
1926 _voucher_atm_dispose(_voucher_atm_t vatm
, bool unregister
)
1928 _dispatch_voucher_atm_debug("dispose", vatm
);
1929 if (slowpath(_TAILQ_IS_ENQUEUED(vatm
, vatm_list
))) {
1930 _dispatch_voucher_atm_debug("corruption", vatm
);
1931 DISPATCH_CRASH("ATM corruption");
1933 vatm
->vatm_list
.tqe_next
= DISPATCH_OBJECT_LISTLESS
;
1934 if (vatm
->vatm_kvoucher
) {
1935 if (unregister
) _voucher_atm_unregister(vatm
);
1936 _voucher_dealloc_mach_voucher(vatm
->vatm_kvoucher
);
1937 vatm
->vatm_kvoucher
= MACH_VOUCHER_NULL
;
1943 static voucher_activity_id_t
1944 _voucher_atm_subid_make(_voucher_atm_t vatm
, voucher_activity_flag_t flags
)
1946 mach_voucher_t kv
= vatm
->vatm_kvoucher
;
1947 _dispatch_voucher_atm_debug("create subid from atm", vatm
);
1949 mach_atm_subaid_t naid
;
1950 mach_voucher_attr_content_t kvc_in
= NULL
;
1951 mach_voucher_attr_content_size_t kvc_in_size
= 0;
1952 mach_voucher_attr_content_t kvc_out
= (mach_voucher_attr_content_t
)&naid
;
1953 mach_voucher_attr_content_size_t kvc_out_size
= sizeof(naid
);
1954 kr
= mach_voucher_attr_command(kv
, MACH_VOUCHER_ATTR_KEY_ATM
,
1955 ATM_ACTION_GETSUBAID
, kvc_in
, kvc_in_size
, kvc_out
, &kvc_out_size
);
1956 DISPATCH_VERIFY_MIG(kr
);
1957 if (dispatch_assume_zero(kr
)) {
1958 DISPATCH_CLIENT_CRASH("Could not get next ATM ID");
1960 _dispatch_voucher_atm_debug("created subid from atm %lld", vatm
, naid
);
1961 return VATMID2ACTID(naid
, flags
);
1965 #pragma mark voucher_activity_id_t
1967 static const size_t _voucher_activity_maxsize
=
1968 _voucher_activity_buffer_size
- _voucher_activity_buffer_header_size
-
1969 _voucher_activity_strings_header_size
;
1971 voucher_activity_id_t
1972 voucher_activity_start_with_location(voucher_activity_trace_id_t trace_id
,
1973 uint64_t location
, voucher_activity_flag_t flags
)
1975 dispatch_once_f(&_voucher_activity_heap_pred
, NULL
,
1976 _voucher_activity_heap_init
);
1977 if (!_voucher_activity_trace_id_enabled(trace_id
)) return 0;
1978 voucher_activity_id_t va_id
= 0;
1979 _voucher_atm_t vatm
= NULL
;
1980 _voucher_activity_t act
= NULL
;
1981 _voucher_activity_tracepoint_t vat
= NULL
;
1982 unsigned int activities
= 1, oactivities
= 0;
1983 voucher_t ov
= _voucher_get();
1984 vatm
= _voucher_get_atm(ov
);
1985 if (!(flags
& voucher_activity_flag_force
) && ov
&& ov
->v_activities
) {
1986 oactivities
= ov
->v_activities
;
1987 activities
+= oactivities
;
1988 if (activities
> _voucher_max_activities
) {
1989 va_id
= _voucher_atm_subid_make(vatm
, flags
);
1993 _voucher_atm_retain(vatm
);
1994 // required for v->v_atm = vatm below
1995 _voucher_atm_retain(vatm
);
1996 va_id
= _voucher_atm_subid_make(vatm
, flags
);
1997 // consumes vatm reference:
1998 act
= _voucher_activity_create_with_atm(vatm
, va_id
, trace_id
, location
,
2000 vat
= (_voucher_activity_tracepoint_t
)act
;
2001 pthread_priority_t priority
= _voucher_get_priority(ov
);
2002 mach_voucher_attr_recipe_size_t extra
= ov
? _voucher_extra_size(ov
) : 0;
2003 voucher_t v
= _voucher_alloc(activities
, priority
, extra
);
2005 memcpy(_voucher_extra_recipes(v
), _voucher_extra_recipes(ov
), extra
);
2007 if (ov
&& ov
->v_kvoucher
) {
2008 voucher_t kvb
= ov
->v_kvbase
? ov
->v_kvbase
: ov
;
2009 v
->v_kvbase
= _voucher_retain(kvb
);
2010 v
->v_kvoucher
= kvb
->v_kvoucher
;
2012 voucher_activity_id_t
*activity_ids
= _voucher_activity_ids(v
);
2014 memcpy(activity_ids
, _voucher_activity_ids(ov
),
2015 oactivities
* sizeof(voucher_activity_id_t
));
2017 activity_ids
[activities
-1] = va_id
;
2019 v
->v_activity
= act
;
2020 _voucher_swap(ov
, v
);
2021 return va_id
; // new activity buffer contains trace info
2023 _voucher_activity_trace_activity_event(trace_id
, va_id
, start
);
2027 voucher_activity_id_t
2028 voucher_activity_start(voucher_activity_trace_id_t trace_id
,
2029 voucher_activity_flag_t flags
)
2031 return voucher_activity_start_with_location(trace_id
, 0, flags
);
2035 voucher_activity_end(voucher_activity_id_t va_id
)
2038 _voucher_activity_trace_activity_event(_voucher_activity_trace_id_release
,
2040 voucher_t v
= _voucher_get();
2042 unsigned int activities
= v
->v_activities
, act_idx
= activities
;
2043 voucher_activity_id_t
*activity_ids
= _voucher_activity_ids(v
);
2045 if (activity_ids
[act_idx
-1] == va_id
) break;
2048 if (!act_idx
) return; // activity_id not found
2049 pthread_priority_t priority
= _voucher_get_priority(v
);
2050 mach_voucher_attr_recipe_size_t extra
= _voucher_extra_size(v
);
2051 voucher_t nv
= NULL
;
2052 if (act_idx
> 1 || activities
== 1) --activities
;
2053 if (priority
|| activities
|| extra
|| v
->v_kvoucher
) {
2054 nv
= _voucher_alloc(activities
, priority
, extra
);
2056 memcpy(_voucher_extra_recipes(nv
), _voucher_extra_recipes(v
),extra
);
2059 if (v
->v_kvoucher
) {
2060 voucher_t kvb
= v
->v_kvbase
? v
->v_kvbase
: v
;
2061 nv
->v_kvbase
= _voucher_retain(kvb
);
2062 nv
->v_kvoucher
= kvb
->v_kvoucher
;
2064 bool atm_collect
= !activities
;
2066 voucher_activity_id_t
*new_activity_ids
= _voucher_activity_ids(nv
);
2067 if (act_idx
== 1 && _voucher_activity_default
) {
2069 // default to _voucher_activity_default base activity
2070 new_activity_ids
[0] = _voucher_activity_default
->va_id
;
2071 memcpy(&new_activity_ids
[1], &activity_ids
[1],
2072 (activities
- 1) * sizeof(voucher_activity_id_t
));
2074 if (v
->v_activity
) {
2075 nv
->v_activity
= _voucher_activity_retain(v
->v_activity
);
2076 nv
->v_atm
= _voucher_atm_retain(v
->v_atm
);
2078 memcpy(new_activity_ids
, activity_ids
,
2079 --act_idx
* sizeof(voucher_activity_id_t
));
2080 if (act_idx
< activities
) {
2081 memcpy(&new_activity_ids
[act_idx
], &activity_ids
[act_idx
+1],
2082 (activities
- act_idx
) * sizeof(voucher_activity_id_t
));
2086 _voucher_swap(v
, nv
);
2090 voucher_get_activities(voucher_activity_id_t
*entries
, unsigned int *count
)
2092 voucher_t v
= _voucher_get();
2093 if (!v
|| !count
) return 0;
2094 unsigned int activities
= v
->v_activities
;
2095 if (*count
< activities
) activities
= *count
;
2096 *count
= v
->v_activities
;
2097 voucher_activity_id_t
*activity_ids
= _voucher_activity_ids(v
);
2098 if (activities
&& entries
) {
2099 memcpy(entries
, activity_ids
, activities
*
2100 sizeof(voucher_activity_id_t
));
2106 voucher_activity_get_namespace(void)
2108 voucher_t v
= _voucher_get();
2109 if (!v
|| !v
->v_activity
) return 0;
2110 voucher_activity_trace_id_t trace_id
= v
->v_activity
->va_trace_id
;
2111 uint8_t cns
= (uint8_t)(trace_id
>>
2112 _voucher_activity_trace_id_code_namespace_shift
);
2117 _voucher_activity_tracepoint_t
2118 _voucher_activity_buffer_tracepoint_acquire_slow(_voucher_activity_t
*vap
,
2119 _voucher_activity_buffer_header_t
*vabp
, unsigned int slots
,
2120 size_t strsize
, uint16_t *stroffsetp
)
2122 _voucher_activity_t act
;
2123 _voucher_activity_buffer_header_t vab
;
2124 _voucher_activity_tracepoint_t vat
= NULL
;
2125 voucher_t v
= _voucher_get();
2126 if (v
&& v
->v_activity
) {
2127 act
= v
->v_activity
;
2129 dispatch_once_f(&_voucher_activity_heap_pred
, NULL
,
2130 _voucher_activity_heap_init
);
2131 if (_voucher_activity_disabled()) return NULL
;
2132 act
= _voucher_activity_default
;
2134 vab
= act
->va_current_buffer
;
2135 if (act
== *vap
&& vab
!= *vabp
) {
2136 goto retry
; // another slowpath raced us
2139 vab
= _voucher_activity_buffer_alloc(act
, vab
);
2142 vat
= _voucher_activity_buffer_tracepoint_acquire(vab
, slots
, strsize
,
2151 _voucher_activity_trace_fault(voucher_activity_trace_id_t trace_id
)
2153 if (!slowpath(_voucher_activity_trace_id_is_subtype(trace_id
, error
))) {
2156 mach_voucher_attr_command_t atm_cmd
= ATM_ACTION_COLLECT
;
2157 if (_voucher_activity_trace_id_is_subtype(trace_id
, fault
)) {
2158 atm_cmd
= ATM_ACTION_LOGFAIL
;
2160 return _voucher_atm_fault(atm_cmd
);
2164 voucher_activity_trace(voucher_activity_trace_id_t trace_id
, uint64_t location
,
2165 void *buffer
, size_t length
)
2167 if (!_voucher_activity_trace_id_enabled(trace_id
)) return 0;
2168 _voucher_activity_t act
;
2169 _voucher_activity_buffer_header_t vab
;
2170 _voucher_activity_tracepoint_t vat
;
2171 const unsigned int slots
= length
<= sizeof(vat
->vat_data
) ? 1 : 2;
2172 act
= _voucher_activity_get();
2173 vab
= _voucher_activity_buffer_get_from_activity(act
);
2174 vat
= _voucher_activity_buffer_tracepoint_acquire(vab
, slots
, 0, NULL
);
2176 vat
= _voucher_activity_buffer_tracepoint_acquire_slow(&act
, &vab
,
2180 uint64_t timestamp
= _voucher_activity_tracepoint_init_with_id(vat
,
2181 trace_id
, location
, true);
2182 void *tbuf
= vat
->vat_data
;
2183 size_t tlen
= sizeof(vat
->vat_data
);
2184 if (length
< tlen
) {
2185 memcpy(tbuf
, buffer
, length
);
2187 memcpy(tbuf
, buffer
, tlen
);
2189 if (length
> tlen
) {
2190 vat
->vat_flags
|= _voucher_activity_trace_flag_wide_first
;
2193 (++vat
)->vat_flags
= _voucher_activity_trace_flag_tracepoint
|
2194 _voucher_activity_trace_flag_wide_second
;
2195 vat
->vat_type
= 0; vat
->vat_namespace
= 0;
2196 tbuf
= (void*)vat
+ offsetof(typeof(*vat
), vat_code
);
2197 tlen
= sizeof(*vat
) - offsetof(typeof(*vat
), vat_code
);
2198 if (length
< tlen
) {
2199 memcpy(tbuf
, buffer
, length
);
2201 memcpy(tbuf
, buffer
, tlen
);
2204 _voucher_activity_trace_fault(trace_id
);
2205 if (_voucher_activity_buffer_tracepoint_release(vab
)) {
2206 _voucher_activity_firehose_push(act
, vab
);
2212 voucher_activity_trace_strings(voucher_activity_trace_id_t trace_id
,
2213 uint64_t location
, void *buffer
, size_t length
, const char *strings
[],
2214 size_t string_lengths
[], size_t strings_size
)
2216 if (!_voucher_activity_trace_id_enabled(trace_id
)) return 0;
2217 _voucher_activity_t act
;
2218 _voucher_activity_buffer_header_t vab
;
2219 _voucher_activity_tracepoint_t vat
;
2221 const unsigned int slots
= length
<= sizeof(vat
->vat_data
) ? 1 : 2;
2222 strings_size
= MIN(strings_size
, _voucher_activity_maxsize
-
2223 slots
* sizeof(struct _voucher_activity_tracepoint_s
));
2224 act
= _voucher_activity_get();
2225 vab
= _voucher_activity_buffer_get_from_activity(act
);
2226 vat
= _voucher_activity_buffer_tracepoint_acquire(vab
, slots
, strings_size
,
2229 vat
= _voucher_activity_buffer_tracepoint_acquire_slow(&act
, &vab
,
2230 slots
, strings_size
, &offset
);
2233 uint64_t timestamp
= _voucher_activity_tracepoint_init_with_id(vat
,
2234 trace_id
, location
, false);
2235 vat
->vat_flags
|= _voucher_activity_trace_flag_tracepoint_strings
;
2236 vat
->vat_stroff
.vats_offset
= offset
;
2237 void *tbuf
= vat
->vat_stroff
.vats_data
;
2238 size_t tlen
= sizeof(vat
->vat_stroff
.vats_data
);
2239 if (length
< tlen
) {
2240 memcpy(tbuf
, buffer
, length
);
2242 memcpy(tbuf
, buffer
, tlen
);
2244 if (length
> tlen
) {
2245 vat
->vat_flags
|= _voucher_activity_trace_flag_wide_first
;
2248 (++vat
)->vat_flags
= _voucher_activity_trace_flag_tracepoint
|
2249 _voucher_activity_trace_flag_wide_second
;
2250 vat
->vat_type
= 0; vat
->vat_namespace
= 0;
2251 tbuf
= (void*)vat
+ offsetof(typeof(*vat
), vat_code
);
2252 tlen
= sizeof(*vat
) - offsetof(typeof(*vat
), vat_code
);
2253 if (length
< tlen
) {
2254 memcpy(tbuf
, buffer
, length
);
2256 memcpy(tbuf
, buffer
, tlen
);
2259 const uint16_t offsetend
= offset
- (uint16_t)strings_size
;
2260 char *b
= (char*)vab
+ _voucher_activity_buffer_size
;
2262 while (offset
> offsetend
&& strings
[i
]) {
2263 size_t maxsize
= MIN(string_lengths
[i
] + 1, offset
- offsetend
);
2264 size_t len
= strlcpy(b
- offset
, strings
[i
++], maxsize
);
2265 offset
-= MIN(len
+ 1, maxsize
);
2267 _voucher_activity_trace_fault(trace_id
);
2268 if (_voucher_activity_buffer_tracepoint_release(vab
)) {
2269 _voucher_activity_firehose_push(act
, vab
);
2275 voucher_activity_trace_args(voucher_activity_trace_id_t trace_id
,
2276 uint64_t location
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
,
2279 if (!_voucher_activity_trace_id_enabled(trace_id
)) return 0;
2280 _voucher_activity_t act
;
2281 _voucher_activity_buffer_header_t vab
;
2282 _voucher_activity_tracepoint_t vat
;
2283 act
= _voucher_activity_get();
2284 vab
= _voucher_activity_buffer_get_from_activity(act
);
2285 vat
= _voucher_activity_buffer_tracepoint_acquire(vab
, 1, 0, NULL
);
2287 vat
= _voucher_activity_buffer_tracepoint_acquire_slow(&act
, &vab
, 1,
2291 uint64_t timestamp
= _voucher_activity_tracepoint_init_with_id(vat
,
2292 trace_id
, location
, true);
2293 vat
->vat_flags
|= _voucher_activity_trace_flag_tracepoint_args
;
2294 vat
->vat_data
[0] = arg1
;
2295 vat
->vat_data
[1] = arg2
;
2296 vat
->vat_data
[2] = arg3
;
2297 vat
->vat_data
[3] = arg4
;
2298 _voucher_activity_trace_fault(trace_id
);
2299 if (_voucher_activity_buffer_tracepoint_release(vab
)) {
2300 _voucher_activity_firehose_push(act
, vab
);
2306 #pragma mark _voucher_debug
2309 _voucher_debug(voucher_t v
, char* buf
, size_t bufsiz
)
2312 #define bufprintf(...) \
2313 offset += dsnprintf(&buf[offset], bufsiz - offset, ##__VA_ARGS__)
2314 bufprintf("voucher[%p] = { xrefcnt = 0x%x, refcnt = 0x%x, ", v
,
2315 v
->os_obj_xref_cnt
+ 1, v
->os_obj_ref_cnt
+ 1);
2318 bufprintf("base voucher %p, ", v
->v_kvbase
);
2320 if (v
->v_kvoucher
) {
2321 bufprintf("kvoucher%s 0x%x, ", v
->v_kvoucher
== v
->v_ipc_kvoucher
?
2322 " & ipc kvoucher" : "", v
->v_kvoucher
);
2324 if (v
->v_ipc_kvoucher
&& v
->v_ipc_kvoucher
!= v
->v_kvoucher
) {
2325 bufprintf("ipc kvoucher 0x%x, ", v
->v_ipc_kvoucher
);
2327 if (v
->v_has_priority
) {
2328 bufprintf("QOS 0x%x, ", *_voucher_priority(v
));
2330 if (v
->v_activities
) {
2331 voucher_activity_id_t
*activity_ids
= _voucher_activity_ids(v
);
2332 bufprintf("activity IDs = { ");
2334 for (i
= 0; i
< v
->v_activities
; i
++) {
2335 bufprintf("0x%llx, ", *activity_ids
++);
2339 if (v
->v_activity
) {
2340 _voucher_activity_t va
= v
->v_activity
;
2341 _voucher_atm_t vatm
= va
->va_atm
;
2342 bufprintf("activity[%p] = { ID 0x%llx, ref %d, atm[%p] = { "
2343 "AID 0x%llx, ref %d, kvoucher 0x%x } }, ", va
, va
->va_id
,
2344 va
->va_refcnt
+ 1, va
->va_atm
, vatm
->vatm_id
,
2345 vatm
->vatm_refcnt
+ 1, vatm
->vatm_kvoucher
);
2351 #else // VOUCHER_USE_MACH_VOUCHER
2354 #pragma mark Simulator / vouchers disabled
2356 #if VOUCHER_ENABLE_RECIPE_OBJECTS
2358 voucher_create(voucher_recipe_t recipe
)
2366 voucher_adopt(voucher_t voucher
)
2378 voucher_copy_without_importance(void)
2384 voucher_retain(voucher_t voucher
)
2390 voucher_release(voucher_t voucher
)
2396 voucher_replace_default_voucher(void)
2401 voucher_decrement_importance_count4CF(voucher_t v
)
2407 _voucher_thread_cleanup(void *voucher
)
2413 _voucher_dealloc_mach_voucher(mach_voucher_t kv
)
2419 _voucher_create_mach_voucher_with_priority(voucher_t voucher
,
2420 pthread_priority_t priority
)
2422 (void)voucher
; (void)priority
;
2423 return MACH_VOUCHER_NULL
;
2427 _voucher_create_with_priority_and_mach_voucher(voucher_t voucher
,
2428 pthread_priority_t priority
, mach_voucher_t kv
)
2430 (void)voucher
; (void)priority
; (void)kv
;
2435 _voucher_create_accounting_voucher(voucher_t voucher
)
2442 voucher_create_with_mach_msg(mach_msg_header_t
*msg
)
2448 #if VOUCHER_ENABLE_GET_MACH_VOUCHER
2450 voucher_get_mach_voucher(voucher_t voucher
)
2458 _voucher_xref_dispose(voucher_t voucher
)
2464 _voucher_dispose(voucher_t voucher
)
2470 _voucher_atfork_child(void)
2480 voucher_activity_get_metadata_buffer(size_t *length
)
2487 voucher_activity_buffer_hook_install_4libtrace(
2488 _voucher_activity_buffer_hook_t hook
)
2494 _voucher_activity_heap_pressure_normal(void)
2499 _voucher_activity_heap_pressure_warn(void)
2503 voucher_activity_id_t
2504 voucher_activity_start_with_location(voucher_activity_trace_id_t trace_id
,
2505 uint64_t location
, voucher_activity_flag_t flags
)
2507 (void)trace_id
; (void)location
; (void)flags
;
2511 voucher_activity_id_t
2512 voucher_activity_start(voucher_activity_trace_id_t trace_id
,
2513 voucher_activity_flag_t flags
)
2515 (void)trace_id
; (void)flags
;
2520 voucher_activity_end(voucher_activity_id_t activity_id
)
2526 voucher_get_activities(voucher_activity_id_t
*entries
, unsigned int *count
)
2528 (void)entries
; (void)count
;
2533 voucher_activity_get_namespace(void)
2539 voucher_activity_trace(voucher_activity_trace_id_t trace_id
, uint64_t location
,
2540 void *buffer
, size_t length
)
2542 (void)trace_id
; (void)location
; (void)buffer
; (void)length
;
2547 voucher_activity_trace_strings(voucher_activity_trace_id_t trace_id
,
2548 uint64_t location
, void *buffer
, size_t length
, const char *strings
[],
2549 size_t string_lengths
[], size_t strings_size
)
2551 (void)trace_id
; (void)location
; (void)buffer
; (void)length
; (void)strings
;
2552 (void)string_lengths
; (void)strings_size
;
2557 voucher_activity_trace_args(voucher_activity_trace_id_t trace_id
,
2558 uint64_t location
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
,
2561 (void)trace_id
; (void)location
;
2562 (void)arg1
; (void)arg2
; (void)arg3
; (void)arg4
;
2567 _voucher_debug(voucher_t v
, char* buf
, size_t bufsiz
)
2569 (void)v
; (void)buf
; (void)bufsiz
;
2573 #endif // VOUCHER_USE_MACH_VOUCHER