]> git.saurik.com Git - apple/libdispatch.git/blob - src/introspection.c
libdispatch-501.40.12.tar.gz
[apple/libdispatch.git] / src / introspection.c
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
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
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
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
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
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
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
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
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
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 type != DISPATCH_MACH_CHANNEL_TYPE) {
316 diqi.type = dispatch_introspection_queue_item_type_source;
317 diqi.source = _dispatch_introspection_source_get_info(dou._ds);
318 } else {
319 diqi.type = dispatch_introspection_queue_item_type_object;
320 diqi.object = _dispatch_introspection_object_get_info(dou._do);
321 }
322 } else {
323 diqi.function = _dispatch_introspection_continuation_get_info(dq, dc,
324 &diqi.type);
325 }
326 return diqi;
327 }
328
329 #pragma mark -
330 #pragma mark dispatch_introspection_iterators
331
332 DISPATCH_USED
333 dispatch_queue_t
334 dispatch_introspection_get_queues(dispatch_queue_t start, size_t count,
335 dispatch_introspection_queue_t queues)
336 {
337 dispatch_queue_t next;
338 next = start ? start : TAILQ_FIRST(&_dispatch_introspection_queues);
339 while (count--) {
340 if (!next) {
341 queues->queue = NULL;
342 break;
343 }
344 *queues++ = dispatch_introspection_queue_get_info(next);
345 next = TAILQ_NEXT(next, diq_list);
346 }
347 return next;
348 }
349
350 DISPATCH_USED
351 dispatch_continuation_t
352 dispatch_introspection_get_queue_threads(dispatch_continuation_t start,
353 size_t count, dispatch_introspection_queue_thread_t threads)
354 {
355 dispatch_introspection_thread_t next = start ? (void*)start :
356 TAILQ_FIRST(&_dispatch_introspection_threads);
357 while (count--) {
358 if (!next) {
359 threads->object = NULL;
360 break;
361 }
362 *threads++ = _dispatch_introspection_thread_get_info(next);
363 next = TAILQ_NEXT(next, dit_list);
364 }
365 return (void*)next;
366 }
367
368 DISPATCH_USED
369 dispatch_continuation_t
370 dispatch_introspection_queue_get_items(dispatch_queue_t dq,
371 dispatch_continuation_t start, size_t count,
372 dispatch_introspection_queue_item_t items)
373 {
374 dispatch_continuation_t next = start ? start :
375 dq->dq_items_head == (void*)~0ul ? NULL : (void*)dq->dq_items_head;
376 while (count--) {
377 if (!next) {
378 items->type = dispatch_introspection_queue_item_type_none;
379 break;
380 }
381 *items++ = dispatch_introspection_queue_item_get_info(dq, next);
382 next = next->do_next;
383 }
384 return next;
385 }
386
387 #pragma mark -
388 #pragma mark dispatch_introspection_hooks
389
390 #define DISPATCH_INTROSPECTION_NO_HOOK ((void*)~0ul)
391
392 dispatch_introspection_hooks_s _dispatch_introspection_hooks;
393 dispatch_introspection_hooks_s _dispatch_introspection_hook_callouts;
394 static const
395 dispatch_introspection_hooks_s _dispatch_introspection_hook_callouts_enabled = {
396 .queue_create = DISPATCH_INTROSPECTION_NO_HOOK,
397 .queue_dispose = DISPATCH_INTROSPECTION_NO_HOOK,
398 .queue_item_enqueue = DISPATCH_INTROSPECTION_NO_HOOK,
399 .queue_item_dequeue = DISPATCH_INTROSPECTION_NO_HOOK,
400 .queue_item_complete = DISPATCH_INTROSPECTION_NO_HOOK,
401 };
402
403 #define DISPATCH_INTROSPECTION_HOOKS_COUNT (( \
404 sizeof(_dispatch_introspection_hook_callouts_enabled) - \
405 sizeof(_dispatch_introspection_hook_callouts_enabled._reserved)) / \
406 sizeof(dispatch_function_t))
407
408 #define DISPATCH_INTROSPECTION_HOOK_ENABLED(h) \
409 (slowpath(_dispatch_introspection_hooks.h))
410
411 #define DISPATCH_INTROSPECTION_HOOK_CALLOUT(h, ...) ({ \
412 typeof(_dispatch_introspection_hooks.h) _h; \
413 _h = _dispatch_introspection_hooks.h; \
414 if (slowpath((void*)(_h) != DISPATCH_INTROSPECTION_NO_HOOK)) { \
415 _h(__VA_ARGS__); \
416 } })
417
418 #define DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(h) \
419 DISPATCH_EXPORT void _dispatch_introspection_hook_##h(void) \
420 asm("_dispatch_introspection_hook_" #h); \
421 void _dispatch_introspection_hook_##h(void) {}
422
423 #define DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(h, ...)\
424 dispatch_introspection_hook_##h(__VA_ARGS__)
425
426 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_create);
427 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_destroy);
428 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_enqueue);
429 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_dequeue);
430 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_complete);
431 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_callout_begin);
432 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_callout_end);
433
434 DISPATCH_USED
435 void
436 dispatch_introspection_hooks_install(dispatch_introspection_hooks_t hooks)
437 {
438 dispatch_introspection_hooks_s old_hooks = _dispatch_introspection_hooks;
439 _dispatch_introspection_hooks = *hooks;
440 dispatch_function_t *e = (void*)&_dispatch_introspection_hook_callouts,
441 *h = (void*)&_dispatch_introspection_hooks, *oh = (void*)&old_hooks;
442 for (size_t i = 0; i < DISPATCH_INTROSPECTION_HOOKS_COUNT; i++) {
443 if (!h[i] && e[i]) {
444 h[i] = DISPATCH_INTROSPECTION_NO_HOOK;
445 }
446 if (oh[i] == DISPATCH_INTROSPECTION_NO_HOOK) {
447 oh[i] = NULL;
448 }
449 }
450 *hooks = old_hooks;
451 }
452
453 DISPATCH_USED
454 void
455 dispatch_introspection_hook_callouts_enable(
456 dispatch_introspection_hooks_t enable)
457 {
458 _dispatch_introspection_hook_callouts = enable ? *enable :
459 _dispatch_introspection_hook_callouts_enabled;
460 dispatch_function_t *e = (void*)&_dispatch_introspection_hook_callouts,
461 *h = (void*)&_dispatch_introspection_hooks;
462 for (size_t i = 0; i < DISPATCH_INTROSPECTION_HOOKS_COUNT; i++) {
463 if (e[i] && !h[i]) {
464 h[i] = DISPATCH_INTROSPECTION_NO_HOOK;
465 } else if (!e[i] && h[i] == DISPATCH_INTROSPECTION_NO_HOOK) {
466 h[i] = NULL;
467 }
468 }
469 }
470
471 DISPATCH_NOINLINE
472 void
473 dispatch_introspection_hook_callout_queue_create(
474 dispatch_introspection_queue_t queue_info)
475 {
476 DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_create, queue_info);
477 }
478
479 DISPATCH_NOINLINE
480 static void
481 _dispatch_introspection_queue_create_hook(dispatch_queue_t dq)
482 {
483 dispatch_introspection_queue_s diq;
484 diq = dispatch_introspection_queue_get_info(dq);
485 dispatch_introspection_hook_callout_queue_create(&diq);
486 }
487
488 dispatch_queue_t
489 _dispatch_introspection_queue_create(dispatch_queue_t dq)
490 {
491 OSSpinLockLock(&_dispatch_introspection_queues_lock);
492 TAILQ_INSERT_TAIL(&_dispatch_introspection_queues, dq, diq_list);
493 OSSpinLockUnlock(&_dispatch_introspection_queues_lock);
494
495 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_create, dq);
496 if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_create)) {
497 _dispatch_introspection_queue_create_hook(dq);
498 }
499 return dq;
500 }
501
502 DISPATCH_NOINLINE
503 void
504 dispatch_introspection_hook_callout_queue_dispose(
505 dispatch_introspection_queue_t queue_info)
506 {
507 DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_dispose, queue_info);
508 }
509
510 DISPATCH_NOINLINE
511 static void
512 _dispatch_introspection_queue_dispose_hook(dispatch_queue_t dq)
513 {
514 dispatch_introspection_queue_s diq;
515 diq = dispatch_introspection_queue_get_info(dq);
516 dispatch_introspection_hook_callout_queue_dispose(&diq);
517 }
518
519 void
520 _dispatch_introspection_queue_dispose(dispatch_queue_t dq)
521 {
522 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_destroy, dq);
523 if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_dispose)) {
524 _dispatch_introspection_queue_dispose_hook(dq);
525 }
526
527 OSSpinLockLock(&_dispatch_introspection_queues_lock);
528 TAILQ_REMOVE(&_dispatch_introspection_queues, dq, diq_list);
529 OSSpinLockUnlock(&_dispatch_introspection_queues_lock);
530 }
531
532 DISPATCH_NOINLINE
533 void
534 dispatch_introspection_hook_callout_queue_item_enqueue(dispatch_queue_t queue,
535 dispatch_introspection_queue_item_t item)
536 {
537 DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_item_enqueue, queue, item);
538 }
539
540 DISPATCH_NOINLINE
541 static void
542 _dispatch_introspection_queue_item_enqueue_hook(dispatch_queue_t dq,
543 dispatch_object_t dou)
544 {
545 dispatch_introspection_queue_item_s diqi;
546 diqi = dispatch_introspection_queue_item_get_info(dq, dou._dc);
547 dispatch_introspection_hook_callout_queue_item_enqueue(dq, &diqi);
548 }
549
550 void
551 _dispatch_introspection_queue_item_enqueue(dispatch_queue_t dq,
552 dispatch_object_t dou)
553 {
554 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(
555 queue_item_enqueue, dq, dou);
556 if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_item_enqueue)) {
557 _dispatch_introspection_queue_item_enqueue_hook(dq, dou);
558 }
559 }
560
561 DISPATCH_NOINLINE
562 void
563 dispatch_introspection_hook_callout_queue_item_dequeue(dispatch_queue_t queue,
564 dispatch_introspection_queue_item_t item)
565 {
566 DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_item_dequeue, queue, item);
567 }
568
569 DISPATCH_NOINLINE
570 static void
571 _dispatch_introspection_queue_item_dequeue_hook(dispatch_queue_t dq,
572 dispatch_object_t dou)
573 {
574 dispatch_introspection_queue_item_s diqi;
575 diqi = dispatch_introspection_queue_item_get_info(dq, dou._dc);
576 dispatch_introspection_hook_callout_queue_item_dequeue(dq, &diqi);
577 }
578
579 void
580 _dispatch_introspection_queue_item_dequeue(dispatch_queue_t dq,
581 dispatch_object_t dou)
582 {
583 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(
584 queue_item_dequeue, dq, dou);
585 if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_item_dequeue)) {
586 _dispatch_introspection_queue_item_dequeue_hook(dq, dou);
587 }
588 }
589
590 DISPATCH_NOINLINE
591 void
592 dispatch_introspection_hook_callout_queue_item_complete(
593 dispatch_continuation_t object)
594 {
595 DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_item_complete, object);
596 }
597
598 DISPATCH_NOINLINE
599 static void
600 _dispatch_introspection_queue_item_complete_hook(dispatch_object_t dou)
601 {
602 dispatch_introspection_hook_callout_queue_item_complete(dou._dc);
603 }
604
605 void
606 _dispatch_introspection_queue_item_complete(dispatch_object_t dou)
607 {
608 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_item_complete, dou);
609 if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_item_complete)) {
610 _dispatch_introspection_queue_item_complete_hook(dou);
611 }
612 }
613
614 void
615 _dispatch_introspection_callout_entry(void *ctxt, dispatch_function_t f) {
616 dispatch_queue_t dq = _dispatch_queue_get_current();
617 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(
618 queue_callout_begin, dq, ctxt, f);
619 }
620
621 void
622 _dispatch_introspection_callout_return(void *ctxt, dispatch_function_t f) {
623 dispatch_queue_t dq = _dispatch_queue_get_current();
624 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(
625 queue_callout_end, dq, ctxt, f);
626 }
627
628 #endif // DISPATCH_INTROSPECTION