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; 74#if DISPATCH_INTROSPECTION 75pthread_key_t dispatch_introspection_key; 76#elif DISPATCH_PERF_MON 77pthread_key_t dispatch_bcounter_key; 78#endif 79#endif // !DISPATCH_USE_DIRECT_TSD 80 81struct _dispatch_hw_config_s _dispatch_hw_config; 82bool _dispatch_safe_fork = true, _dispatch_child_of_unsafe_fork; 83 84DISPATCH_NOINLINE 85bool 86_dispatch_is_multithreaded(void) 87{ 88 return !_dispatch_safe_fork; 89} 90 91 92DISPATCH_NOINLINE 93bool 94_dispatch_is_fork_of_multithreaded_parent(void) 95{ 96 return _dispatch_child_of_unsafe_fork; 97} 98 99const struct dispatch_queue_offsets_s dispatch_queue_offsets = { 100 .dqo_version = 4, 101 .dqo_label = offsetof(struct dispatch_queue_s, dq_label), 102 .dqo_label_size = sizeof(((dispatch_queue_t)NULL)->dq_label), 103 .dqo_flags = 0, 104 .dqo_flags_size = 0, 105 .dqo_width = offsetof(struct dispatch_queue_s, dq_width), 106 .dqo_width_size = sizeof(((dispatch_queue_t)NULL)->dq_width), 107 .dqo_serialnum = offsetof(struct dispatch_queue_s, dq_serialnum), 108 .dqo_serialnum_size = sizeof(((dispatch_queue_t)NULL)->dq_serialnum), 109 .dqo_running = offsetof(struct dispatch_queue_s, dq_running), 110 .dqo_running_size = sizeof(((dispatch_queue_t)NULL)->dq_running), 111}; 112 113// 6618342 Contact the team that owns the Instrument DTrace probe before 114// renaming this symbol 115DISPATCH_CACHELINE_ALIGN 116struct dispatch_queue_s _dispatch_main_q = { 117 .do_vtable = DISPATCH_VTABLE(queue), 118#if !DISPATCH_USE_RESOLVERS 119 .do_targetq = &_dispatch_root_queues[ 120 DISPATCH_ROOT_QUEUE_IDX_DEFAULT_OVERCOMMIT_PRIORITY], 121#endif 122 .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, 123 .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, 124 .do_suspend_cnt = DISPATCH_OBJECT_SUSPEND_LOCK, 125 .dq_label = "com.apple.main-thread", 126 .dq_running = 1, 127 .dq_width = 1, 128 .dq_is_thread_bound = 1, 129 .dq_serialnum = 1, 130}; 131 132struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent = { 133 .do_vtable = DISPATCH_VTABLE(queue_attr), 134 .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, 135 .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, 136 .do_next = DISPATCH_OBJECT_LISTLESS, 137}; 138 139#pragma mark - 140#pragma mark dispatch_vtables 141 142DISPATCH_VTABLE_INSTANCE(semaphore, 143 .do_type = DISPATCH_SEMAPHORE_TYPE, 144 .do_kind = "semaphore", 145 .do_dispose = _dispatch_semaphore_dispose, 146 .do_debug = _dispatch_semaphore_debug, 147); 148 149DISPATCH_VTABLE_INSTANCE(group, 150 .do_type = DISPATCH_GROUP_TYPE, 151 .do_kind = "group", 152 .do_dispose = _dispatch_semaphore_dispose, 153 .do_debug = _dispatch_semaphore_debug, 154); 155 156DISPATCH_VTABLE_INSTANCE(queue, 157 .do_type = DISPATCH_QUEUE_TYPE, 158 .do_kind = "queue", 159 .do_dispose = _dispatch_queue_dispose, 160 .do_invoke = _dispatch_queue_invoke, 161 .do_probe = _dispatch_queue_probe, 162 .do_debug = dispatch_queue_debug, 163); 164 165DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_root, queue, 166 .do_type = DISPATCH_QUEUE_ROOT_TYPE, 167 .do_kind = "global-queue", 168 .do_dispose = _dispatch_pthread_root_queue_dispose, 169 .do_probe = _dispatch_root_queue_probe, 170 .do_debug = dispatch_queue_debug, 171); 172 173DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_runloop, queue, 174 .do_type = DISPATCH_QUEUE_ROOT_TYPE, 175 .do_kind = "runloop-queue", 176 .do_dispose = _dispatch_runloop_queue_dispose, 177 .do_invoke = _dispatch_queue_invoke, 178 .do_probe = _dispatch_runloop_queue_probe, 179 .do_debug = dispatch_queue_debug, 180); 181 182DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_mgr, queue, 183 .do_type = DISPATCH_QUEUE_MGR_TYPE, 184 .do_kind = "mgr-queue", 185 .do_invoke = _dispatch_mgr_thread, 186 .do_probe = _dispatch_mgr_queue_probe, 187 .do_debug = dispatch_queue_debug, 188); 189 190DISPATCH_VTABLE_INSTANCE(queue_specific_queue, 191 .do_type = DISPATCH_QUEUE_SPECIFIC_TYPE, 192 .do_kind = "queue-context", 193 .do_dispose = _dispatch_queue_specific_queue_dispose, 194 .do_invoke = (void*)_dispatch_queue_invoke, 195 .do_probe = (void *)_dispatch_queue_probe, 196 .do_debug = (void *)dispatch_queue_debug, 197); 198 199DISPATCH_VTABLE_INSTANCE(queue_attr, 200 .do_type = DISPATCH_QUEUE_ATTR_TYPE, 201 .do_kind = "queue-attr", 202); 203 204DISPATCH_VTABLE_INSTANCE(source, 205 .do_type = DISPATCH_SOURCE_KEVENT_TYPE, 206 .do_kind = "kevent-source", 207 .do_dispose = _dispatch_source_dispose, 208 .do_invoke = _dispatch_source_invoke, 209 .do_probe = _dispatch_source_probe, 210 .do_debug = _dispatch_source_debug, 211); 212 213DISPATCH_VTABLE_INSTANCE(mach, 214 .do_type = DISPATCH_MACH_CHANNEL_TYPE, 215 .do_kind = "mach-channel", 216 .do_dispose = _dispatch_mach_dispose, 217 .do_invoke = _dispatch_mach_invoke, 218 .do_probe = _dispatch_mach_probe, 219 .do_debug = _dispatch_mach_debug, 220); 221 222DISPATCH_VTABLE_INSTANCE(mach_msg, 223 .do_type = DISPATCH_MACH_MSG_TYPE, 224 .do_kind = "mach-msg", 225 .do_dispose = _dispatch_mach_msg_dispose, 226 .do_invoke = _dispatch_mach_msg_invoke, 227 .do_debug = _dispatch_mach_msg_debug, 228); 229 230#if !USE_OBJC 231DISPATCH_VTABLE_INSTANCE(data, 232 .do_type = DISPATCH_DATA_TYPE, 233 .do_kind = "data", 234 .do_dispose = _dispatch_data_dispose, 235 .do_debug = _dispatch_data_debug, 236); 237#endif 238 239DISPATCH_VTABLE_INSTANCE(io, 240 .do_type = DISPATCH_IO_TYPE, 241 .do_kind = "channel", 242 .do_dispose = _dispatch_io_dispose, 243 .do_debug = _dispatch_io_debug, 244); 245 246DISPATCH_VTABLE_INSTANCE(operation, 247 .do_type = DISPATCH_OPERATION_TYPE, 248 .do_kind = "operation", 249 .do_dispose = _dispatch_operation_dispose, 250 .do_debug = _dispatch_operation_debug, 251); 252 253DISPATCH_VTABLE_INSTANCE(disk, 254 .do_type = DISPATCH_DISK_TYPE, 255 .do_kind = "disk", 256 .do_dispose = _dispatch_disk_dispose, 257); 258 259void 260_dispatch_vtable_init(void) 261{ 262#if USE_OBJC 263 // ObjC classes and dispatch vtables are co-located via linker order and 264 // alias files, verify correct layout during initialization rdar://10640168 265 DISPATCH_OBJC_CLASS_DECL(semaphore); 266 dispatch_assert((char*)DISPATCH_VTABLE(semaphore) - 267 (char*)DISPATCH_OBJC_CLASS(semaphore) == 0); 268 dispatch_assert((char*)&DISPATCH_CONCAT(_,DISPATCH_CLASS(semaphore_vtable)) 269 - (char*)DISPATCH_OBJC_CLASS(semaphore) == 270 sizeof(_os_object_class_s)); 271#endif // USE_OBJC 272} 273 274#pragma mark - 275#pragma mark dispatch_bug 276 277static char _dispatch_build[16]; 278 279static void 280_dispatch_build_init(void *context DISPATCH_UNUSED) 281{ 282#ifdef __APPLE__ 283 int mib[] = { CTL_KERN, KERN_OSVERSION }; 284 size_t bufsz = sizeof(_dispatch_build); 285 286 sysctl(mib, 2, _dispatch_build, &bufsz, NULL, 0); 287#else 288 /* 289 * XXXRW: What to do here for !Mac OS X? 290 */ 291 memset(_dispatch_build, 0, sizeof(_dispatch_build)); 292#endif 293} 294 295static dispatch_once_t _dispatch_build_pred; 296 297char* 298_dispatch_get_build(void) 299{ 300 dispatch_once_f(&_dispatch_build_pred, NULL, _dispatch_build_init); 301 return _dispatch_build; 302} 303 304#define _dispatch_bug_log(msg, ...) do { \ 305 static void *last_seen; \ 306 void *ra = __builtin_return_address(0); \ 307 if (last_seen != ra) { \ 308 last_seen = ra; \ 309 _dispatch_log(msg, ##__VA_ARGS__); \ 310 } \ 311} while(0) 312 313void 314_dispatch_bug(size_t line, long val) 315{ 316 dispatch_once_f(&_dispatch_build_pred, NULL, _dispatch_build_init); 317 _dispatch_bug_log("BUG in libdispatch: %s - %lu - 0x%lx", 318 _dispatch_build, (unsigned long)line, val); 319} 320 321void 322_dispatch_bug_client(const char* msg) 323{ 324 _dispatch_bug_log("BUG in libdispatch client: %s", msg); 325} 326 327void 328_dispatch_bug_mach_client(const char* msg, mach_msg_return_t kr) 329{ 330 _dispatch_bug_log("BUG in libdispatch client: %s %s - 0x%x", msg, 331 mach_error_string(kr), kr); 332} 333 334void 335_dispatch_bug_kevent_client(const char* msg, const char* filter, 336 const char *operation, int err) 337{ 338 _dispatch_bug_log("BUG in libdispatch client: %s[%s] %s: \"%s\" - 0x%x", 339 msg, filter, operation, strerror(err), err); 340} 341 342void 343_dispatch_abort(size_t line, long val) 344{ 345 _dispatch_bug(line, val); 346 abort(); 347} 348 349#if !DISPATCH_USE_OS_TRACE 350 351#pragma mark - 352#pragma mark dispatch_log 353 354static int dispatch_logfile = -1; 355static bool dispatch_log_disabled; 356static dispatch_once_t _dispatch_logv_pred; 357 358static void 359_dispatch_logv_init(void *context DISPATCH_UNUSED) 360{ 361#if DISPATCH_DEBUG 362 bool log_to_file = true; 363#else 364 bool log_to_file = false; 365#endif 366 char *e = getenv("LIBDISPATCH_LOG"); 367 if (e) { 368 if (strcmp(e, "YES") == 0) { 369 // default 370 } else if (strcmp(e, "NO") == 0) { 371 dispatch_log_disabled = true; 372 } else if (strcmp(e, "syslog") == 0) { 373 log_to_file = false; 374 } else if (strcmp(e, "file") == 0) { 375 log_to_file = true; 376 } else if (strcmp(e, "stderr") == 0) { 377 log_to_file = true; 378 dispatch_logfile = STDERR_FILENO; 379 } 380 } 381 if (!dispatch_log_disabled) { 382 if (log_to_file && dispatch_logfile == -1) { 383 char path[PATH_MAX]; 384 snprintf(path, sizeof(path), "/var/tmp/libdispatch.%d.log", 385 getpid()); 386 dispatch_logfile = open(path, O_WRONLY | O_APPEND | O_CREAT | 387 O_NOFOLLOW | O_CLOEXEC, 0666); 388 } 389 if (dispatch_logfile != -1) { 390 struct timeval tv; 391 gettimeofday(&tv, NULL); 392 dprintf(dispatch_logfile, "=== log file opened for %s[%u] at " 393 "%ld.%06u ===\n", getprogname() ?: "", getpid(), 394 tv.tv_sec, tv.tv_usec); 395 } 396 } 397} 398 399static inline void 400_dispatch_log_file(char *buf, size_t len) 401{ 402 ssize_t r; 403 404 buf[len++] = '\n'; 405retry: 406 r = write(dispatch_logfile, buf, len); 407 if (slowpath(r == -1) && errno == EINTR) { 408 goto retry; 409 } 410} 411 412DISPATCH_NOINLINE 413static void 414_dispatch_logv_file(const char *msg, va_list ap) 415{ 416 char buf[2048]; 417 int r = vsnprintf(buf, sizeof(buf), msg, ap); 418 if (r < 0) return; 419 size_t len = (size_t)r; 420 if (len > sizeof(buf) - 1) { 421 len = sizeof(buf) - 1; 422 } 423 _dispatch_log_file(buf, len); 424} 425 426DISPATCH_ALWAYS_INLINE 427static inline void 428_dispatch_logv(const char *msg, size_t len, va_list ap) 429{ 430 dispatch_once_f(&_dispatch_logv_pred, NULL, _dispatch_logv_init); 431 if (slowpath(dispatch_log_disabled)) { 432 return; 433 } 434 if (slowpath(dispatch_logfile != -1)) { 435 if (!ap) { 436 return _dispatch_log_file((char*)msg, len); 437 } 438 return _dispatch_logv_file(msg, ap); 439 } 440 if (!ap) { 441 return syslog(LOG_NOTICE, "%s", msg); 442 } 443 return vsyslog(LOG_NOTICE, msg, ap); 444} 445 446DISPATCH_NOINLINE 447void 448_dispatch_log(const char *msg, ...) 449{ 450 va_list ap; 451 452 va_start(ap, msg); 453 _dispatch_logv(msg, 0, ap); 454 va_end(ap); 455} 456 457#endif // DISPATCH_USE_OS_TRACE 458 459#pragma mark - 460#pragma mark dispatch_debug 461 462static size_t 463_dispatch_object_debug2(dispatch_object_t dou, char* buf, size_t bufsiz) 464{ 465 DISPATCH_OBJECT_TFB(_dispatch_objc_debug, dou, buf, bufsiz); 466 if (dou._do->do_vtable->do_debug) { 467 return dx_debug(dou._do, buf, bufsiz); 468 } 469 return strlcpy(buf, "NULL vtable slot: ", bufsiz); 470} 471 472DISPATCH_NOINLINE 473static void 474_dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap) 475{ 476 char buf[2048]; 477 int r; 478 size_t offs; 479 if (dou._do) { 480 offs = _dispatch_object_debug2(dou, buf, sizeof(buf)); 481 dispatch_assert(offs + 2 < sizeof(buf)); 482 buf[offs++] = ':'; 483 buf[offs++] = ' '; 484 buf[offs] = '\0'; 485 } else { 486 offs = strlcpy(buf, "NULL: ", sizeof(buf)); 487 } 488 r = vsnprintf(buf + offs, sizeof(buf) - offs, msg, ap); 489#if !DISPATCH_USE_OS_TRACE 490 size_t len = offs + (r < 0 ? 0 : (size_t)r); 491 if (len > sizeof(buf) - 1) { 492 len = sizeof(buf) - 1; 493 } 494 _dispatch_logv(buf, len, NULL); 495#else 496 _dispatch_log("%s", buf); 497#endif 498} 499 500DISPATCH_NOINLINE 501void 502dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap) 503{ 504 _dispatch_debugv(dou, msg, ap); 505} 506 507DISPATCH_NOINLINE 508void 509dispatch_debug(dispatch_object_t dou, const char *msg, ...) 510{ 511 va_list ap; 512 513 va_start(ap, msg); 514 _dispatch_debugv(dou, msg, ap); 515 va_end(ap); 516} 517 518#if DISPATCH_DEBUG 519DISPATCH_NOINLINE 520void 521_dispatch_object_debug(dispatch_object_t dou, const char *msg, ...) 522{ 523 va_list ap; 524 525 va_start(ap, msg); 526 _dispatch_debugv(dou._do, msg, ap); 527 va_end(ap); 528} 529#endif 530 531#pragma mark - 532#pragma mark dispatch_calloc 533 534DISPATCH_NOINLINE 535void 536_dispatch_temporary_resource_shortage(void) 537{ 538 sleep(1); 539} 540 541void * 542_dispatch_calloc(size_t num_items, size_t size) 543{ 544 void *buf; 545 while (!fastpath(buf = calloc(num_items, size))) { 546 _dispatch_temporary_resource_shortage(); 547 } 548 return buf; 549} 550 551#pragma mark - 552#pragma mark dispatch_block_t 553 554#ifdef __BLOCKS__ 555 556#undef _dispatch_Block_copy 557dispatch_block_t 558_dispatch_Block_copy(dispatch_block_t db) 559{ 560 dispatch_block_t rval; 561 562 if (fastpath(db)) { 563 while (!fastpath(rval = Block_copy(db))) { 564 _dispatch_temporary_resource_shortage(); 565 } 566 return rval; 567 } 568 DISPATCH_CLIENT_CRASH("NULL was passed where a block should have been"); 569} 570 571void 572_dispatch_call_block_and_release(void *block) 573{ 574 void (^b)(void) = block; 575 b(); 576 Block_release(b); 577} 578 579#endif // __BLOCKS__ 580 581#pragma mark - 582#pragma mark dispatch_client_callout 583 584// Abort on uncaught exceptions thrown from client callouts rdar://8577499 585#if DISPATCH_USE_CLIENT_CALLOUT && (__arm__ || !USE_OBJC) 586// On platforms with SjLj exceptions, avoid the SjLj overhead on every callout 587// by clearing the unwinder's TSD pointer to the handler stack around callouts 588 589#define _dispatch_get_tsd_base() 590#define _dispatch_get_unwind_tsd() (NULL) 591#define _dispatch_set_unwind_tsd(u) do {(void)(u);} while (0) 592#define _dispatch_free_unwind_tsd() 593 594#undef _dispatch_client_callout 595DISPATCH_NOINLINE 596void 597_dispatch_client_callout(void *ctxt, dispatch_function_t f) 598{ 599 _dispatch_get_tsd_base(); 600 void *u = _dispatch_get_unwind_tsd(); 601 if (fastpath(!u)) return f(ctxt); 602 _dispatch_set_unwind_tsd(NULL); 603 f(ctxt); 604 _dispatch_free_unwind_tsd(); 605 _dispatch_set_unwind_tsd(u); 606} 607 608#undef _dispatch_client_callout2 609DISPATCH_NOINLINE 610void 611_dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t)) 612{ 613 _dispatch_get_tsd_base(); 614 void *u = _dispatch_get_unwind_tsd(); 615 if (fastpath(!u)) return f(ctxt, i); 616 _dispatch_set_unwind_tsd(NULL); 617 f(ctxt, i); 618 _dispatch_free_unwind_tsd(); 619 _dispatch_set_unwind_tsd(u); 620} 621 622#undef _dispatch_client_callout3 623bool 624_dispatch_client_callout3(void *ctxt, dispatch_data_t region, size_t offset, 625 const void *buffer, size_t size, dispatch_data_applier_function_t f) 626{ 627 _dispatch_get_tsd_base(); 628 void *u = _dispatch_get_unwind_tsd(); 629 if (fastpath(!u)) return f(ctxt, region, offset, buffer, size); 630 _dispatch_set_unwind_tsd(NULL); 631 bool res = f(ctxt, region, offset, buffer, size); 632 _dispatch_free_unwind_tsd(); 633 _dispatch_set_unwind_tsd(u); 634 return res; 635} 636 637#undef _dispatch_client_callout4 638void 639_dispatch_client_callout4(void *ctxt, dispatch_mach_reason_t reason, 640 dispatch_mach_msg_t dmsg, mach_error_t error, 641 dispatch_mach_handler_function_t f) 642{ 643 _dispatch_get_tsd_base(); 644 void *u = _dispatch_get_unwind_tsd(); 645 if (fastpath(!u)) return f(ctxt, reason, dmsg, error); 646 _dispatch_set_unwind_tsd(NULL); 647 f(ctxt, reason, dmsg, error); 648 _dispatch_free_unwind_tsd(); 649 _dispatch_set_unwind_tsd(u); 650} 651 652#endif // DISPATCH_USE_CLIENT_CALLOUT 653 654#pragma mark - 655#pragma mark _os_object_t no_objc 656 657#if !USE_OBJC 658 659static const _os_object_class_s _os_object_class; 660 661void 662_os_object_init(void) 663{ 664 return; 665} 666 667inline _os_object_t 668_os_object_alloc_realized(const void *cls, size_t size) 669{ 670 _os_object_t obj; 671 dispatch_assert(size >= sizeof(struct _os_object_s)); 672 while (!fastpath(obj = calloc(1u, size))) { 673 _dispatch_temporary_resource_shortage(); 674 } 675 obj->os_obj_isa = cls; 676 return obj; 677} 678 679_os_object_t 680_os_object_alloc(const void *cls, size_t size) 681{ 682 if (!cls) cls = &_os_object_class; 683 return _os_object_alloc_realized(cls, size); 684} 685 686void 687_os_object_dealloc(_os_object_t obj) 688{ 689 *((void *volatile*)&obj->os_obj_isa) = (void *)0x200; 690 return free(obj); 691} 692 693void 694_os_object_xref_dispose(_os_object_t obj) 695{ 696 if (fastpath(obj->os_obj_isa->_os_obj_xref_dispose)) { 697 return obj->os_obj_isa->_os_obj_xref_dispose(obj); 698 } 699 return _os_object_release_internal(obj); 700} 701 702void 703_os_object_dispose(_os_object_t obj) 704{ 705 if (fastpath(obj->os_obj_isa->_os_obj_dispose)) { 706 return obj->os_obj_isa->_os_obj_dispose(obj); 707 } 708 return _os_object_dealloc(obj); 709} 710 711#pragma mark - 712#pragma mark dispatch_autorelease_pool no_objc 713 714#if DISPATCH_COCOA_COMPAT 715 716void *_dispatch_autorelease_pool_push(void) { 717 void *pool = NULL; 718 if (_dispatch_begin_NSAutoReleasePool) { 719 pool = _dispatch_begin_NSAutoReleasePool(); 720 } 721 return pool; 722} 723 724void _dispatch_autorelease_pool_pop(void *pool) { 725 if (_dispatch_end_NSAutoReleasePool) { 726 _dispatch_end_NSAutoReleasePool(pool); 727 } 728} 729 730#endif // DISPATCH_COCOA_COMPAT 731#endif // !USE_OBJC 732 733#pragma mark - 734#pragma mark dispatch_source_types 735 736static void 737dispatch_source_type_timer_init(dispatch_source_t ds, 738 dispatch_source_type_t type DISPATCH_UNUSED, 739 uintptr_t handle DISPATCH_UNUSED, 740 unsigned long mask, 741 dispatch_queue_t q) 742{ 743 if (fastpath(!ds->ds_refs)) { 744 ds->ds_refs = _dispatch_calloc(1ul, 745 sizeof(struct dispatch_timer_source_refs_s)); 746 } 747 ds->ds_needs_rearm = true; 748 ds->ds_is_timer = true; 749 if (q == dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) 750 || q == dispatch_get_global_queue( 751 DISPATCH_QUEUE_PRIORITY_BACKGROUND, DISPATCH_QUEUE_OVERCOMMIT)){ 752 mask |= DISPATCH_TIMER_BACKGROUND; // <rdar://problem/12200216> 753 } 754 ds_timer(ds->ds_refs).flags = mask; 755} 756 757const struct dispatch_source_type_s _dispatch_source_type_timer = { 758 .ke = { 759 .filter = DISPATCH_EVFILT_TIMER, 760 }, 761 .mask = DISPATCH_TIMER_STRICT|DISPATCH_TIMER_BACKGROUND| 762 DISPATCH_TIMER_WALL_CLOCK, 763 .init = dispatch_source_type_timer_init, 764}; 765 766static void 767dispatch_source_type_timer_with_aggregate_init(dispatch_source_t ds, 768 dispatch_source_type_t type, uintptr_t handle, unsigned long mask, 769 dispatch_queue_t q) 770{ 771 ds->ds_refs = _dispatch_calloc(1ul, 772 sizeof(struct dispatch_timer_source_aggregate_refs_s)); 773 dispatch_source_type_timer_init(ds, type, handle, mask, q); 774 ds_timer(ds->ds_refs).flags |= DISPATCH_TIMER_WITH_AGGREGATE; 775 ds->dq_specific_q = (void*)handle; 776 _dispatch_retain(ds->dq_specific_q); 777} 778 779const struct dispatch_source_type_s _dispatch_source_type_timer_with_aggregate={ 780 .ke = { 781 .filter = DISPATCH_EVFILT_TIMER, 782 .ident = ~0ull, 783 }, 784 .mask = DISPATCH_TIMER_STRICT|DISPATCH_TIMER_BACKGROUND, 785 .init = dispatch_source_type_timer_with_aggregate_init, 786}; 787 788static void 789dispatch_source_type_interval_init(dispatch_source_t ds, 790 dispatch_source_type_t type, uintptr_t handle, unsigned long mask, 791 dispatch_queue_t q) 792{ 793 dispatch_source_type_timer_init(ds, type, handle, mask, q); 794 ds_timer(ds->ds_refs).flags |= DISPATCH_TIMER_INTERVAL; 795 unsigned long ident = _dispatch_source_timer_idx(ds->ds_refs); 796 ds->ds_dkev->dk_kevent.ident = ds->ds_ident_hack = ident; 797 _dispatch_source_set_interval(ds, handle); 798} 799 800const struct dispatch_source_type_s _dispatch_source_type_interval = { 801 .ke = { 802 .filter = DISPATCH_EVFILT_TIMER, 803 .ident = ~0ull, 804 }, 805 .mask = DISPATCH_TIMER_STRICT|DISPATCH_TIMER_BACKGROUND| 806 DISPATCH_INTERVAL_UI_ANIMATION, 807 .init = dispatch_source_type_interval_init, 808}; 809 810const struct dispatch_source_type_s _dispatch_source_type_read = { 811 .ke = { 812 .filter = EVFILT_READ, 813 .flags = EV_DISPATCH, 814 }, 815}; 816 817const struct dispatch_source_type_s _dispatch_source_type_write = { 818 .ke = { 819 .filter = EVFILT_WRITE, 820 .flags = EV_DISPATCH, 821 }, 822}; 823 824#if DISPATCH_USE_VM_PRESSURE 825#if TARGET_IPHONE_SIMULATOR // rdar://problem/9219483 826static int _dispatch_ios_simulator_memory_warnings_fd = -1; 827static void 828_dispatch_ios_simulator_vm_source_init(void *context DISPATCH_UNUSED) 829{ 830 char *e = getenv("IPHONE_SIMULATOR_MEMORY_WARNINGS"); 831 if (!e) return; 832 _dispatch_ios_simulator_memory_warnings_fd = open(e, O_EVTONLY); 833 if (_dispatch_ios_simulator_memory_warnings_fd == -1) { 834 (void)dispatch_assume_zero(errno); 835 } 836} 837static void 838dispatch_source_type_vm_init(dispatch_source_t ds, 839 dispatch_source_type_t type DISPATCH_UNUSED, 840 uintptr_t handle DISPATCH_UNUSED, 841 unsigned long mask, 842 dispatch_queue_t q DISPATCH_UNUSED) 843{ 844 static dispatch_once_t pred; 845 dispatch_once_f(&pred, NULL, _dispatch_ios_simulator_vm_source_init); 846 ds->ds_dkev->dk_kevent.ident = (uint64_t)(mask & DISPATCH_VM_PRESSURE ? 847 _dispatch_ios_simulator_memory_warnings_fd : -1); 848} 849 850const struct dispatch_source_type_s _dispatch_source_type_vm = { 851 .ke = { 852 .filter = EVFILT_VNODE, 853 .flags = EV_CLEAR, 854 }, 855 .mask = NOTE_ATTRIB, 856 .init = dispatch_source_type_vm_init, 857}; 858#else 859static void 860dispatch_source_type_vm_init(dispatch_source_t ds, 861 dispatch_source_type_t type DISPATCH_UNUSED, 862 uintptr_t handle DISPATCH_UNUSED, 863 unsigned long mask DISPATCH_UNUSED, 864 dispatch_queue_t q DISPATCH_UNUSED) 865{ 866 ds->ds_is_level = false; 867} 868 869const struct dispatch_source_type_s _dispatch_source_type_vm = { 870 .ke = { 871 .filter = EVFILT_VM, 872 .flags = EV_DISPATCH, 873 }, 874 .mask = NOTE_VM_PRESSURE, 875 .init = dispatch_source_type_vm_init, 876}; 877#endif 878#endif 879 880#ifdef DISPATCH_USE_MEMORYSTATUS 881static void 882dispatch_source_type_memorystatus_init(dispatch_source_t ds, 883 dispatch_source_type_t type DISPATCH_UNUSED, 884 uintptr_t handle DISPATCH_UNUSED, 885 unsigned long mask DISPATCH_UNUSED, 886 dispatch_queue_t q DISPATCH_UNUSED) 887{ 888 ds->ds_is_level = false; 889} 890 891const struct dispatch_source_type_s _dispatch_source_type_memorystatus = { 892 .ke = { 893 .filter = EVFILT_MEMORYSTATUS, 894 .flags = EV_DISPATCH, 895 }, 896 .mask = NOTE_MEMORYSTATUS_PRESSURE_NORMAL|NOTE_MEMORYSTATUS_PRESSURE_WARN 897#ifdef NOTE_MEMORYSTATUS_PRESSURE_CRITICAL 898 |NOTE_MEMORYSTATUS_PRESSURE_CRITICAL 899#endif 900 , 901 .init = dispatch_source_type_memorystatus_init, 902}; 903#endif 904 905const struct dispatch_source_type_s _dispatch_source_type_proc = { 906 .ke = { 907 .filter = EVFILT_PROC, 908 .flags = EV_CLEAR, 909 }, 910 .mask = NOTE_EXIT|NOTE_FORK|NOTE_EXEC 911#if HAVE_DECL_NOTE_SIGNAL 912 |NOTE_SIGNAL 913#endif 914#if HAVE_DECL_NOTE_REAP 915 |NOTE_REAP 916#endif 917 , 918}; 919 920const struct dispatch_source_type_s _dispatch_source_type_signal = { 921 .ke = { 922 .filter = EVFILT_SIGNAL, 923 }, 924}; 925 926const struct dispatch_source_type_s _dispatch_source_type_vnode = { 927 .ke = { 928 .filter = EVFILT_VNODE, 929 .flags = EV_CLEAR, 930 }, 931 .mask = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK| 932 NOTE_RENAME|NOTE_REVOKE 933#if HAVE_DECL_NOTE_NONE 934 |NOTE_NONE 935#endif 936 , 937}; 938 939const struct dispatch_source_type_s _dispatch_source_type_vfs = { 940 .ke = { 941 .filter = EVFILT_FS, 942 .flags = EV_CLEAR, 943 }, 944 .mask = VQ_NOTRESP|VQ_NEEDAUTH|VQ_LOWDISK|VQ_MOUNT|VQ_UNMOUNT|VQ_DEAD| 945 VQ_ASSIST|VQ_NOTRESPLOCK 946#if HAVE_DECL_VQ_UPDATE 947 |VQ_UPDATE 948#endif 949#if HAVE_DECL_VQ_VERYLOWDISK 950 |VQ_VERYLOWDISK 951#endif 952 , 953}; 954 955const struct dispatch_source_type_s _dispatch_source_type_sock = { 956#ifdef EVFILT_SOCK 957 .ke = { 958 .filter = EVFILT_SOCK, 959 .flags = EV_CLEAR, 960 }, 961 .mask = NOTE_CONNRESET | NOTE_READCLOSED | NOTE_WRITECLOSED | 962 NOTE_TIMEOUT | NOTE_NOSRCADDR | NOTE_IFDENIED | NOTE_SUSPEND | 963 NOTE_RESUME | NOTE_KEEPALIVE 964#ifdef NOTE_ADAPTIVE_WTIMO 965 | NOTE_ADAPTIVE_WTIMO | NOTE_ADAPTIVE_RTIMO 966#endif 967#ifdef NOTE_CONNECTED 968 | NOTE_CONNECTED | NOTE_DISCONNECTED | NOTE_CONNINFO_UPDATED 969#endif 970 , 971#endif // EVFILT_SOCK 972}; 973 974const struct dispatch_source_type_s _dispatch_source_type_data_add = { 975 .ke = { 976 .filter = DISPATCH_EVFILT_CUSTOM_ADD, 977 }, 978}; 979 980const struct dispatch_source_type_s _dispatch_source_type_data_or = { 981 .ke = { 982 .filter = DISPATCH_EVFILT_CUSTOM_OR, 983 .flags = EV_CLEAR, 984 .fflags = ~0u, 985 }, 986}; 987 988#if HAVE_MACH 989 990static void 991dispatch_source_type_mach_send_init(dispatch_source_t ds, 992 dispatch_source_type_t type DISPATCH_UNUSED, 993 uintptr_t handle DISPATCH_UNUSED, unsigned long mask, 994 dispatch_queue_t q DISPATCH_UNUSED) 995{ 996 if (!mask) { 997 // Preserve legacy behavior that (mask == 0) => DISPATCH_MACH_SEND_DEAD 998 ds->ds_dkev->dk_kevent.fflags = DISPATCH_MACH_SEND_DEAD; 999 ds->ds_pending_data_mask = DISPATCH_MACH_SEND_DEAD; 1000 } 1001} 1002 1003const struct dispatch_source_type_s _dispatch_source_type_mach_send = { 1004 .ke = { 1005 .filter = DISPATCH_EVFILT_MACH_NOTIFICATION, 1006 .flags = EV_CLEAR, 1007 }, 1008 .mask = DISPATCH_MACH_SEND_DEAD|DISPATCH_MACH_SEND_POSSIBLE, 1009 .init = dispatch_source_type_mach_send_init, 1010}; 1011 1012static void 1013dispatch_source_type_mach_recv_init(dispatch_source_t ds, 1014 dispatch_source_type_t type DISPATCH_UNUSED, 1015 uintptr_t handle DISPATCH_UNUSED, 1016 unsigned long mask DISPATCH_UNUSED, 1017 dispatch_queue_t q DISPATCH_UNUSED) 1018{ 1019 ds->ds_is_level = false; 1020} 1021 1022const struct dispatch_source_type_s _dispatch_source_type_mach_recv = { 1023 .ke = { 1024 .filter = EVFILT_MACHPORT, 1025 .flags = EV_DISPATCH, 1026 .fflags = DISPATCH_MACH_RECV_MESSAGE, 1027 }, 1028 .init = dispatch_source_type_mach_recv_init, 1029}; 1030 1031#pragma mark - 1032#pragma mark dispatch_mig 1033 1034void * 1035dispatch_mach_msg_get_context(mach_msg_header_t *msg) 1036{ 1037 mach_msg_context_trailer_t *tp; 1038 void *context = NULL; 1039 1040 tp = (mach_msg_context_trailer_t *)((uint8_t *)msg + 1041 round_msg(msg->msgh_size)); 1042 if (tp->msgh_trailer_size >= 1043 (mach_msg_size_t)sizeof(mach_msg_context_trailer_t)) { 1044 context = (void *)(uintptr_t)tp->msgh_context; 1045 } 1046 return context; 1047} 1048 1049kern_return_t 1050_dispatch_wakeup_runloop_thread(mach_port_t mp DISPATCH_UNUSED) 1051{ 1052 // dummy function just to pop a runloop thread out of mach_msg() 1053 return 0; 1054} 1055 1056kern_return_t 1057_dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED) 1058{ 1059 // dummy function to consume a send-once right 1060 return 0; 1061} 1062 1063kern_return_t 1064_dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED, 1065 mach_port_t name) 1066{ 1067 kern_return_t kr; 1068 // this function should never be called 1069 (void)dispatch_assume_zero(name); 1070 kr = mach_port_mod_refs(mach_task_self(), name, MACH_PORT_RIGHT_RECEIVE,-1); 1071 DISPATCH_VERIFY_MIG(kr); 1072 (void)dispatch_assume_zero(kr); 1073 return KERN_SUCCESS; 1074} 1075 1076kern_return_t 1077_dispatch_mach_notify_no_senders(mach_port_t notify, 1078 mach_port_mscount_t mscnt DISPATCH_UNUSED) 1079{ 1080 // this function should never be called 1081 (void)dispatch_assume_zero(notify); 1082 return KERN_SUCCESS; 1083} 1084 1085kern_return_t 1086_dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED) 1087{ 1088 // we only register for dead-name notifications 1089 // some code deallocated our send-once right without consuming it 1090#if DISPATCH_DEBUG 1091 _dispatch_log("Corruption: An app/library deleted a libdispatch " 1092 "dead-name notification"); 1093#endif 1094 return KERN_SUCCESS; 1095} 1096 1097#endif // HAVE_MACH 1098