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 30typedef 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; 36typedef struct dispatch_introspection_thread_s *dispatch_introspection_thread_t; 37 38static TAILQ_HEAD(, dispatch_introspection_thread_s) 39 _dispatch_introspection_threads = 40 TAILQ_HEAD_INITIALIZER(_dispatch_introspection_threads); 41static volatile OSSpinLock _dispatch_introspection_threads_lock; 42 43static void _dispatch_introspection_thread_remove(void *ctxt); 44 45static TAILQ_HEAD(, dispatch_queue_s) _dispatch_introspection_queues = 46 TAILQ_HEAD_INITIALIZER(_dispatch_introspection_queues); 47static volatile OSSpinLock _dispatch_introspection_queues_lock; 48 49static ptrdiff_t _dispatch_introspection_thread_queue_offset; 50 51#pragma mark - 52#pragma mark dispatch_introspection_init 53 54void 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 85const struct dispatch_introspection_versions_s 86dispatch_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 109void 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 127static 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 141static inline 142dispatch_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 208static inline 209dispatch_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 221DISPATCH_USED inline 222dispatch_introspection_queue_s 223dispatch_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 246static inline 247dispatch_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 286static inline 287dispatch_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 300DISPATCH_USED inline 301dispatch_introspection_queue_item_s 302dispatch_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 331DISPATCH_USED 332dispatch_queue_t 333dispatch_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 349DISPATCH_USED 350dispatch_continuation_t 351dispatch_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 367DISPATCH_USED 368dispatch_continuation_t 369dispatch_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 391dispatch_introspection_hooks_s _dispatch_introspection_hooks; 392dispatch_introspection_hooks_s _dispatch_introspection_hook_callouts; 393static const 394dispatch_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 425DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_create); 426DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_destroy); 427DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_enqueue); 428DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_dequeue); 429DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_item_complete); 430DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_callout_begin); 431DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK(queue_callout_end); 432 433DISPATCH_USED 434void 435dispatch_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 452DISPATCH_USED 453void 454dispatch_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 470DISPATCH_NOINLINE 471void 472dispatch_introspection_hook_callout_queue_create( 473 dispatch_introspection_queue_t queue_info) 474{ 475 DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_create, queue_info); 476} 477 478DISPATCH_NOINLINE 479static void 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 487dispatch_queue_t 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 501DISPATCH_NOINLINE 502void 503dispatch_introspection_hook_callout_queue_dispose( 504 dispatch_introspection_queue_t queue_info) 505{ 506 DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_dispose, queue_info); 507} 508 509DISPATCH_NOINLINE 510static void 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 518void 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 531DISPATCH_NOINLINE 532void 533dispatch_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 539DISPATCH_NOINLINE 540static void 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 549void 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 560DISPATCH_NOINLINE 561void 562dispatch_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 568DISPATCH_NOINLINE 569static void 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 578void 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 589DISPATCH_NOINLINE 590void 591dispatch_introspection_hook_callout_queue_item_complete( 592 dispatch_continuation_t object) 593{ 594 DISPATCH_INTROSPECTION_HOOK_CALLOUT(queue_item_complete, object); 595} 596 597DISPATCH_NOINLINE 598static void 599_dispatch_introspection_queue_item_complete_hook(dispatch_object_t dou) 600{ 601 dispatch_introspection_hook_callout_queue_item_complete(dou._dc); 602} 603 604void 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 613void 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 620void 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