xref: /trueos/lib/libdispatch/src/introspection.c (revision bf5f91cb28c5878845eb00fbf329c042f6c643c9)
1 /*
2  * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3  *
4  * @APPLE_APACHE_LICENSE_HEADER_START@
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  * @APPLE_APACHE_LICENSE_HEADER_END@
19  */
20 
21 // Contains introspection routines that only exist in the version of the
22 // library with introspection support
23 
24 #if DISPATCH_INTROSPECTION
25 
26 #include "internal.h"
27 #include "dispatch/introspection.h"
28 #include "introspection_private.h"
29 
30 typedef struct dispatch_introspection_thread_s {
31 	void *dit_isa;
32 	TAILQ_ENTRY(dispatch_introspection_thread_s) dit_list;
33 	pthread_t thread;
34 	dispatch_queue_t *queue;
35 } dispatch_introspection_thread_s;
36 typedef struct dispatch_introspection_thread_s *dispatch_introspection_thread_t;
37 
38 static TAILQ_HEAD(, dispatch_introspection_thread_s)
39 		_dispatch_introspection_threads =
40 		TAILQ_HEAD_INITIALIZER(_dispatch_introspection_threads);
41 static volatile OSSpinLock _dispatch_introspection_threads_lock;
42 
43 static void _dispatch_introspection_thread_remove(void *ctxt);
44 
45 static TAILQ_HEAD(, dispatch_queue_s) _dispatch_introspection_queues =
46 		TAILQ_HEAD_INITIALIZER(_dispatch_introspection_queues);
47 static volatile OSSpinLock _dispatch_introspection_queues_lock;
48 
49 static ptrdiff_t _dispatch_introspection_thread_queue_offset;
50 
51 #pragma mark -
52 #pragma mark dispatch_introspection_init
53 
54 void
_dispatch_introspection_init(void)55 _dispatch_introspection_init(void)
56 {
57 	TAILQ_INSERT_TAIL(&_dispatch_introspection_queues,
58 			&_dispatch_main_q, diq_list);
59 	TAILQ_INSERT_TAIL(&_dispatch_introspection_queues,
60 			&_dispatch_mgr_q, diq_list);
61 #if DISPATCH_ENABLE_PTHREAD_ROOT_QUEUES
62 	TAILQ_INSERT_TAIL(&_dispatch_introspection_queues,
63 			_dispatch_mgr_q.do_targetq, diq_list);
64 #endif
65 	for (size_t i = 0; i < DISPATCH_ROOT_QUEUE_COUNT; i++) {
66 		TAILQ_INSERT_TAIL(&_dispatch_introspection_queues,
67 				&_dispatch_root_queues[i], diq_list);
68 	}
69 
70 	// Hack to determine queue TSD offset from start of pthread structure
71 	uintptr_t thread = _dispatch_thread_self();
72 	thread_identifier_info_data_t tiid;
73 	mach_msg_type_number_t cnt = THREAD_IDENTIFIER_INFO_COUNT;
74 	kern_return_t kr = thread_info(pthread_mach_thread_np((void*)thread),
75 			THREAD_IDENTIFIER_INFO, (thread_info_t)&tiid, &cnt);
76 	if (!dispatch_assume_zero(kr)) {
77 		_dispatch_introspection_thread_queue_offset =
78 				(void*)(uintptr_t)tiid.dispatch_qaddr - (void*)thread;
79 	}
80 	_dispatch_thread_key_create(&dispatch_introspection_key,
81 			_dispatch_introspection_thread_remove);
82 	_dispatch_introspection_thread_add(); // add main thread
83 }
84 
85 const struct dispatch_introspection_versions_s
86 dispatch_introspection_versions = {
87 	.introspection_version = 1,
88 	.hooks_version = 2,
89 	.hooks_size = sizeof(dispatch_introspection_hooks_s),
90 	.queue_item_version = 1,
91 	.queue_item_size = sizeof(dispatch_introspection_queue_item_s),
92 	.queue_block_version = 1,
93 	.queue_block_size = sizeof(dispatch_introspection_queue_block_s),
94 	.queue_function_version = 1,
95 	.queue_function_size = sizeof(dispatch_introspection_queue_function_s),
96 	.queue_thread_version = 1,
97 	.queue_thread_size = sizeof(dispatch_introspection_queue_thread_s),
98 	.object_version = 1,
99 	.object_size = sizeof(dispatch_introspection_object_s),
100 	.queue_version = 1,
101 	.queue_size = sizeof(dispatch_introspection_queue_s),
102 	.source_version = 1,
103 	.source_size = sizeof(dispatch_introspection_source_s),
104 };
105 
106 #pragma mark -
107 #pragma mark dispatch_introspection_threads
108 
109 void
_dispatch_introspection_thread_add(void)110 _dispatch_introspection_thread_add(void)
111 {
112 	if (_dispatch_thread_getspecific(dispatch_introspection_key)) {
113 		return;
114 	}
115 	uintptr_t thread = _dispatch_thread_self();
116 	dispatch_introspection_thread_t dit = (void*)_dispatch_continuation_alloc();
117 	dit->dit_isa = (void*)0x41;
118 	dit->thread = (void*)thread;
119 	dit->queue = !_dispatch_introspection_thread_queue_offset ? NULL :
120 			(void*)thread + _dispatch_introspection_thread_queue_offset;
121 	_dispatch_thread_setspecific(dispatch_introspection_key, dit);
122 	OSSpinLockLock(&_dispatch_introspection_threads_lock);
123 	TAILQ_INSERT_TAIL(&_dispatch_introspection_threads, dit, dit_list);
124 	OSSpinLockUnlock(&_dispatch_introspection_threads_lock);
125 }
126 
127 static void
_dispatch_introspection_thread_remove(void * ctxt)128 _dispatch_introspection_thread_remove(void *ctxt)
129 {
130 	dispatch_introspection_thread_t dit = ctxt;
131 	OSSpinLockLock(&_dispatch_introspection_threads_lock);
132 	TAILQ_REMOVE(&_dispatch_introspection_threads, dit, dit_list);
133 	OSSpinLockUnlock(&_dispatch_introspection_threads_lock);
134 	_dispatch_continuation_free((void*)dit);
135 	_dispatch_thread_setspecific(dispatch_introspection_key, NULL);
136 }
137 
138 #pragma mark -
139 #pragma mark dispatch_introspection_info
140 
141 static inline
142 dispatch_introspection_queue_function_s
_dispatch_introspection_continuation_get_info(dispatch_queue_t dq,dispatch_continuation_t dc,unsigned long * type)143 _dispatch_introspection_continuation_get_info(dispatch_queue_t dq,
144 		dispatch_continuation_t dc, unsigned long *type)
145 {
146 	void *ctxt = dc->dc_ctxt;
147 	dispatch_function_t func = dc->dc_func;
148 	pthread_t waiter = NULL;
149 	bool apply = false;
150 	long flags = (long)dc->do_vtable;
151 	if (flags & DISPATCH_OBJ_SYNC_SLOW_BIT) {
152 		waiter = pthread_from_mach_thread_np((mach_port_t)dc->dc_data);
153 		if (flags & DISPATCH_OBJ_BARRIER_BIT) {
154 			dc = dc->dc_ctxt;
155 			dq = dc->dc_data;
156 		}
157 		ctxt = dc->dc_ctxt;
158 		func = dc->dc_func;
159 	}
160 	if (func == _dispatch_sync_recurse_invoke) {
161 		dc = dc->dc_ctxt;
162 		dq = dc->dc_data;
163 		ctxt = dc->dc_ctxt;
164 		func = dc->dc_func;
165 	} else if (func == _dispatch_async_redirect_invoke) {
166 		dq = dc->dc_data;
167 		dc = dc->dc_other;
168 		ctxt = dc->dc_ctxt;
169 		func = dc->dc_func;
170 		flags = (long)dc->do_vtable;
171 	} else if (func == _dispatch_mach_barrier_invoke) {
172 		dq = dq->do_targetq;
173 		ctxt = dc->dc_data;
174 		func = dc->dc_other;
175 	} else if (func == _dispatch_apply_invoke ||
176 			func == _dispatch_apply_redirect_invoke) {
177 		dispatch_apply_t da = ctxt;
178 		if (da->da_todo) {
179 			dc = da->da_dc;
180 			if (func == _dispatch_apply_redirect_invoke) {
181 				dq = dc->dc_data;
182 			}
183 			ctxt = dc->dc_ctxt;
184 			func = dc->dc_func;
185 			apply = true;
186 		}
187 	}
188 	if (func == _dispatch_call_block_and_release) {
189 		*type = dispatch_introspection_queue_item_type_block;
190 		func = _dispatch_Block_invoke(ctxt);
191 	} else {
192 		*type = dispatch_introspection_queue_item_type_function;
193 	}
194 	dispatch_introspection_queue_function_s diqf= {
195 		.continuation = dc,
196 		.target_queue = dq,
197 		.context = ctxt,
198 		.function = func,
199 		.group = flags & DISPATCH_OBJ_GROUP_BIT ? dc->dc_data : NULL,
200 		.waiter = waiter,
201 		.barrier = flags & DISPATCH_OBJ_BARRIER_BIT,
202 		.sync = flags & DISPATCH_OBJ_SYNC_SLOW_BIT,
203 		.apply = apply,
204 	};
205 	return diqf;
206 }
207 
208 static inline
209 dispatch_introspection_object_s
_dispatch_introspection_object_get_info(dispatch_object_t dou)210 _dispatch_introspection_object_get_info(dispatch_object_t dou)
211 {
212 	dispatch_introspection_object_s dio = {
213 		.object = dou._dc,
214 		.target_queue = dou._do->do_targetq,
215 		.type = (void*)dou._do->do_vtable,
216 		.kind = dx_kind(dou._do),
217 	};
218 	return dio;
219 }
220 
221 DISPATCH_USED inline
222 dispatch_introspection_queue_s
dispatch_introspection_queue_get_info(dispatch_queue_t dq)223 dispatch_introspection_queue_get_info(dispatch_queue_t dq)
224 {
225 	bool global = (dq->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) ||
226 			(dq->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT);
227 	uint16_t width = dq->dq_width;
228 	if (width > 1 && width != DISPATCH_QUEUE_WIDTH_MAX) width /= 2;
229 	dispatch_introspection_queue_s diq = {
230 		.queue = dq,
231 		.target_queue = dq->do_targetq,
232 		.label = dq->dq_label,
233 		.serialnum = dq->dq_serialnum,
234 		.width = width,
235 		.suspend_count = dq->do_suspend_cnt / 2,
236 		.enqueued = (dq->do_suspend_cnt & 1) && !global,
237 		.barrier = (dq->dq_running & 1) && !global,
238 		.draining = (dq->dq_items_head == (void*)~0ul) ||
239 				(!dq->dq_items_head && dq->dq_items_tail),
240 		.global = global,
241 		.main = (dq == &_dispatch_main_q),
242 	};
243 	return diq;
244 }
245 
246 static inline
247 dispatch_introspection_source_s
_dispatch_introspection_source_get_info(dispatch_source_t ds)248 _dispatch_introspection_source_get_info(dispatch_source_t ds)
249 {
250 	dispatch_source_refs_t dr = ds->ds_refs;
251 	dispatch_continuation_t dc = dr->ds_handler[DS_EVENT_HANDLER];
252 	void *ctxt = NULL;
253 	dispatch_function_t handler = NULL;
254 	bool hdlr_is_block = false;
255 	if (dc) {
256 		ctxt = dc->dc_ctxt;
257 		handler = dc->dc_func;
258 		hdlr_is_block = ((long)dc->do_vtable & DISPATCH_OBJ_BLOCK_RELEASE_BIT);
259 	}
260 	bool after = (handler == _dispatch_after_timer_callback);
261 	if (after && !(ds->ds_atomic_flags & DSF_CANCELED)) {
262 		dc = ctxt;
263 		ctxt = dc->dc_ctxt;
264 		handler = dc->dc_func;
265 		hdlr_is_block = (handler == _dispatch_call_block_and_release);
266 		if (hdlr_is_block) {
267 			handler = _dispatch_Block_invoke(ctxt);
268 		}
269 	}
270 	dispatch_introspection_source_s dis = {
271 		.source = ds,
272 		.target_queue = ds->do_targetq,
273 		.type = ds->ds_dkev ? (unsigned long)ds->ds_dkev->dk_kevent.filter : 0,
274 		.handle = ds->ds_dkev ? (unsigned long)ds->ds_dkev->dk_kevent.ident : 0,
275 		.context = ctxt,
276 		.handler = handler,
277 		.suspend_count = ds->do_suspend_cnt / 2,
278 		.enqueued = (ds->do_suspend_cnt & 1),
279 		.handler_is_block = hdlr_is_block,
280 		.timer = ds->ds_is_timer,
281 		.after = after,
282 	};
283 	return dis;
284 }
285 
286 static inline
287 dispatch_introspection_queue_thread_s
_dispatch_introspection_thread_get_info(dispatch_introspection_thread_t dit)288 _dispatch_introspection_thread_get_info(dispatch_introspection_thread_t dit)
289 {
290 	dispatch_introspection_queue_thread_s diqt = {
291 		.object = (void*)dit,
292 		.thread = dit->thread,
293 	};
294 	if (dit->queue && *dit->queue) {
295 		diqt.queue = dispatch_introspection_queue_get_info(*dit->queue);
296 	}
297 	return diqt;
298 }
299 
300 DISPATCH_USED inline
301 dispatch_introspection_queue_item_s
dispatch_introspection_queue_item_get_info(dispatch_queue_t dq,dispatch_continuation_t dc)302 dispatch_introspection_queue_item_get_info(dispatch_queue_t dq,
303 		dispatch_continuation_t dc)
304 {
305 	dispatch_introspection_queue_item_s diqi;
306 	if (DISPATCH_OBJ_IS_VTABLE(dc)) {
307 		dispatch_object_t dou = (dispatch_object_t)dc;
308 		unsigned long type = dx_type(dou._do);
309 		unsigned long metatype = type & _DISPATCH_META_TYPE_MASK;
310 		if (metatype == _DISPATCH_QUEUE_TYPE &&
311 				type != DISPATCH_QUEUE_SPECIFIC_TYPE) {
312 			diqi.type = dispatch_introspection_queue_item_type_queue;
313 			diqi.queue = dispatch_introspection_queue_get_info(dou._dq);
314 		} else if (metatype == _DISPATCH_SOURCE_TYPE) {
315 			diqi.type = dispatch_introspection_queue_item_type_source;
316 			diqi.source = _dispatch_introspection_source_get_info(dou._ds);
317 		} else {
318 			diqi.type = dispatch_introspection_queue_item_type_object;
319 			diqi.object = _dispatch_introspection_object_get_info(dou._do);
320 		}
321 	} else {
322 		diqi.function = _dispatch_introspection_continuation_get_info(dq, dc,
323 				&diqi.type);
324 	}
325 	return diqi;
326 }
327 
328 #pragma mark -
329 #pragma mark dispatch_introspection_iterators
330 
331 DISPATCH_USED
332 dispatch_queue_t
dispatch_introspection_get_queues(dispatch_queue_t start,size_t count,dispatch_introspection_queue_t queues)333 dispatch_introspection_get_queues(dispatch_queue_t start, size_t count,
334 		dispatch_introspection_queue_t queues)
335 {
336 	dispatch_queue_t next;
337 	next = start ? start : TAILQ_FIRST(&_dispatch_introspection_queues);
338 	while (count--) {
339 		if (!next) {
340 			queues->queue = NULL;
341 			break;
342 		}
343 		*queues++ = dispatch_introspection_queue_get_info(next);
344 		next = TAILQ_NEXT(next, diq_list);
345 	}
346 	return next;
347 }
348 
349 DISPATCH_USED
350 dispatch_continuation_t
dispatch_introspection_get_queue_threads(dispatch_continuation_t start,size_t count,dispatch_introspection_queue_thread_t threads)351 dispatch_introspection_get_queue_threads(dispatch_continuation_t start,
352 		size_t count, dispatch_introspection_queue_thread_t threads)
353 {
354 	dispatch_introspection_thread_t next = start ? (void*)start :
355 			TAILQ_FIRST(&_dispatch_introspection_threads);
356 	while (count--) {
357 		if (!next) {
358 			threads->object = NULL;
359 			break;
360 		}
361 		*threads++ = _dispatch_introspection_thread_get_info(next);
362 		next = TAILQ_NEXT(next, dit_list);
363 	}
364 	return (void*)next;
365 }
366 
367 DISPATCH_USED
368 dispatch_continuation_t
dispatch_introspection_queue_get_items(dispatch_queue_t dq,dispatch_continuation_t start,size_t count,dispatch_introspection_queue_item_t items)369 dispatch_introspection_queue_get_items(dispatch_queue_t dq,
370 		dispatch_continuation_t start, size_t count,
371 		dispatch_introspection_queue_item_t items)
372 {
373 	dispatch_continuation_t next = start ? start :
374 			dq->dq_items_head == (void*)~0ul ? NULL : (void*)dq->dq_items_head;
375 	while (count--) {
376 		if (!next) {
377 			items->type = dispatch_introspection_queue_item_type_none;
378 			break;
379 		}
380 		*items++ = dispatch_introspection_queue_item_get_info(dq, next);
381 		next = next->do_next;
382 	}
383 	return next;
384 }
385 
386 #pragma mark -
387 #pragma mark dispatch_introspection_hooks
388 
389 #define DISPATCH_INTROSPECTION_NO_HOOK ((void*)~0ul)
390 
391 dispatch_introspection_hooks_s _dispatch_introspection_hooks;
392 dispatch_introspection_hooks_s _dispatch_introspection_hook_callouts;
393 static const
394 dispatch_introspection_hooks_s _dispatch_introspection_hook_callouts_enabled = {
395 	.queue_create = DISPATCH_INTROSPECTION_NO_HOOK,
396 	.queue_dispose = DISPATCH_INTROSPECTION_NO_HOOK,
397 	.queue_item_enqueue = DISPATCH_INTROSPECTION_NO_HOOK,
398 	.queue_item_dequeue = DISPATCH_INTROSPECTION_NO_HOOK,
399 	.queue_item_complete = DISPATCH_INTROSPECTION_NO_HOOK,
400 };
401 
402 #define DISPATCH_INTROSPECTION_HOOKS_COUNT (( \
403 		sizeof(_dispatch_introspection_hook_callouts_enabled) - \
404 		sizeof(_dispatch_introspection_hook_callouts_enabled._reserved)) / \
405 		sizeof(dispatch_function_t))
406 
407 #define DISPATCH_INTROSPECTION_HOOK_ENABLED(h) \
408 		(slowpath(_dispatch_introspection_hooks.h))
409 
410 #define DISPATCH_INTROSPECTION_HOOK_CALLOUT(h, ...) ({ \
411 		typeof(_dispatch_introspection_hooks.h) _h; \
412 		_h = _dispatch_introspection_hooks.h; \
413 		if (slowpath((void*)(_h) != DISPATCH_INTROSPECTION_NO_HOOK)) { \
414 			_h(__VA_ARGS__); \
415 		} })
416 
417 #define DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(h) \
418 		DISPATCH_EXPORT void _dispatch_introspection_hook_##h(void) \
419 		asm("_dispatch_introspection_hook_" #h); \
420 		void _dispatch_introspection_hook_##h(void) {}
421 
422 #define DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(h, ...)\
423 		dispatch_introspection_hook_##h(__VA_ARGS__)
424 
425 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_create);
426 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_destroy);
427 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_enqueue);
428 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_dequeue);
429 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_complete);
430 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_callout_begin);
431 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_callout_end);
432 
433 DISPATCH_USED
434 void
dispatch_introspection_hooks_install(dispatch_introspection_hooks_t hooks)435 dispatch_introspection_hooks_install(dispatch_introspection_hooks_t hooks)
436 {
437 	dispatch_introspection_hooks_s old_hooks = _dispatch_introspection_hooks;
438 	_dispatch_introspection_hooks = *hooks;
439 	dispatch_function_t *e = (void*)&_dispatch_introspection_hook_callouts,
440 			*h = (void*)&_dispatch_introspection_hooks, *oh = (void*)&old_hooks;
441 	for (size_t i = 0; i < DISPATCH_INTROSPECTION_HOOKS_COUNT; i++) {
442 		if (!h[i] && e[i]) {
443 			h[i] = DISPATCH_INTROSPECTION_NO_HOOK;
444 		}
445 		if (oh[i] == DISPATCH_INTROSPECTION_NO_HOOK) {
446 			oh[i] = NULL;
447 		}
448 	}
449 	*hooks = old_hooks;
450 }
451 
452 DISPATCH_USED
453 void
dispatch_introspection_hook_callouts_enable(dispatch_introspection_hooks_t enable)454 dispatch_introspection_hook_callouts_enable(
455 		dispatch_introspection_hooks_t enable)
456 {
457 	_dispatch_introspection_hook_callouts = enable ? *enable :
458 			_dispatch_introspection_hook_callouts_enabled;
459 	dispatch_function_t *e = (void*)&_dispatch_introspection_hook_callouts,
460 			*h = (void*)&_dispatch_introspection_hooks;
461 	for (size_t i = 0; i < DISPATCH_INTROSPECTION_HOOKS_COUNT; i++) {
462 		if (e[i] && !h[i]) {
463 			h[i] = DISPATCH_INTROSPECTION_NO_HOOK;
464 		} else if (!e[i] && h[i] == DISPATCH_INTROSPECTION_NO_HOOK) {
465 			h[i] = NULL;
466 		}
467 	}
468 }
469 
470 DISPATCH_NOINLINE
471 void
dispatch_introspection_hook_callout_queue_create(dispatch_introspection_queue_t queue_info)472 dispatch_introspection_hook_callout_queue_create(
473 		dispatch_introspection_queue_t queue_info)
474 {
475 	DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_create, queue_info);
476 }
477 
478 DISPATCH_NOINLINE
479 static void
_dispatch_introspection_queue_create_hook(dispatch_queue_t dq)480 _dispatch_introspection_queue_create_hook(dispatch_queue_t dq)
481 {
482 	dispatch_introspection_queue_s diq;
483 	diq = dispatch_introspection_queue_get_info(dq);
484 	dispatch_introspection_hook_callout_queue_create(&diq);
485 }
486 
487 dispatch_queue_t
_dispatch_introspection_queue_create(dispatch_queue_t dq)488 _dispatch_introspection_queue_create(dispatch_queue_t dq)
489 {
490 	OSSpinLockLock(&_dispatch_introspection_queues_lock);
491 	TAILQ_INSERT_TAIL(&_dispatch_introspection_queues, dq, diq_list);
492 	OSSpinLockUnlock(&_dispatch_introspection_queues_lock);
493 
494 	DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_create, dq);
495 	if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_create)) {
496 		_dispatch_introspection_queue_create_hook(dq);
497 	}
498 	return dq;
499 }
500 
501 DISPATCH_NOINLINE
502 void
dispatch_introspection_hook_callout_queue_dispose(dispatch_introspection_queue_t queue_info)503 dispatch_introspection_hook_callout_queue_dispose(
504 		dispatch_introspection_queue_t queue_info)
505 {
506 	DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_dispose, queue_info);
507 }
508 
509 DISPATCH_NOINLINE
510 static void
_dispatch_introspection_queue_dispose_hook(dispatch_queue_t dq)511 _dispatch_introspection_queue_dispose_hook(dispatch_queue_t dq)
512 {
513 	dispatch_introspection_queue_s diq;
514 	diq = dispatch_introspection_queue_get_info(dq);
515 	dispatch_introspection_hook_callout_queue_dispose(&diq);
516 }
517 
518 void
_dispatch_introspection_queue_dispose(dispatch_queue_t dq)519 _dispatch_introspection_queue_dispose(dispatch_queue_t dq)
520 {
521 	DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_destroy, dq);
522 	if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_dispose)) {
523 		_dispatch_introspection_queue_dispose_hook(dq);
524 	}
525 
526 	OSSpinLockLock(&_dispatch_introspection_queues_lock);
527 	TAILQ_REMOVE(&_dispatch_introspection_queues, dq, diq_list);
528 	OSSpinLockUnlock(&_dispatch_introspection_queues_lock);
529 }
530 
531 DISPATCH_NOINLINE
532 void
dispatch_introspection_hook_callout_queue_item_enqueue(dispatch_queue_t queue,dispatch_introspection_queue_item_t item)533 dispatch_introspection_hook_callout_queue_item_enqueue(dispatch_queue_t queue,
534 		dispatch_introspection_queue_item_t item)
535 {
536 	DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_item_enqueue, queue, item);
537 }
538 
539 DISPATCH_NOINLINE
540 static void
_dispatch_introspection_queue_item_enqueue_hook(dispatch_queue_t dq,dispatch_object_t dou)541 _dispatch_introspection_queue_item_enqueue_hook(dispatch_queue_t dq,
542 		dispatch_object_t dou)
543 {
544 	dispatch_introspection_queue_item_s diqi;
545 	diqi = dispatch_introspection_queue_item_get_info(dq, dou._dc);
546 	dispatch_introspection_hook_callout_queue_item_enqueue(dq, &diqi);
547 }
548 
549 void
_dispatch_introspection_queue_item_enqueue(dispatch_queue_t dq,dispatch_object_t dou)550 _dispatch_introspection_queue_item_enqueue(dispatch_queue_t dq,
551 		dispatch_object_t dou)
552 {
553 	DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(
554 			queue_item_enqueue, dq, dou);
555 	if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_item_enqueue)) {
556 		_dispatch_introspection_queue_item_enqueue_hook(dq, dou);
557 	}
558 }
559 
560 DISPATCH_NOINLINE
561 void
dispatch_introspection_hook_callout_queue_item_dequeue(dispatch_queue_t queue,dispatch_introspection_queue_item_t item)562 dispatch_introspection_hook_callout_queue_item_dequeue(dispatch_queue_t queue,
563 		dispatch_introspection_queue_item_t item)
564 {
565 	DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_item_dequeue, queue, item);
566 }
567 
568 DISPATCH_NOINLINE
569 static void
_dispatch_introspection_queue_item_dequeue_hook(dispatch_queue_t dq,dispatch_object_t dou)570 _dispatch_introspection_queue_item_dequeue_hook(dispatch_queue_t dq,
571 		dispatch_object_t dou)
572 {
573 	dispatch_introspection_queue_item_s diqi;
574 	diqi = dispatch_introspection_queue_item_get_info(dq, dou._dc);
575 	dispatch_introspection_hook_callout_queue_item_dequeue(dq, &diqi);
576 }
577 
578 void
_dispatch_introspection_queue_item_dequeue(dispatch_queue_t dq,dispatch_object_t dou)579 _dispatch_introspection_queue_item_dequeue(dispatch_queue_t dq,
580 		dispatch_object_t dou)
581 {
582 	DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(
583 			queue_item_dequeue, dq, dou);
584 	if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_item_dequeue)) {
585 		_dispatch_introspection_queue_item_dequeue_hook(dq, dou);
586 	}
587 }
588 
589 DISPATCH_NOINLINE
590 void
dispatch_introspection_hook_callout_queue_item_complete(dispatch_continuation_t object)591 dispatch_introspection_hook_callout_queue_item_complete(
592 		dispatch_continuation_t object)
593 {
594 	DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_item_complete, object);
595 }
596 
597 DISPATCH_NOINLINE
598 static void
_dispatch_introspection_queue_item_complete_hook(dispatch_object_t dou)599 _dispatch_introspection_queue_item_complete_hook(dispatch_object_t dou)
600 {
601 	dispatch_introspection_hook_callout_queue_item_complete(dou._dc);
602 }
603 
604 void
_dispatch_introspection_queue_item_complete(dispatch_object_t dou)605 _dispatch_introspection_queue_item_complete(dispatch_object_t dou)
606 {
607 	DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_item_complete, dou);
608 	if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_item_complete)) {
609 		_dispatch_introspection_queue_item_complete_hook(dou);
610 	}
611 }
612 
613 void
_dispatch_introspection_callout_entry(void * ctxt,dispatch_function_t f)614 _dispatch_introspection_callout_entry(void *ctxt, dispatch_function_t f) {
615 	dispatch_queue_t dq = _dispatch_queue_get_current();
616 	DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(
617 			queue_callout_begin, dq, ctxt, f);
618 }
619 
620 void
_dispatch_introspection_callout_return(void * ctxt,dispatch_function_t f)621 _dispatch_introspection_callout_return(void *ctxt, dispatch_function_t f) {
622 	dispatch_queue_t dq = _dispatch_queue_get_current();
623 	DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(
624 			queue_callout_end, dq, ctxt, f);
625 }
626 
627 #endif // DISPATCH_INTROSPECTION
628