1/* 2 * Copyright (c) 2008-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 exported global data and initialization & other routines that must 22// only exist once in the shared library even when resolvers are used. 23 24#include "internal.h" 25 26#if HAVE_MACH 27#include "protocolServer.h" 28#endif 29 30#pragma mark - 31#pragma mark dispatch_init 32 33#if USE_LIBDISPATCH_INIT_CONSTRUCTOR 34DISPATCH_NOTHROW __attribute__((constructor)) 35void 36_libdispatch_init(void); 37 38DISPATCH_EXPORT DISPATCH_NOTHROW 39void 40_libdispatch_init(void) 41{ 42 libdispatch_init(); 43} 44#endif 45 46DISPATCH_EXPORT DISPATCH_NOTHROW 47void 48dispatch_atfork_prepare(void) 49{ 50} 51 52DISPATCH_EXPORT DISPATCH_NOTHROW 53void 54dispatch_atfork_parent(void) 55{ 56} 57 58#pragma mark - 59#pragma mark dispatch_globals 60 61#if DISPATCH_COCOA_COMPAT 62void (*dispatch_begin_thread_4GC)(void); 63void (*dispatch_end_thread_4GC)(void); 64void *(*_dispatch_begin_NSAutoReleasePool)(void); 65void (*_dispatch_end_NSAutoReleasePool)(void *); 66#endif 67 68#if !DISPATCH_USE_DIRECT_TSD 69pthread_key_t dispatch_queue_key; 70pthread_key_t dispatch_sema4_key; 71pthread_key_t dispatch_cache_key; 72pthread_key_t dispatch_io_key; 73pthread_key_t dispatch_apply_key; 74pthread_key_t dispatch_defaultpriority_key; 75#if DISPATCH_INTROSPECTION 76pthread_key_t dispatch_introspection_key; 77#elif DISPATCH_PERF_MON 78pthread_key_t dispatch_bcounter_key; 79#endif 80#endif // !DISPATCH_USE_DIRECT_TSD 81 82#if VOUCHER_USE_MACH_VOUCHER 83dispatch_once_t _voucher_task_mach_voucher_pred; 84mach_voucher_t _voucher_task_mach_voucher; 85_voucher_activity_t _voucher_activity_default; 86#endif 87voucher_activity_mode_t _voucher_activity_mode; 88int _dispatch_set_qos_class_enabled; 89 90 91DISPATCH_NOINLINE 92voucher_activity_mode_t 93voucher_activity_get_mode(void) 94{ 95 return _voucher_activity_mode; 96} 97 98void 99voucher_activity_set_mode_4libtrace(voucher_activity_mode_t mode) 100{ 101 if (_voucher_activity_disabled()) return; 102 _voucher_activity_mode = mode; 103} 104 105DISPATCH_HW_CONFIG(); 106bool _dispatch_safe_fork = true, _dispatch_child_of_unsafe_fork; 107 108DISPATCH_NOINLINE 109bool 110_dispatch_is_multithreaded(void) 111{ 112 return !_dispatch_safe_fork; 113} 114 115DISPATCH_NOINLINE 116bool 117_dispatch_is_fork_of_multithreaded_parent(void) 118{ 119 return _dispatch_child_of_unsafe_fork; 120} 121 122const struct dispatch_queue_offsets_s dispatch_queue_offsets = { 123 .dqo_version = 5, 124 .dqo_label = offsetof(struct dispatch_queue_s, dq_label), 125 .dqo_label_size = sizeof(((dispatch_queue_t)NULL)->dq_label), 126 .dqo_flags = 0, 127 .dqo_flags_size = 0, 128 .dqo_serialnum = offsetof(struct dispatch_queue_s, dq_serialnum), 129 .dqo_serialnum_size = sizeof(((dispatch_queue_t)NULL)->dq_serialnum), 130 .dqo_width = offsetof(struct dispatch_queue_s, dq_width), 131 .dqo_width_size = sizeof(((dispatch_queue_t)NULL)->dq_width), 132 .dqo_running = offsetof(struct dispatch_queue_s, dq_running), 133 .dqo_running_size = sizeof(((dispatch_queue_t)NULL)->dq_running), 134 .dqo_suspend_cnt = offsetof(struct dispatch_queue_s, do_suspend_cnt), 135 .dqo_suspend_cnt_size = sizeof(((dispatch_queue_t)NULL)->do_suspend_cnt), 136 .dqo_target_queue = offsetof(struct dispatch_queue_s, do_targetq), 137 .dqo_target_queue_size = sizeof(((dispatch_queue_t)NULL)->do_targetq), 138 .dqo_priority = offsetof(struct dispatch_queue_s, dq_priority), 139 .dqo_priority_size = sizeof(((dispatch_queue_t)NULL)->dq_priority), 140}; 141 142#if VOUCHER_USE_MACH_VOUCHER 143const struct voucher_offsets_s voucher_offsets = { 144 .vo_version = 1, 145 .vo_activity_ids_count = offsetof(struct voucher_s, v_activities), 146 .vo_activity_ids_count_size = sizeof(((voucher_t)NULL)->v_activities), 147 .vo_activity_ids_array = (uint16_t)_voucher_activity_ids((voucher_t)(NULL)), 148 .vo_activity_ids_array_entry_size = sizeof(voucher_activity_id_t), 149}; 150#else // VOUCHER_USE_MACH_VOUCHER 151const struct voucher_offsets_s voucher_offsets = { 152 .vo_version = 0, 153}; 154#endif // VOUCHER_USE_MACH_VOUCHER 155 156#if DISPATCH_USE_DIRECT_TSD 157const struct dispatch_tsd_indexes_s dispatch_tsd_indexes = { 158 .dti_version = 2, 159 .dti_queue_index = dispatch_queue_key, 160 .dti_voucher_index = dispatch_voucher_key, 161 .dti_qos_class_index = dispatch_priority_key, 162}; 163#else // DISPATCH_USE_DIRECT_TSD 164#error Not implemented on this platform 165#endif // DISPATCH_USE_DIRECT_TSD 166 167// 6618342 Contact the team that owns the Instrument DTrace probe before 168// renaming this symbol 169DISPATCH_CACHELINE_ALIGN 170struct dispatch_queue_s _dispatch_main_q = { 171 .do_vtable = DISPATCH_VTABLE(queue), 172#if !DISPATCH_USE_RESOLVERS 173 .do_targetq = &_dispatch_root_queues[ 174 DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT], 175#endif 176 .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, 177 .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, 178 .do_suspend_cnt = DISPATCH_OBJECT_SUSPEND_LOCK, 179 .dq_label = "com.apple.main-thread", 180 .dq_running = 1, 181 .dq_width = 1, 182 .dq_is_thread_bound = 1, 183 .dq_serialnum = 1, 184}; 185 186#pragma mark - 187#pragma mark dispatch_queue_attr_t 188 189#define DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, overcommit, concurrent) \ 190 { \ 191 .do_vtable = DISPATCH_VTABLE(queue_attr), \ 192 .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, \ 193 .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, \ 194 .do_next = DISPATCH_OBJECT_LISTLESS, \ 195 .dqa_qos_class = (qos), \ 196 .dqa_relative_priority = (qos) ? (prio) : 0, \ 197 .dqa_overcommit = (overcommit), \ 198 .dqa_concurrent = (concurrent), \ 199 } 200 201#define DISPATCH_QUEUE_ATTR_KIND_INIT(qos, prio) \ 202 { \ 203 [DQA_INDEX_NON_OVERCOMMIT][DQA_INDEX_CONCURRENT] = \ 204 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, 0, 1), \ 205 [DQA_INDEX_NON_OVERCOMMIT][DQA_INDEX_SERIAL] = \ 206 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, 0, 0), \ 207 [DQA_INDEX_OVERCOMMIT][DQA_INDEX_CONCURRENT] = \ 208 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, 1, 1), \ 209 [DQA_INDEX_OVERCOMMIT][DQA_INDEX_SERIAL] = \ 210 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, 1, 0), \ 211 } 212 213#define DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, prio) \ 214 [prio] = DISPATCH_QUEUE_ATTR_KIND_INIT(qos, -(prio)) 215 216#define DISPATCH_QUEUE_ATTR_PRIO_INIT(qos) \ 217 { \ 218 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 0), \ 219 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 1), \ 220 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 2), \ 221 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 3), \ 222 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 4), \ 223 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 5), \ 224 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 6), \ 225 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 7), \ 226 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 8), \ 227 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 9), \ 228 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 10), \ 229 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 11), \ 230 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 12), \ 231 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 13), \ 232 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 14), \ 233 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 15), \ 234 } 235 236#define DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(qos) \ 237 [DQA_INDEX_QOS_CLASS_##qos] = \ 238 DISPATCH_QUEUE_ATTR_PRIO_INIT(_DISPATCH_QOS_CLASS_##qos) 239 240const struct dispatch_queue_attr_s _dispatch_queue_attrs[] 241 [DISPATCH_QUEUE_ATTR_PRIO_COUNT][2][2] = { 242 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(UNSPECIFIED), 243 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(MAINTENANCE), 244 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(BACKGROUND), 245 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(UTILITY), 246 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(DEFAULT), 247 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(USER_INITIATED), 248 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(USER_INTERACTIVE), 249}; 250 251 252#pragma mark - 253#pragma mark dispatch_vtables 254 255DISPATCH_VTABLE_INSTANCE(semaphore, 256 .do_type = DISPATCH_SEMAPHORE_TYPE, 257 .do_kind = "semaphore", 258 .do_dispose = _dispatch_semaphore_dispose, 259 .do_debug = _dispatch_semaphore_debug, 260); 261 262DISPATCH_VTABLE_INSTANCE(group, 263 .do_type = DISPATCH_GROUP_TYPE, 264 .do_kind = "group", 265 .do_dispose = _dispatch_semaphore_dispose, 266 .do_debug = _dispatch_semaphore_debug, 267); 268 269DISPATCH_VTABLE_INSTANCE(queue, 270 .do_type = DISPATCH_QUEUE_TYPE, 271 .do_kind = "queue", 272 .do_dispose = _dispatch_queue_dispose, 273 .do_invoke = _dispatch_queue_invoke, 274 .do_probe = _dispatch_queue_probe, 275 .do_debug = dispatch_queue_debug, 276); 277 278DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_root, queue, 279 .do_type = DISPATCH_QUEUE_ROOT_TYPE, 280 .do_kind = "global-queue", 281 .do_dispose = _dispatch_pthread_root_queue_dispose, 282 .do_probe = _dispatch_root_queue_probe, 283 .do_debug = dispatch_queue_debug, 284); 285 286DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_runloop, queue, 287 .do_type = DISPATCH_QUEUE_ROOT_TYPE, 288 .do_kind = "runloop-queue", 289 .do_dispose = _dispatch_runloop_queue_dispose, 290 .do_invoke = _dispatch_queue_invoke, 291 .do_probe = _dispatch_runloop_queue_probe, 292 .do_debug = dispatch_queue_debug, 293); 294 295DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_mgr, queue, 296 .do_type = DISPATCH_QUEUE_MGR_TYPE, 297 .do_kind = "mgr-queue", 298 .do_invoke = _dispatch_mgr_thread, 299 .do_probe = _dispatch_mgr_queue_probe, 300 .do_debug = dispatch_queue_debug, 301); 302 303DISPATCH_VTABLE_INSTANCE(queue_specific_queue, 304 .do_type = DISPATCH_QUEUE_SPECIFIC_TYPE, 305 .do_kind = "queue-context", 306 .do_dispose = _dispatch_queue_specific_queue_dispose, 307 .do_invoke = (void*)_dispatch_queue_invoke, 308 .do_probe = (void *)_dispatch_queue_probe, 309 .do_debug = (void *)dispatch_queue_debug, 310); 311 312DISPATCH_VTABLE_INSTANCE(queue_attr, 313 .do_type = DISPATCH_QUEUE_ATTR_TYPE, 314 .do_kind = "queue-attr", 315); 316 317DISPATCH_VTABLE_INSTANCE(source, 318 .do_type = DISPATCH_SOURCE_KEVENT_TYPE, 319 .do_kind = "kevent-source", 320 .do_dispose = _dispatch_source_dispose, 321 .do_invoke = _dispatch_source_invoke, 322 .do_probe = _dispatch_source_probe, 323 .do_debug = _dispatch_source_debug, 324); 325 326DISPATCH_VTABLE_INSTANCE(mach, 327 .do_type = DISPATCH_MACH_CHANNEL_TYPE, 328 .do_kind = "mach-channel", 329 .do_dispose = _dispatch_mach_dispose, 330 .do_invoke = _dispatch_mach_invoke, 331 .do_probe = _dispatch_mach_probe, 332 .do_debug = _dispatch_mach_debug, 333); 334 335DISPATCH_VTABLE_INSTANCE(mach_msg, 336 .do_type = DISPATCH_MACH_MSG_TYPE, 337 .do_kind = "mach-msg", 338 .do_dispose = _dispatch_mach_msg_dispose, 339 .do_invoke = _dispatch_mach_msg_invoke, 340 .do_debug = _dispatch_mach_msg_debug, 341); 342 343#if !USE_OBJC 344DISPATCH_VTABLE_INSTANCE(data, 345 .do_type = DISPATCH_DATA_TYPE, 346 .do_kind = "data", 347 .do_dispose = _dispatch_data_dispose, 348 .do_debug = _dispatch_data_debug, 349); 350#endif 351 352DISPATCH_VTABLE_INSTANCE(io, 353 .do_type = DISPATCH_IO_TYPE, 354 .do_kind = "channel", 355 .do_dispose = _dispatch_io_dispose, 356 .do_debug = _dispatch_io_debug, 357); 358 359DISPATCH_VTABLE_INSTANCE(operation, 360 .do_type = DISPATCH_OPERATION_TYPE, 361 .do_kind = "operation", 362 .do_dispose = _dispatch_operation_dispose, 363 .do_debug = _dispatch_operation_debug, 364); 365 366DISPATCH_VTABLE_INSTANCE(disk, 367 .do_type = DISPATCH_DISK_TYPE, 368 .do_kind = "disk", 369 .do_dispose = _dispatch_disk_dispose, 370); 371 372void 373_dispatch_vtable_init(void) 374{ 375#if USE_OBJC 376 // ObjC classes and dispatch vtables are co-located via linker order and 377 // alias files, verify correct layout during initialization rdar://10640168 378 DISPATCH_OBJC_CLASS_DECL(semaphore); 379 dispatch_assert((char*)DISPATCH_VTABLE(semaphore) - 380 (char*)DISPATCH_OBJC_CLASS(semaphore) == 0); 381 dispatch_assert((char*)&DISPATCH_CONCAT(_,DISPATCH_CLASS(semaphore_vtable)) 382 - (char*)DISPATCH_OBJC_CLASS(semaphore) == 383 sizeof(_os_object_class_s)); 384#endif // USE_OBJC 385} 386 387#pragma mark - 388#pragma mark dispatch_bug 389 390static char _dispatch_build[16]; 391 392static void 393_dispatch_build_init(void *context DISPATCH_UNUSED) 394{ 395#ifdef __APPLE__ 396 int mib[] = { CTL_KERN, KERN_OSVERSION }; 397 size_t bufsz = sizeof(_dispatch_build); 398 399 sysctl(mib, 2, _dispatch_build, &bufsz, NULL, 0); 400#else 401 /* 402 * XXXRW: What to do here for !Mac OS X? 403 */ 404 memset(_dispatch_build, 0, sizeof(_dispatch_build)); 405#endif 406} 407 408static dispatch_once_t _dispatch_build_pred; 409 410char* 411_dispatch_get_build(void) 412{ 413 dispatch_once_f(&_dispatch_build_pred, NULL, _dispatch_build_init); 414 return _dispatch_build; 415} 416 417#define _dispatch_bug_log(msg, ...) do { \ 418 static void *last_seen; \ 419 void *ra = __builtin_return_address(0); \ 420 if (last_seen != ra) { \ 421 last_seen = ra; \ 422 _dispatch_log(msg, ##__VA_ARGS__); \ 423 } \ 424} while(0) 425 426void 427_dispatch_bug(size_t line, long val) 428{ 429 dispatch_once_f(&_dispatch_build_pred, NULL, _dispatch_build_init); 430 _dispatch_bug_log("BUG in libdispatch: %s - %lu - 0x%lx", 431 _dispatch_build, (unsigned long)line, val); 432} 433 434void 435_dispatch_bug_client(const char* msg) 436{ 437 _dispatch_bug_log("BUG in libdispatch client: %s", msg); 438} 439 440void 441_dispatch_bug_mach_client(const char* msg, mach_msg_return_t kr) 442{ 443 _dispatch_bug_log("BUG in libdispatch client: %s %s - 0x%x", msg, 444 mach_error_string(kr), kr); 445} 446 447void 448_dispatch_bug_kevent_client(const char* msg, const char* filter, 449 const char *operation, int err) 450{ 451 _dispatch_bug_log("BUG in libdispatch client: %s[%s] %s: \"%s\" - 0x%x", 452 msg, filter, operation, strerror(err), err); 453} 454 455void 456_dispatch_abort(size_t line, long val) 457{ 458 _dispatch_bug(line, val); 459 abort(); 460} 461 462#if !DISPATCH_USE_OS_DEBUG_LOG 463 464#pragma mark - 465#pragma mark dispatch_log 466 467static int dispatch_logfile = -1; 468static bool dispatch_log_disabled; 469static dispatch_once_t _dispatch_logv_pred; 470 471static void 472_dispatch_logv_init(void *context DISPATCH_UNUSED) 473{ 474#if DISPATCH_DEBUG 475 bool log_to_file = true; 476#else 477 bool log_to_file = false; 478#endif 479 char *e = getenv("LIBDISPATCH_LOG"); 480 if (e) { 481 if (strcmp(e, "YES") == 0) { 482 // default 483 } else if (strcmp(e, "NO") == 0) { 484 dispatch_log_disabled = true; 485 } else if (strcmp(e, "syslog") == 0) { 486 log_to_file = false; 487 } else if (strcmp(e, "file") == 0) { 488 log_to_file = true; 489 } else if (strcmp(e, "stderr") == 0) { 490 log_to_file = true; 491 dispatch_logfile = STDERR_FILENO; 492 } 493 } 494 if (!dispatch_log_disabled) { 495 if (log_to_file && dispatch_logfile == -1) { 496 char path[PATH_MAX]; 497 snprintf(path, sizeof(path), "/var/tmp/libdispatch.%d.log", 498 getpid()); 499 dispatch_logfile = open(path, O_WRONLY | O_APPEND | O_CREAT | 500 O_NOFOLLOW | O_CLOEXEC, 0666); 501 } 502 if (dispatch_logfile != -1) { 503 struct timeval tv; 504 gettimeofday(&tv, NULL); 505 dprintf(dispatch_logfile, "=== log file opened for %s[%u] at " 506 "%ld.%06u ===\n", getprogname() ?: "", getpid(), 507 tv.tv_sec, tv.tv_usec); 508 } 509 } 510} 511 512static inline void 513_dispatch_log_file(char *buf, size_t len) 514{ 515 ssize_t r; 516 517 buf[len++] = '\n'; 518retry: 519 r = write(dispatch_logfile, buf, len); 520 if (slowpath(r == -1) && errno == EINTR) { 521 goto retry; 522 } 523} 524 525DISPATCH_NOINLINE 526static void 527_dispatch_logv_file(const char *msg, va_list ap) 528{ 529 char buf[2048]; 530 int r = vsnprintf(buf, sizeof(buf), msg, ap); 531 if (r < 0) return; 532 size_t len = (size_t)r; 533 if (len > sizeof(buf) - 1) { 534 len = sizeof(buf) - 1; 535 } 536 _dispatch_log_file(buf, len); 537} 538 539#if DISPATCH_USE_SIMPLE_ASL 540static inline void 541_dispatch_syslog(const char *msg) 542{ 543 _simple_asl_log(ASL_LEVEL_NOTICE, "com.apple.libsystem.libdispatch", msg); 544} 545 546static inline void 547_dispatch_vsyslog(const char *msg, va_list ap) 548{ 549 char *str; 550 vasprintf(&str, msg, ap); 551 if (str) { 552 _dispatch_syslog(str); 553 free(str); 554 } 555} 556#else // DISPATCH_USE_SIMPLE_ASL 557static inline void 558_dispatch_syslog(const char *msg) 559{ 560 syslog(LOG_NOTICE, "%s", msg); 561} 562 563static inline void 564_dispatch_vsyslog(const char *msg, va_list ap) 565{ 566 vsyslog(LOG_NOTICE, msg, *ap_ptr); 567} 568#endif // DISPATCH_USE_SIMPLE_ASL 569 570DISPATCH_ALWAYS_INLINE 571static inline void 572_dispatch_logv(const char *msg, size_t len, va_list *ap_ptr) 573{ 574 dispatch_once_f(&_dispatch_logv_pred, NULL, _dispatch_logv_init); 575 if (slowpath(dispatch_log_disabled)) { 576 return; 577 } 578 if (slowpath(dispatch_logfile != -1)) { 579 if (!ap_ptr) { 580 return _dispatch_log_file((char*)msg, len); 581 } 582 return _dispatch_logv_file(msg, *ap_ptr); 583 } 584 if (!ap_ptr) { 585 return _dispatch_syslog(msg); 586 } 587 return _dispatch_vsyslog(msg, *ap_ptr); 588} 589 590DISPATCH_NOINLINE 591void 592_dispatch_log(const char *msg, ...) 593{ 594 va_list ap; 595 596 va_start(ap, msg); 597 _dispatch_logv(msg, 0, &ap); 598 va_end(ap); 599} 600 601#endif // DISPATCH_USE_OS_DEBUG_LOG 602 603#pragma mark - 604#pragma mark dispatch_debug 605 606static size_t 607_dispatch_object_debug2(dispatch_object_t dou, char* buf, size_t bufsiz) 608{ 609 DISPATCH_OBJECT_TFB(_dispatch_objc_debug, dou, buf, bufsiz); 610 if (dou._do->do_vtable->do_debug) { 611 return dx_debug(dou._do, buf, bufsiz); 612 } 613 return strlcpy(buf, "NULL vtable slot: ", bufsiz); 614} 615 616DISPATCH_NOINLINE 617static void 618_dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap) 619{ 620 char buf[2048]; 621 int r; 622 size_t offs; 623 if (dou._do) { 624 offs = _dispatch_object_debug2(dou, buf, sizeof(buf)); 625 dispatch_assert(offs + 2 < sizeof(buf)); 626 buf[offs++] = ':'; 627 buf[offs++] = ' '; 628 buf[offs] = '\0'; 629 } else { 630 offs = strlcpy(buf, "NULL: ", sizeof(buf)); 631 } 632 r = vsnprintf(buf + offs, sizeof(buf) - offs, msg, ap); 633#if !DISPATCH_USE_OS_DEBUG_LOG 634 size_t len = offs + (r < 0 ? 0 : (size_t)r); 635 if (len > sizeof(buf) - 1) { 636 len = sizeof(buf) - 1; 637 } 638 _dispatch_logv(buf, len, NULL); 639#else 640 _dispatch_log("%s", buf); 641#endif 642} 643 644DISPATCH_NOINLINE 645void 646dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap) 647{ 648 _dispatch_debugv(dou, msg, ap); 649} 650 651DISPATCH_NOINLINE 652void 653dispatch_debug(dispatch_object_t dou, const char *msg, ...) 654{ 655 va_list ap; 656 657 va_start(ap, msg); 658 _dispatch_debugv(dou, msg, ap); 659 va_end(ap); 660} 661 662#if DISPATCH_DEBUG 663DISPATCH_NOINLINE 664void 665_dispatch_object_debug(dispatch_object_t dou, const char *msg, ...) 666{ 667 va_list ap; 668 669 va_start(ap, msg); 670 _dispatch_debugv(dou._do, msg, ap); 671 va_end(ap); 672} 673#endif 674 675#pragma mark - 676#pragma mark dispatch_calloc 677 678DISPATCH_NOINLINE 679void 680_dispatch_temporary_resource_shortage(void) 681{ 682 sleep(1); 683} 684 685void * 686_dispatch_calloc(size_t num_items, size_t size) 687{ 688 void *buf; 689 while (!fastpath(buf = calloc(num_items, size))) { 690 _dispatch_temporary_resource_shortage(); 691 } 692 return buf; 693} 694 695#pragma mark - 696#pragma mark dispatch_block_t 697 698#ifdef __BLOCKS__ 699 700#undef _dispatch_Block_copy 701dispatch_block_t 702_dispatch_Block_copy(dispatch_block_t db) 703{ 704 dispatch_block_t rval; 705 706 if (fastpath(db)) { 707 while (!fastpath(rval = Block_copy(db))) { 708 _dispatch_temporary_resource_shortage(); 709 } 710 return rval; 711 } 712 DISPATCH_CLIENT_CRASH("NULL was passed where a block should have been"); 713} 714 715void 716_dispatch_call_block_and_release(void *block) 717{ 718 void (^b)(void) = block; 719 b(); 720 Block_release(b); 721} 722 723#pragma mark - 724#pragma mark _dispatch_block_create no_objc 725 726#if !USE_OBJC 727 728// The compiler hides the name of the function it generates, and changes it if 729// we try to reference it directly, but the linker still sees it. 730extern void DISPATCH_BLOCK_SPECIAL_INVOKE(void *) 731 asm("____dispatch_block_create_block_invoke"); 732void (*_dispatch_block_special_invoke)(void*) = DISPATCH_BLOCK_SPECIAL_INVOKE; 733 734dispatch_block_t 735_dispatch_block_create(dispatch_block_flags_t flags, voucher_t voucher, 736 pthread_priority_t pri, dispatch_block_t block) 737{ 738 dispatch_block_t copy_block = _dispatch_Block_copy(block); // 17094902 739 (void)voucher; // No voucher capture! (requires ObjC runtime) 740 struct dispatch_block_private_data_s dbpds = 741 DISPATCH_BLOCK_PRIVATE_DATA_INITIALIZER(flags, NULL, pri, copy_block); 742 dispatch_block_t new_block = _dispatch_Block_copy(^{ 743 // Capture object references, which retains copy_block. 744 // All retained objects must be captured by the *block*. We 745 // cannot borrow any references, because the block might be 746 // called zero or several times, so Block_release() is the 747 // only place that can release retained objects. 748 (void)copy_block; 749 _dispatch_block_invoke(&dbpds); 750 }); 751 Block_release(copy_block); 752 return new_block; 753} 754 755#endif // !USE_OBJC 756 757#endif // __BLOCKS__ 758 759#pragma mark - 760#pragma mark dispatch_client_callout 761 762// Abort on uncaught exceptions thrown from client callouts rdar://8577499 763#if DISPATCH_USE_CLIENT_CALLOUT && (__USING_SJLJ_EXCEPTIONS__ || !USE_OBJC) 764// On platforms with SjLj exceptions, avoid the SjLj overhead on every callout 765// by clearing the unwinder's TSD pointer to the handler stack around callouts 766 767#define _dispatch_get_tsd_base() 768#define _dispatch_get_unwind_tsd() (NULL) 769#define _dispatch_set_unwind_tsd(u) do {(void)(u);} while (0) 770#define _dispatch_free_unwind_tsd() 771 772#undef _dispatch_client_callout 773DISPATCH_NOINLINE 774void 775_dispatch_client_callout(void *ctxt, dispatch_function_t f) 776{ 777 _dispatch_get_tsd_base(); 778 void *u = _dispatch_get_unwind_tsd(); 779 if (fastpath(!u)) return f(ctxt); 780 _dispatch_set_unwind_tsd(NULL); 781 f(ctxt); 782 _dispatch_free_unwind_tsd(); 783 _dispatch_set_unwind_tsd(u); 784} 785 786#undef _dispatch_client_callout2 787DISPATCH_NOINLINE 788void 789_dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t)) 790{ 791 _dispatch_get_tsd_base(); 792 void *u = _dispatch_get_unwind_tsd(); 793 if (fastpath(!u)) return f(ctxt, i); 794 _dispatch_set_unwind_tsd(NULL); 795 f(ctxt, i); 796 _dispatch_free_unwind_tsd(); 797 _dispatch_set_unwind_tsd(u); 798} 799 800#undef _dispatch_client_callout3 801bool 802_dispatch_client_callout3(void *ctxt, dispatch_data_t region, size_t offset, 803 const void *buffer, size_t size, dispatch_data_applier_function_t f) 804{ 805 _dispatch_get_tsd_base(); 806 void *u = _dispatch_get_unwind_tsd(); 807 if (fastpath(!u)) return f(ctxt, region, offset, buffer, size); 808 _dispatch_set_unwind_tsd(NULL); 809 bool res = f(ctxt, region, offset, buffer, size); 810 _dispatch_free_unwind_tsd(); 811 _dispatch_set_unwind_tsd(u); 812 return res; 813} 814 815#undef _dispatch_client_callout4 816void 817_dispatch_client_callout4(void *ctxt, dispatch_mach_reason_t reason, 818 dispatch_mach_msg_t dmsg, mach_error_t error, 819 dispatch_mach_handler_function_t f) 820{ 821 _dispatch_get_tsd_base(); 822 void *u = _dispatch_get_unwind_tsd(); 823 if (fastpath(!u)) return f(ctxt, reason, dmsg, error); 824 _dispatch_set_unwind_tsd(NULL); 825 f(ctxt, reason, dmsg, error); 826 _dispatch_free_unwind_tsd(); 827 _dispatch_set_unwind_tsd(u); 828} 829 830#endif // DISPATCH_USE_CLIENT_CALLOUT 831 832#pragma mark - 833#pragma mark _os_object_t no_objc 834 835#if !USE_OBJC 836 837static const _os_object_class_s _os_object_class; 838 839void 840_os_object_init(void) 841{ 842 return; 843} 844 845inline _os_object_t 846_os_object_alloc_realized(const void *cls, size_t size) 847{ 848 _os_object_t obj; 849 dispatch_assert(size >= sizeof(struct _os_object_s)); 850 while (!fastpath(obj = calloc(1u, size))) { 851 _dispatch_temporary_resource_shortage(); 852 } 853 obj->os_obj_isa = cls; 854 return obj; 855} 856 857_os_object_t 858_os_object_alloc(const void *cls, size_t size) 859{ 860 if (!cls) cls = &_os_object_class; 861 return _os_object_alloc_realized(cls, size); 862} 863 864void 865_os_object_dealloc(_os_object_t obj) 866{ 867 *((void *volatile*)&obj->os_obj_isa) = (void *)0x200; 868 return free(obj); 869} 870 871void 872_os_object_xref_dispose(_os_object_t obj) 873{ 874 if (fastpath(obj->os_obj_isa->_os_obj_xref_dispose)) { 875 return obj->os_obj_isa->_os_obj_xref_dispose(obj); 876 } 877 return _os_object_release_internal(obj); 878} 879 880void 881_os_object_dispose(_os_object_t obj) 882{ 883 if (fastpath(obj->os_obj_isa->_os_obj_dispose)) { 884 return obj->os_obj_isa->_os_obj_dispose(obj); 885 } 886 return _os_object_dealloc(obj); 887} 888 889void* 890os_retain(void *obj) 891{ 892 if (fastpath(obj)) { 893 return _os_object_retain(obj); 894 } 895 return obj; 896} 897 898#undef os_release 899void 900os_release(void *obj) 901{ 902 if (fastpath(obj)) { 903 return _os_object_release(obj); 904 } 905} 906 907#pragma mark - 908#pragma mark dispatch_autorelease_pool no_objc 909 910#if DISPATCH_COCOA_COMPAT 911 912void *_dispatch_autorelease_pool_push(void) { 913 void *pool = NULL; 914 if (_dispatch_begin_NSAutoReleasePool) { 915 pool = _dispatch_begin_NSAutoReleasePool(); 916 } 917 return pool; 918} 919 920void _dispatch_autorelease_pool_pop(void *pool) { 921 if (_dispatch_end_NSAutoReleasePool) { 922 _dispatch_end_NSAutoReleasePool(pool); 923 } 924} 925 926#endif // DISPATCH_COCOA_COMPAT 927#endif // !USE_OBJC 928 929#pragma mark - 930#pragma mark dispatch_source_types 931 932static void 933dispatch_source_type_timer_init(dispatch_source_t ds, 934 dispatch_source_type_t type DISPATCH_UNUSED, 935 uintptr_t handle DISPATCH_UNUSED, 936 unsigned long mask, 937 dispatch_queue_t q) 938{ 939 if (fastpath(!ds->ds_refs)) { 940 ds->ds_refs = _dispatch_calloc(1ul, 941 sizeof(struct dispatch_timer_source_refs_s)); 942 } 943 ds->ds_needs_rearm = true; 944 ds->ds_is_timer = true; 945 if (q == dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) 946 || q == dispatch_get_global_queue( 947 DISPATCH_QUEUE_PRIORITY_BACKGROUND, DISPATCH_QUEUE_OVERCOMMIT)){ 948 mask |= DISPATCH_TIMER_BACKGROUND; // <rdar://problem/12200216> 949 } 950 ds_timer(ds->ds_refs).flags = mask; 951} 952 953const struct dispatch_source_type_s _dispatch_source_type_timer = { 954 .ke = { 955 .filter = DISPATCH_EVFILT_TIMER, 956 }, 957 .mask = DISPATCH_TIMER_STRICT|DISPATCH_TIMER_BACKGROUND| 958 DISPATCH_TIMER_WALL_CLOCK, 959 .init = dispatch_source_type_timer_init, 960}; 961 962static void 963dispatch_source_type_timer_with_aggregate_init(dispatch_source_t ds, 964 dispatch_source_type_t type, uintptr_t handle, unsigned long mask, 965 dispatch_queue_t q) 966{ 967 ds->ds_refs = _dispatch_calloc(1ul, 968 sizeof(struct dispatch_timer_source_aggregate_refs_s)); 969 dispatch_source_type_timer_init(ds, type, handle, mask, q); 970 ds_timer(ds->ds_refs).flags |= DISPATCH_TIMER_WITH_AGGREGATE; 971 ds->dq_specific_q = (void*)handle; 972 _dispatch_retain(ds->dq_specific_q); 973} 974 975const struct dispatch_source_type_s _dispatch_source_type_timer_with_aggregate={ 976 .ke = { 977 .filter = DISPATCH_EVFILT_TIMER, 978 .ident = ~0ull, 979 }, 980 .mask = DISPATCH_TIMER_STRICT|DISPATCH_TIMER_BACKGROUND, 981 .init = dispatch_source_type_timer_with_aggregate_init, 982}; 983 984static void 985dispatch_source_type_interval_init(dispatch_source_t ds, 986 dispatch_source_type_t type, uintptr_t handle, unsigned long mask, 987 dispatch_queue_t q) 988{ 989 dispatch_source_type_timer_init(ds, type, handle, mask, q); 990 ds_timer(ds->ds_refs).flags |= DISPATCH_TIMER_INTERVAL; 991 unsigned long ident = _dispatch_source_timer_idx(ds->ds_refs); 992 ds->ds_dkev->dk_kevent.ident = ds->ds_ident_hack = ident; 993 _dispatch_source_set_interval(ds, handle); 994} 995 996const struct dispatch_source_type_s _dispatch_source_type_interval = { 997 .ke = { 998 .filter = DISPATCH_EVFILT_TIMER, 999 .ident = ~0ull, 1000 }, 1001 .mask = DISPATCH_TIMER_STRICT|DISPATCH_TIMER_BACKGROUND| 1002 DISPATCH_INTERVAL_UI_ANIMATION, 1003 .init = dispatch_source_type_interval_init, 1004}; 1005 1006const struct dispatch_source_type_s _dispatch_source_type_read = { 1007 .ke = { 1008 .filter = EVFILT_READ, 1009 .flags = EV_DISPATCH, 1010 }, 1011}; 1012 1013const struct dispatch_source_type_s _dispatch_source_type_write = { 1014 .ke = { 1015 .filter = EVFILT_WRITE, 1016 .flags = EV_DISPATCH, 1017 }, 1018}; 1019 1020#if DISPATCH_USE_MEMORYSTATUS 1021 1022#if TARGET_IPHONE_SIMULATOR // rdar://problem/9219483 1023static int _dispatch_ios_simulator_memory_warnings_fd = -1; 1024static void 1025_dispatch_ios_simulator_memorypressure_init(void *context DISPATCH_UNUSED) 1026{ 1027 char *e = getenv("SIMULATOR_MEMORY_WARNINGS"); 1028 if (!e) return; 1029 _dispatch_ios_simulator_memory_warnings_fd = open(e, O_EVTONLY); 1030 if (_dispatch_ios_simulator_memory_warnings_fd == -1) { 1031 (void)dispatch_assume_zero(errno); 1032 } 1033} 1034#endif 1035 1036static void 1037dispatch_source_type_memorystatus_init(dispatch_source_t ds, 1038 dispatch_source_type_t type DISPATCH_UNUSED, 1039 uintptr_t handle DISPATCH_UNUSED, 1040 unsigned long mask DISPATCH_UNUSED, 1041 dispatch_queue_t q DISPATCH_UNUSED) 1042{ 1043#if TARGET_IPHONE_SIMULATOR 1044 static dispatch_once_t pred; 1045 dispatch_once_f(&pred, NULL, _dispatch_ios_simulator_memorypressure_init); 1046 handle = (uintptr_t)_dispatch_ios_simulator_memory_warnings_fd; 1047 mask = NOTE_ATTRIB; 1048 ds->ds_dkev->dk_kevent.filter = EVFILT_VNODE; 1049 ds->ds_dkev->dk_kevent.ident = handle; 1050 ds->ds_dkev->dk_kevent.flags |= EV_CLEAR; 1051 ds->ds_dkev->dk_kevent.fflags = (uint32_t)mask; 1052 ds->ds_ident_hack = handle; 1053 ds->ds_pending_data_mask = mask; 1054 ds->ds_memorystatus_override = 1; 1055#endif 1056 ds->ds_is_level = false; 1057} 1058 1059#ifndef NOTE_MEMORYSTATUS_LOW_SWAP 1060#define NOTE_MEMORYSTATUS_LOW_SWAP 0x8 1061#endif 1062 1063const struct dispatch_source_type_s _dispatch_source_type_memorystatus = { 1064 .ke = { 1065 .filter = EVFILT_MEMORYSTATUS, 1066 .flags = EV_DISPATCH, 1067 }, 1068 .mask = NOTE_MEMORYSTATUS_PRESSURE_NORMAL|NOTE_MEMORYSTATUS_PRESSURE_WARN 1069 |NOTE_MEMORYSTATUS_PRESSURE_CRITICAL|NOTE_MEMORYSTATUS_LOW_SWAP, 1070 .init = dispatch_source_type_memorystatus_init, 1071}; 1072 1073static void 1074dispatch_source_type_vm_init(dispatch_source_t ds, 1075 dispatch_source_type_t type, 1076 uintptr_t handle, 1077 unsigned long mask, 1078 dispatch_queue_t q) 1079{ 1080 // Map legacy vm pressure to memorystatus warning rdar://problem/15907505 1081 mask = NOTE_MEMORYSTATUS_PRESSURE_WARN; 1082 ds->ds_dkev->dk_kevent.fflags = (uint32_t)mask; 1083 ds->ds_pending_data_mask = mask; 1084 ds->ds_vmpressure_override = 1; 1085 dispatch_source_type_memorystatus_init(ds, type, handle, mask, q); 1086} 1087 1088const struct dispatch_source_type_s _dispatch_source_type_vm = { 1089 .ke = { 1090 .filter = EVFILT_MEMORYSTATUS, 1091 .flags = EV_DISPATCH, 1092 }, 1093 .mask = NOTE_VM_PRESSURE, 1094 .init = dispatch_source_type_vm_init, 1095}; 1096 1097#elif DISPATCH_USE_VM_PRESSURE 1098 1099static void 1100dispatch_source_type_vm_init(dispatch_source_t ds, 1101 dispatch_source_type_t type DISPATCH_UNUSED, 1102 uintptr_t handle DISPATCH_UNUSED, 1103 unsigned long mask DISPATCH_UNUSED, 1104 dispatch_queue_t q DISPATCH_UNUSED) 1105{ 1106 ds->ds_is_level = false; 1107} 1108 1109const struct dispatch_source_type_s _dispatch_source_type_vm = { 1110 .ke = { 1111 .filter = EVFILT_VM, 1112 .flags = EV_DISPATCH, 1113 }, 1114 .mask = NOTE_VM_PRESSURE, 1115 .init = dispatch_source_type_vm_init, 1116}; 1117 1118#endif // DISPATCH_USE_VM_PRESSURE 1119 1120const struct dispatch_source_type_s _dispatch_source_type_proc = { 1121 .ke = { 1122 .filter = EVFILT_PROC, 1123 .flags = EV_CLEAR, 1124 }, 1125 .mask = NOTE_EXIT|NOTE_FORK|NOTE_EXEC 1126#if HAVE_DECL_NOTE_SIGNAL 1127 |NOTE_SIGNAL 1128#endif 1129#if HAVE_DECL_NOTE_REAP 1130 |NOTE_REAP 1131#endif 1132 , 1133}; 1134 1135const struct dispatch_source_type_s _dispatch_source_type_signal = { 1136 .ke = { 1137 .filter = EVFILT_SIGNAL, 1138 }, 1139}; 1140 1141const struct dispatch_source_type_s _dispatch_source_type_vnode = { 1142 .ke = { 1143 .filter = EVFILT_VNODE, 1144 .flags = EV_CLEAR, 1145 }, 1146 .mask = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK| 1147 NOTE_RENAME|NOTE_REVOKE 1148#if HAVE_DECL_NOTE_NONE 1149 |NOTE_NONE 1150#endif 1151 , 1152}; 1153 1154const struct dispatch_source_type_s _dispatch_source_type_vfs = { 1155 .ke = { 1156 .filter = EVFILT_FS, 1157 .flags = EV_CLEAR, 1158 }, 1159 .mask = VQ_NOTRESP|VQ_NEEDAUTH|VQ_LOWDISK|VQ_MOUNT|VQ_UNMOUNT|VQ_DEAD| 1160 VQ_ASSIST|VQ_NOTRESPLOCK 1161#if HAVE_DECL_VQ_UPDATE 1162 |VQ_UPDATE 1163#endif 1164#if HAVE_DECL_VQ_VERYLOWDISK 1165 |VQ_VERYLOWDISK 1166#endif 1167 , 1168}; 1169 1170const struct dispatch_source_type_s _dispatch_source_type_sock = { 1171#ifdef EVFILT_SOCK 1172 .ke = { 1173 .filter = EVFILT_SOCK, 1174 .flags = EV_CLEAR, 1175 }, 1176 .mask = NOTE_CONNRESET | NOTE_READCLOSED | NOTE_WRITECLOSED | 1177 NOTE_TIMEOUT | NOTE_NOSRCADDR | NOTE_IFDENIED | NOTE_SUSPEND | 1178 NOTE_RESUME | NOTE_KEEPALIVE 1179#ifdef NOTE_ADAPTIVE_WTIMO 1180 | NOTE_ADAPTIVE_WTIMO | NOTE_ADAPTIVE_RTIMO 1181#endif 1182#ifdef NOTE_CONNECTED 1183 | NOTE_CONNECTED | NOTE_DISCONNECTED | NOTE_CONNINFO_UPDATED 1184#endif 1185 , 1186#endif // EVFILT_SOCK 1187}; 1188 1189const struct dispatch_source_type_s _dispatch_source_type_data_add = { 1190 .ke = { 1191 .filter = DISPATCH_EVFILT_CUSTOM_ADD, 1192 }, 1193}; 1194 1195const struct dispatch_source_type_s _dispatch_source_type_data_or = { 1196 .ke = { 1197 .filter = DISPATCH_EVFILT_CUSTOM_OR, 1198 .flags = EV_CLEAR, 1199 .fflags = ~0u, 1200 }, 1201}; 1202 1203#if HAVE_MACH 1204 1205static void 1206dispatch_source_type_mach_send_init(dispatch_source_t ds, 1207 dispatch_source_type_t type DISPATCH_UNUSED, 1208 uintptr_t handle DISPATCH_UNUSED, unsigned long mask, 1209 dispatch_queue_t q DISPATCH_UNUSED) 1210{ 1211 if (!mask) { 1212 // Preserve legacy behavior that (mask == 0) => DISPATCH_MACH_SEND_DEAD 1213 ds->ds_dkev->dk_kevent.fflags = DISPATCH_MACH_SEND_DEAD; 1214 ds->ds_pending_data_mask = DISPATCH_MACH_SEND_DEAD; 1215 } 1216} 1217 1218const struct dispatch_source_type_s _dispatch_source_type_mach_send = { 1219 .ke = { 1220 .filter = DISPATCH_EVFILT_MACH_NOTIFICATION, 1221 .flags = EV_CLEAR, 1222 }, 1223 .mask = DISPATCH_MACH_SEND_DEAD|DISPATCH_MACH_SEND_POSSIBLE, 1224 .init = dispatch_source_type_mach_send_init, 1225}; 1226 1227static void 1228dispatch_source_type_mach_recv_init(dispatch_source_t ds, 1229 dispatch_source_type_t type DISPATCH_UNUSED, 1230 uintptr_t handle DISPATCH_UNUSED, 1231 unsigned long mask DISPATCH_UNUSED, 1232 dispatch_queue_t q DISPATCH_UNUSED) 1233{ 1234 ds->ds_is_level = false; 1235} 1236 1237const struct dispatch_source_type_s _dispatch_source_type_mach_recv = { 1238 .ke = { 1239 .filter = EVFILT_MACHPORT, 1240 .flags = EV_DISPATCH, 1241 .fflags = DISPATCH_MACH_RECV_MESSAGE, 1242 }, 1243 .init = dispatch_source_type_mach_recv_init, 1244}; 1245 1246#pragma mark - 1247#pragma mark dispatch_mig 1248 1249void * 1250dispatch_mach_msg_get_context(mach_msg_header_t *msg) 1251{ 1252 mach_msg_context_trailer_t *tp; 1253 void *context = NULL; 1254 1255 tp = (mach_msg_context_trailer_t *)((uint8_t *)msg + 1256 round_msg(msg->msgh_size)); 1257 if (tp->msgh_trailer_size >= 1258 (mach_msg_size_t)sizeof(mach_msg_context_trailer_t)) { 1259 context = (void *)(uintptr_t)tp->msgh_context; 1260 } 1261 return context; 1262} 1263 1264kern_return_t 1265_dispatch_wakeup_runloop_thread(mach_port_t mp DISPATCH_UNUSED) 1266{ 1267 // dummy function just to pop a runloop thread out of mach_msg() 1268 return 0; 1269} 1270 1271kern_return_t 1272_dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED) 1273{ 1274 // dummy function to consume a send-once right 1275 return 0; 1276} 1277 1278kern_return_t 1279_dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED, 1280 mach_port_t name) 1281{ 1282 kern_return_t kr; 1283 // this function should never be called 1284 (void)dispatch_assume_zero(name); 1285 kr = mach_port_mod_refs(mach_task_self(), name, MACH_PORT_RIGHT_RECEIVE,-1); 1286 DISPATCH_VERIFY_MIG(kr); 1287 (void)dispatch_assume_zero(kr); 1288 return KERN_SUCCESS; 1289} 1290 1291kern_return_t 1292_dispatch_mach_notify_no_senders(mach_port_t notify, 1293 mach_port_mscount_t mscnt DISPATCH_UNUSED) 1294{ 1295 // this function should never be called 1296 (void)dispatch_assume_zero(notify); 1297 return KERN_SUCCESS; 1298} 1299 1300kern_return_t 1301_dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED) 1302{ 1303 // we only register for dead-name notifications 1304 // some code deallocated our send-once right without consuming it 1305#if DISPATCH_DEBUG 1306 _dispatch_log("Corruption: An app/library deleted a libdispatch " 1307 "dead-name notification"); 1308#endif 1309 return KERN_SUCCESS; 1310} 1311 1312#endif // HAVE_MACH 1313