2 * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
21 // Contains exported global data and initialization & other routines that must
22 // only exist once in the shared library even when resolvers are used.
24 // NOTE: this file must not contain any atomic operations
29 #include "protocolServer.h"
33 #pragma mark dispatch_init
35 #if USE_LIBDISPATCH_INIT_CONSTRUCTOR
36 DISPATCH_NOTHROW
__attribute__((constructor
))
38 _libdispatch_init(void);
40 DISPATCH_EXPORT DISPATCH_NOTHROW
42 _libdispatch_init(void)
48 DISPATCH_EXPORT DISPATCH_NOTHROW
50 dispatch_atfork_prepare(void)
52 _os_object_atfork_prepare();
55 DISPATCH_EXPORT DISPATCH_NOTHROW
57 dispatch_atfork_parent(void)
59 _os_object_atfork_parent();
62 DISPATCH_EXPORT DISPATCH_NOTHROW
64 dispatch_atfork_child(void)
66 _os_object_atfork_child();
67 _voucher_atfork_child();
68 _dispatch_event_loop_atfork_child();
69 if (_dispatch_is_multithreaded_inline()) {
70 _dispatch_child_of_unsafe_fork
= true;
72 _dispatch_queue_atfork_child();
73 // clear the _PROHIBIT and _MULTITHREADED bits if set
74 _dispatch_unsafe_fork
= 0;
78 _dispatch_sigmask(void)
83 /* Workaround: 6269619 Not all signals can be delivered on any thread */
84 r
|= sigfillset(&mask
);
85 r
|= sigdelset(&mask
, SIGILL
);
86 r
|= sigdelset(&mask
, SIGTRAP
);
88 r
|= sigdelset(&mask
, SIGEMT
);
90 r
|= sigdelset(&mask
, SIGFPE
);
91 r
|= sigdelset(&mask
, SIGBUS
);
92 r
|= sigdelset(&mask
, SIGSEGV
);
93 r
|= sigdelset(&mask
, SIGSYS
);
94 r
|= sigdelset(&mask
, SIGPIPE
);
95 r
|= sigdelset(&mask
, SIGPROF
);
96 r
|= pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
97 return dispatch_assume_zero(r
);
101 #pragma mark dispatch_globals
103 DISPATCH_HIDE_SYMBOL(dispatch_assert_queue
, 10.12, 10.0, 10.0, 3.0);
104 DISPATCH_HIDE_SYMBOL(dispatch_assert_queue_not
, 10.12, 10.0, 10.0, 3.0);
105 DISPATCH_HIDE_SYMBOL(dispatch_queue_create_with_target
, 10.12, 10.0, 10.0, 3.0);
107 #if DISPATCH_COCOA_COMPAT
108 void *(*_dispatch_begin_NSAutoReleasePool
)(void);
109 void (*_dispatch_end_NSAutoReleasePool
)(void *);
112 #if DISPATCH_USE_THREAD_LOCAL_STORAGE
113 __thread
struct dispatch_tsd __dispatch_tsd
;
114 pthread_key_t __dispatch_tsd_key
;
115 #elif !DISPATCH_USE_DIRECT_TSD
116 pthread_key_t dispatch_queue_key
;
117 pthread_key_t dispatch_frame_key
;
118 pthread_key_t dispatch_cache_key
;
119 pthread_key_t dispatch_context_key
;
120 pthread_key_t dispatch_pthread_root_queue_observer_hooks_key
;
121 pthread_key_t dispatch_basepri_key
;
122 #if DISPATCH_INTROSPECTION
123 pthread_key_t dispatch_introspection_key
;
124 #elif DISPATCH_PERF_MON
125 pthread_key_t dispatch_bcounter_key
;
127 pthread_key_t dispatch_wlh_key
;
128 pthread_key_t dispatch_voucher_key
;
129 pthread_key_t dispatch_deferred_items_key
;
130 #endif // !DISPATCH_USE_DIRECT_TSD && !DISPATCH_USE_THREAD_LOCAL_STORAGE
132 #if VOUCHER_USE_MACH_VOUCHER
133 dispatch_once_t _voucher_task_mach_voucher_pred
;
134 mach_voucher_t _voucher_task_mach_voucher
;
135 #if !VOUCHER_USE_EMPTY_MACH_BASE_VOUCHER
136 mach_voucher_t _voucher_default_task_mach_voucher
;
138 dispatch_once_t _firehose_task_buffer_pred
;
139 firehose_buffer_t _firehose_task_buffer
;
140 const uint32_t _firehose_spi_version
= OS_FIREHOSE_SPI_VERSION
;
141 uint64_t _voucher_unique_pid
;
142 voucher_activity_hooks_t _voucher_libtrace_hooks
;
143 dispatch_mach_t _voucher_activity_debug_channel
;
145 #if HAVE_PTHREAD_WORKQUEUE_QOS && DISPATCH_DEBUG
146 int _dispatch_set_qos_class_enabled
;
148 #if DISPATCH_USE_KEVENT_WORKQUEUE && DISPATCH_USE_MGR_THREAD
149 int _dispatch_kevent_workqueue_enabled
;
152 DISPATCH_HW_CONFIG();
153 uint8_t _dispatch_unsafe_fork
;
154 bool _dispatch_child_of_unsafe_fork
;
155 #if DISPATCH_USE_MEMORYPRESSURE_SOURCE
156 bool _dispatch_memory_warn
;
157 int _dispatch_continuation_cache_limit
= DISPATCH_CONTINUATION_CACHE_LIMIT
;
162 _dispatch_is_multithreaded(void)
164 return _dispatch_is_multithreaded_inline();
169 _dispatch_is_fork_of_multithreaded_parent(void)
171 return _dispatch_child_of_unsafe_fork
;
174 const struct dispatch_queue_offsets_s dispatch_queue_offsets
= {
176 .dqo_label
= offsetof(struct dispatch_queue_s
, dq_label
),
177 .dqo_label_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_label
),
180 .dqo_serialnum
= offsetof(struct dispatch_queue_s
, dq_serialnum
),
181 .dqo_serialnum_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_serialnum
),
182 .dqo_width
= offsetof(struct dispatch_queue_s
, dq_width
),
183 .dqo_width_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_width
),
185 .dqo_running_size
= 0,
186 .dqo_suspend_cnt
= 0,
187 .dqo_suspend_cnt_size
= 0,
188 .dqo_target_queue
= offsetof(struct dispatch_queue_s
, do_targetq
),
189 .dqo_target_queue_size
= sizeof(((dispatch_queue_t
)NULL
)->do_targetq
),
191 .dqo_priority_size
= 0,
194 #if DISPATCH_USE_DIRECT_TSD
195 const struct dispatch_tsd_indexes_s dispatch_tsd_indexes
= {
197 .dti_queue_index
= dispatch_queue_key
,
198 .dti_voucher_index
= dispatch_voucher_key
,
199 .dti_qos_class_index
= dispatch_priority_key
,
201 #endif // DISPATCH_USE_DIRECT_TSD
203 // 6618342 Contact the team that owns the Instrument DTrace probe before
204 // renaming this symbol
205 DISPATCH_CACHELINE_ALIGN
206 struct dispatch_queue_s _dispatch_main_q
= {
207 DISPATCH_GLOBAL_OBJECT_HEADER(queue_main
),
208 #if !DISPATCH_USE_RESOLVERS
209 .do_targetq
= &_dispatch_root_queues
[
210 DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT
],
212 .dq_state
= DISPATCH_QUEUE_STATE_INIT_VALUE(1) |
213 DISPATCH_QUEUE_ROLE_BASE_ANON
,
214 .dq_label
= "com.apple.main-thread",
215 .dq_atomic_flags
= DQF_THREAD_BOUND
| DQF_CANNOT_TRYSYNC
| DQF_WIDTH(1),
220 #pragma mark dispatch_queue_attr_t
222 #define DISPATCH_QUEUE_ATTR_INIT(qos, prio, overcommit, freq, concurrent, \
225 DISPATCH_GLOBAL_OBJECT_HEADER(queue_attr), \
226 .dqa_qos_and_relpri = (_dispatch_priority_make(qos, prio) & \
227 DISPATCH_PRIORITY_REQUESTED_MASK), \
228 .dqa_overcommit = _dispatch_queue_attr_overcommit_##overcommit, \
229 .dqa_autorelease_frequency = DISPATCH_AUTORELEASE_FREQUENCY_##freq, \
230 .dqa_concurrent = (concurrent), \
231 .dqa_inactive = (inactive), \
234 #define DISPATCH_QUEUE_ATTR_ACTIVE_INIT(qos, prio, overcommit, freq, \
237 [DQA_INDEX_ACTIVE] = DISPATCH_QUEUE_ATTR_INIT( \
238 qos, prio, overcommit, freq, concurrent, false), \
239 [DQA_INDEX_INACTIVE] = DISPATCH_QUEUE_ATTR_INIT( \
240 qos, prio, overcommit, freq, concurrent, true), \
243 #define DISPATCH_QUEUE_ATTR_OVERCOMMIT_INIT(qos, prio, overcommit) \
245 [DQA_INDEX_AUTORELEASE_FREQUENCY_INHERIT][DQA_INDEX_CONCURRENT] = \
246 DISPATCH_QUEUE_ATTR_ACTIVE_INIT( \
247 qos, prio, overcommit, INHERIT, 1), \
248 [DQA_INDEX_AUTORELEASE_FREQUENCY_INHERIT][DQA_INDEX_SERIAL] = \
249 DISPATCH_QUEUE_ATTR_ACTIVE_INIT( \
250 qos, prio, overcommit, INHERIT, 0), \
251 [DQA_INDEX_AUTORELEASE_FREQUENCY_WORK_ITEM][DQA_INDEX_CONCURRENT] = \
252 DISPATCH_QUEUE_ATTR_ACTIVE_INIT( \
253 qos, prio, overcommit, WORK_ITEM, 1), \
254 [DQA_INDEX_AUTORELEASE_FREQUENCY_WORK_ITEM][DQA_INDEX_SERIAL] = \
255 DISPATCH_QUEUE_ATTR_ACTIVE_INIT( \
256 qos, prio, overcommit, WORK_ITEM, 0), \
257 [DQA_INDEX_AUTORELEASE_FREQUENCY_NEVER][DQA_INDEX_CONCURRENT] = \
258 DISPATCH_QUEUE_ATTR_ACTIVE_INIT( \
259 qos, prio, overcommit, NEVER, 1), \
260 [DQA_INDEX_AUTORELEASE_FREQUENCY_NEVER][DQA_INDEX_SERIAL] = \
261 DISPATCH_QUEUE_ATTR_ACTIVE_INIT(\
262 qos, prio, overcommit, NEVER, 0), \
265 #define DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, prio) \
267 [DQA_INDEX_UNSPECIFIED_OVERCOMMIT] = \
268 DISPATCH_QUEUE_ATTR_OVERCOMMIT_INIT(qos, -(prio), unspecified),\
269 [DQA_INDEX_NON_OVERCOMMIT] = \
270 DISPATCH_QUEUE_ATTR_OVERCOMMIT_INIT(qos, -(prio), disabled), \
271 [DQA_INDEX_OVERCOMMIT] = \
272 DISPATCH_QUEUE_ATTR_OVERCOMMIT_INIT(qos, -(prio), enabled), \
275 #define DISPATCH_QUEUE_ATTR_PRIO_INIT(qos) \
277 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 0), \
278 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 1), \
279 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 2), \
280 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 3), \
281 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 4), \
282 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 5), \
283 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 6), \
284 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 7), \
285 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 8), \
286 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 9), \
287 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 10), \
288 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 11), \
289 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 12), \
290 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 13), \
291 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 14), \
292 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 15), \
295 #define DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(qos) \
296 [DQA_INDEX_QOS_CLASS_##qos] = \
297 DISPATCH_QUEUE_ATTR_PRIO_INIT(DISPATCH_QOS_##qos)
299 // DISPATCH_QUEUE_CONCURRENT resp. _dispatch_queue_attr_concurrent is aliased
300 // to array member [0][0][0][0][0][0] and their properties must match!
301 const struct dispatch_queue_attr_s _dispatch_queue_attrs
[]
302 [DISPATCH_QUEUE_ATTR_PRIO_COUNT
]
303 [DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT
]
304 [DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT
]
305 [DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT
]
306 [DISPATCH_QUEUE_ATTR_INACTIVE_COUNT
] = {
307 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(UNSPECIFIED
),
308 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(MAINTENANCE
),
309 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(BACKGROUND
),
310 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(UTILITY
),
311 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(DEFAULT
),
312 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(USER_INITIATED
),
313 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(USER_INTERACTIVE
),
316 #if DISPATCH_VARIANT_STATIC
317 // <rdar://problem/16778703>
318 struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent
=
319 DISPATCH_QUEUE_ATTR_INIT(QOS_CLASS_UNSPECIFIED
, 0,
320 unspecified
, INHERIT
, 1, false);
321 #endif // DISPATCH_VARIANT_STATIC
323 // _dispatch_queue_attr_concurrent is aliased using libdispatch.aliases
324 // and the -alias_list linker option on Darwin but needs to be done manually
325 // for other platforms.
327 extern struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent
328 __attribute__((__alias__("_dispatch_queue_attrs")));
332 #pragma mark dispatch_vtables
334 DISPATCH_VTABLE_INSTANCE(semaphore
,
335 .do_type
= DISPATCH_SEMAPHORE_TYPE
,
336 .do_kind
= "semaphore",
337 .do_dispose
= _dispatch_semaphore_dispose
,
338 .do_debug
= _dispatch_semaphore_debug
,
341 DISPATCH_VTABLE_INSTANCE(group
,
342 .do_type
= DISPATCH_GROUP_TYPE
,
344 .do_dispose
= _dispatch_group_dispose
,
345 .do_debug
= _dispatch_group_debug
,
348 DISPATCH_VTABLE_INSTANCE(queue
,
349 .do_type
= DISPATCH_QUEUE_LEGACY_TYPE
,
351 .do_dispose
= _dispatch_queue_dispose
,
352 .do_suspend
= _dispatch_queue_suspend
,
353 .do_resume
= _dispatch_queue_resume
,
354 .do_push
= _dispatch_queue_push
,
355 .do_invoke
= _dispatch_queue_invoke
,
356 .do_wakeup
= _dispatch_queue_wakeup
,
357 .do_debug
= dispatch_queue_debug
,
358 .do_set_targetq
= _dispatch_queue_set_target_queue
,
361 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_serial
, queue
,
362 .do_type
= DISPATCH_QUEUE_SERIAL_TYPE
,
363 .do_kind
= "serial-queue",
364 .do_dispose
= _dispatch_queue_dispose
,
365 .do_suspend
= _dispatch_queue_suspend
,
366 .do_resume
= _dispatch_queue_resume
,
367 .do_finalize_activation
= _dispatch_queue_finalize_activation
,
368 .do_push
= _dispatch_queue_push
,
369 .do_invoke
= _dispatch_queue_invoke
,
370 .do_wakeup
= _dispatch_queue_wakeup
,
371 .do_debug
= dispatch_queue_debug
,
372 .do_set_targetq
= _dispatch_queue_set_target_queue
,
375 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_concurrent
, queue
,
376 .do_type
= DISPATCH_QUEUE_CONCURRENT_TYPE
,
377 .do_kind
= "concurrent-queue",
378 .do_dispose
= _dispatch_queue_dispose
,
379 .do_suspend
= _dispatch_queue_suspend
,
380 .do_resume
= _dispatch_queue_resume
,
381 .do_finalize_activation
= _dispatch_queue_finalize_activation
,
382 .do_push
= _dispatch_queue_push
,
383 .do_invoke
= _dispatch_queue_invoke
,
384 .do_wakeup
= _dispatch_queue_wakeup
,
385 .do_debug
= dispatch_queue_debug
,
386 .do_set_targetq
= _dispatch_queue_set_target_queue
,
390 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_root
, queue
,
391 .do_type
= DISPATCH_QUEUE_GLOBAL_ROOT_TYPE
,
392 .do_kind
= "global-queue",
393 .do_dispose
= _dispatch_pthread_root_queue_dispose
,
394 .do_push
= _dispatch_root_queue_push
,
396 .do_wakeup
= _dispatch_root_queue_wakeup
,
397 .do_debug
= dispatch_queue_debug
,
401 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_main
, queue
,
402 .do_type
= DISPATCH_QUEUE_SERIAL_TYPE
,
403 .do_kind
= "main-queue",
404 .do_dispose
= _dispatch_queue_dispose
,
405 .do_push
= _dispatch_queue_push
,
406 .do_invoke
= _dispatch_queue_invoke
,
407 .do_wakeup
= _dispatch_main_queue_wakeup
,
408 .do_debug
= dispatch_queue_debug
,
411 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_runloop
, queue
,
412 .do_type
= DISPATCH_QUEUE_RUNLOOP_TYPE
,
413 .do_kind
= "runloop-queue",
414 .do_dispose
= _dispatch_runloop_queue_dispose
,
415 .do_push
= _dispatch_queue_push
,
416 .do_invoke
= _dispatch_queue_invoke
,
417 .do_wakeup
= _dispatch_runloop_queue_wakeup
,
418 .do_debug
= dispatch_queue_debug
,
421 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_mgr
, queue
,
422 .do_type
= DISPATCH_QUEUE_MGR_TYPE
,
423 .do_kind
= "mgr-queue",
424 .do_push
= _dispatch_mgr_queue_push
,
425 .do_invoke
= _dispatch_mgr_thread
,
426 .do_wakeup
= _dispatch_mgr_queue_wakeup
,
427 .do_debug
= dispatch_queue_debug
,
430 DISPATCH_VTABLE_INSTANCE(queue_specific_queue
,
431 .do_type
= DISPATCH_QUEUE_SPECIFIC_TYPE
,
432 .do_kind
= "queue-context",
433 .do_dispose
= _dispatch_queue_specific_queue_dispose
,
434 .do_push
= (void *)_dispatch_queue_push
,
435 .do_invoke
= (void *)_dispatch_queue_invoke
,
436 .do_wakeup
= (void *)_dispatch_queue_wakeup
,
437 .do_debug
= (void *)dispatch_queue_debug
,
440 DISPATCH_VTABLE_INSTANCE(queue_attr
,
441 .do_type
= DISPATCH_QUEUE_ATTR_TYPE
,
442 .do_kind
= "queue-attr",
445 DISPATCH_VTABLE_INSTANCE(source
,
446 .do_type
= DISPATCH_SOURCE_KEVENT_TYPE
,
447 .do_kind
= "kevent-source",
448 .do_dispose
= _dispatch_source_dispose
,
449 .do_suspend
= (void *)_dispatch_queue_suspend
,
450 .do_resume
= (void *)_dispatch_queue_resume
,
451 .do_finalize_activation
= _dispatch_source_finalize_activation
,
452 .do_push
= (void *)_dispatch_queue_push
,
453 .do_invoke
= _dispatch_source_invoke
,
454 .do_wakeup
= _dispatch_source_wakeup
,
455 .do_debug
= _dispatch_source_debug
,
456 .do_set_targetq
= (void *)_dispatch_queue_set_target_queue
,
460 DISPATCH_VTABLE_INSTANCE(mach
,
461 .do_type
= DISPATCH_MACH_CHANNEL_TYPE
,
462 .do_kind
= "mach-channel",
463 .do_dispose
= _dispatch_mach_dispose
,
464 .do_suspend
= (void *)_dispatch_queue_suspend
,
465 .do_resume
= (void *)_dispatch_queue_resume
,
466 .do_finalize_activation
= _dispatch_mach_finalize_activation
,
467 .do_push
= (void *)_dispatch_queue_push
,
468 .do_invoke
= _dispatch_mach_invoke
,
469 .do_wakeup
= _dispatch_mach_wakeup
,
470 .do_debug
= _dispatch_mach_debug
,
471 .do_set_targetq
= (void *)_dispatch_queue_set_target_queue
,
474 DISPATCH_VTABLE_INSTANCE(mach_msg
,
475 .do_type
= DISPATCH_MACH_MSG_TYPE
,
476 .do_kind
= "mach-msg",
477 .do_dispose
= _dispatch_mach_msg_dispose
,
478 .do_invoke
= _dispatch_mach_msg_invoke
,
479 .do_debug
= _dispatch_mach_msg_debug
,
483 #if !DISPATCH_DATA_IS_BRIDGED_TO_NSDATA
484 DISPATCH_VTABLE_INSTANCE(data
,
485 .do_type
= DISPATCH_DATA_TYPE
,
487 .do_dispose
= _dispatch_data_dispose
,
488 .do_debug
= _dispatch_data_debug
,
489 .do_set_targetq
= (void*)_dispatch_data_set_target_queue
,
493 DISPATCH_VTABLE_INSTANCE(io
,
494 .do_type
= DISPATCH_IO_TYPE
,
495 .do_kind
= "channel",
496 .do_dispose
= _dispatch_io_dispose
,
497 .do_debug
= _dispatch_io_debug
,
498 .do_set_targetq
= _dispatch_io_set_target_queue
,
501 DISPATCH_VTABLE_INSTANCE(operation
,
502 .do_type
= DISPATCH_OPERATION_TYPE
,
503 .do_kind
= "operation",
504 .do_dispose
= _dispatch_operation_dispose
,
505 .do_debug
= _dispatch_operation_debug
,
508 DISPATCH_VTABLE_INSTANCE(disk
,
509 .do_type
= DISPATCH_DISK_TYPE
,
511 .do_dispose
= _dispatch_disk_dispose
,
516 _dispatch_vtable_init(void)
518 #if OS_OBJECT_HAVE_OBJC2
519 // ObjC classes and dispatch vtables are co-located via linker order and
520 // alias files, verify correct layout during initialization rdar://10640168
521 dispatch_assert((char*)&DISPATCH_CONCAT(_
,DISPATCH_CLASS(semaphore_vtable
))
522 - (char*)DISPATCH_VTABLE(semaphore
) ==
523 offsetof(struct dispatch_semaphore_vtable_s
, _os_obj_vtable
));
528 #pragma mark dispatch_data globals
530 const dispatch_block_t _dispatch_data_destructor_free
= ^{
531 DISPATCH_INTERNAL_CRASH(0, "free destructor called");
534 const dispatch_block_t _dispatch_data_destructor_none
= ^{
535 DISPATCH_INTERNAL_CRASH(0, "none destructor called");
539 const dispatch_block_t _dispatch_data_destructor_munmap
= ^{
540 DISPATCH_INTERNAL_CRASH(0, "munmap destructor called");
543 // _dispatch_data_destructor_munmap is a linker alias to the following
544 const dispatch_block_t _dispatch_data_destructor_vm_deallocate
= ^{
545 DISPATCH_INTERNAL_CRASH(0, "vmdeallocate destructor called");
549 const dispatch_block_t _dispatch_data_destructor_inline
= ^{
550 DISPATCH_INTERNAL_CRASH(0, "inline destructor called");
553 struct dispatch_data_s _dispatch_data_empty
= {
554 #if DISPATCH_DATA_IS_BRIDGED_TO_NSDATA
555 .do_vtable
= DISPATCH_DATA_EMPTY_CLASS
,
557 DISPATCH_GLOBAL_OBJECT_HEADER(data
),
558 .do_next
= DISPATCH_OBJECT_LISTLESS
,
563 #pragma mark dispatch_bug
565 static char _dispatch_build
[16];
568 _dispatch_build_init(void *context DISPATCH_UNUSED
)
571 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
572 size_t bufsz
= sizeof(_dispatch_build
);
574 sysctl(mib
, 2, _dispatch_build
, &bufsz
, NULL
, 0);
575 #if TARGET_IPHONE_SIMULATOR
576 char *sim_version
= getenv("SIMULATOR_RUNTIME_BUILD_VERSION");
578 (void)strlcat(_dispatch_build
, " ", sizeof(_dispatch_build
));
579 (void)strlcat(_dispatch_build
, sim_version
, sizeof(_dispatch_build
));
581 #endif // TARGET_IPHONE_SIMULATOR
585 * XXXRW: What to do here for !Mac OS X?
587 memset(_dispatch_build
, 0, sizeof(_dispatch_build
));
591 static dispatch_once_t _dispatch_build_pred
;
594 _dispatch_get_build(void)
596 dispatch_once_f(&_dispatch_build_pred
, NULL
, _dispatch_build_init
);
597 return _dispatch_build
;
600 #define _dispatch_bug_log(msg, ...) do { \
601 static void *last_seen; \
602 void *ra = __builtin_return_address(0); \
603 if (last_seen != ra) { \
605 _dispatch_log(msg, ##__VA_ARGS__); \
610 _dispatch_bug(size_t line
, long val
)
612 dispatch_once_f(&_dispatch_build_pred
, NULL
, _dispatch_build_init
);
613 _dispatch_bug_log("BUG in libdispatch: %s - %lu - 0x%lx",
614 _dispatch_build
, (unsigned long)line
, val
);
618 _dispatch_bug_client(const char* msg
)
620 _dispatch_bug_log("BUG in libdispatch client: %s", msg
);
625 _dispatch_bug_mach_client(const char* msg
, mach_msg_return_t kr
)
627 _dispatch_bug_log("BUG in libdispatch client: %s %s - 0x%x", msg
,
628 mach_error_string(kr
), kr
);
633 _dispatch_bug_kevent_client(const char* msg
, const char* filter
,
634 const char *operation
, int err
)
636 if (operation
&& err
) {
637 _dispatch_bug_log("BUG in libdispatch client: %s[%s] %s: \"%s\" - 0x%x",
638 msg
, filter
, operation
, strerror(err
), err
);
639 } else if (operation
) {
640 _dispatch_bug_log("BUG in libdispatch client: %s[%s] %s",
641 msg
, filter
, operation
);
643 _dispatch_bug_log("BUG in libdispatch: %s[%s]: \"%s\" - 0x%x",
644 msg
, filter
, strerror(err
), err
);
649 _dispatch_bug_deprecated(const char *msg
)
651 _dispatch_bug_log("DEPRECATED USE in libdispatch client: %s", msg
);
655 _dispatch_abort(size_t line
, long val
)
657 _dispatch_bug(line
, val
);
661 #if !DISPATCH_USE_OS_DEBUG_LOG
664 #pragma mark dispatch_log
666 static int dispatch_logfile
= -1;
667 static bool dispatch_log_disabled
;
669 static uint64_t dispatch_log_basetime
;
671 static dispatch_once_t _dispatch_logv_pred
;
674 _dispatch_logv_init(void *context DISPATCH_UNUSED
)
677 bool log_to_file
= true;
679 bool log_to_file
= false;
681 char *e
= getenv("LIBDISPATCH_LOG");
683 if (strcmp(e
, "YES") == 0) {
685 } else if (strcmp(e
, "NO") == 0) {
686 dispatch_log_disabled
= true;
687 } else if (strcmp(e
, "syslog") == 0) {
689 } else if (strcmp(e
, "file") == 0) {
691 } else if (strcmp(e
, "stderr") == 0) {
693 dispatch_logfile
= STDERR_FILENO
;
696 if (!dispatch_log_disabled
) {
697 if (log_to_file
&& dispatch_logfile
== -1) {
699 snprintf(path
, sizeof(path
), "/var/tmp/libdispatch.%d.log",
701 dispatch_logfile
= open(path
, O_WRONLY
| O_APPEND
| O_CREAT
|
702 O_NOFOLLOW
| O_CLOEXEC
, 0666);
704 if (dispatch_logfile
!= -1) {
706 gettimeofday(&tv
, NULL
);
708 dispatch_log_basetime
= _dispatch_absolute_time();
710 dprintf(dispatch_logfile
, "=== log file opened for %s[%u] at "
711 "%ld.%06u ===\n", getprogname() ?: "", getpid(),
712 tv
.tv_sec
, (int)tv
.tv_usec
);
718 _dispatch_log_file(char *buf
, size_t len
)
724 r
= write(dispatch_logfile
, buf
, len
);
725 if (slowpath(r
== -1) && errno
== EINTR
) {
732 _dispatch_logv_file(const char *msg
, va_list ap
)
735 size_t bufsiz
= sizeof(buf
), offset
= 0;
739 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
, "%llu\t",
740 _dispatch_absolute_time() - dispatch_log_basetime
);
742 r
= vsnprintf(&buf
[offset
], bufsiz
- offset
, msg
, ap
);
745 if (offset
> bufsiz
- 1) {
748 _dispatch_log_file(buf
, offset
);
751 #if DISPATCH_USE_SIMPLE_ASL
753 _dispatch_syslog(const char *msg
)
755 _simple_asl_log(ASL_LEVEL_NOTICE
, "com.apple.libsystem.libdispatch", msg
);
759 _dispatch_vsyslog(const char *msg
, va_list ap
)
762 vasprintf(&str
, msg
, ap
);
764 _dispatch_syslog(str
);
768 #else // DISPATCH_USE_SIMPLE_ASL
770 _dispatch_syslog(const char *msg
)
772 syslog(LOG_NOTICE
, "%s", msg
);
776 _dispatch_vsyslog(const char *msg
, va_list ap
)
778 vsyslog(LOG_NOTICE
, msg
, ap
);
780 #endif // DISPATCH_USE_SIMPLE_ASL
782 DISPATCH_ALWAYS_INLINE
784 _dispatch_logv(const char *msg
, size_t len
, va_list *ap_ptr
)
786 dispatch_once_f(&_dispatch_logv_pred
, NULL
, _dispatch_logv_init
);
787 if (slowpath(dispatch_log_disabled
)) {
790 if (slowpath(dispatch_logfile
!= -1)) {
792 return _dispatch_log_file((char*)msg
, len
);
794 return _dispatch_logv_file(msg
, *ap_ptr
);
797 return _dispatch_syslog(msg
);
799 return _dispatch_vsyslog(msg
, *ap_ptr
);
804 _dispatch_log(const char *msg
, ...)
809 _dispatch_logv(msg
, 0, &ap
);
813 #endif // DISPATCH_USE_OS_DEBUG_LOG
816 #pragma mark dispatch_debug
819 _dispatch_object_debug2(dispatch_object_t dou
, char* buf
, size_t bufsiz
)
821 DISPATCH_OBJECT_TFB(_dispatch_objc_debug
, dou
, buf
, bufsiz
);
822 if (dx_vtable(dou
._do
)->do_debug
) {
823 return dx_debug(dou
._do
, buf
, bufsiz
);
825 return strlcpy(buf
, "NULL vtable slot: ", bufsiz
);
830 _dispatch_debugv(dispatch_object_t dou
, const char *msg
, va_list ap
)
833 size_t bufsiz
= sizeof(buf
), offset
= 0;
835 #if DISPATCH_DEBUG && !DISPATCH_USE_OS_DEBUG_LOG
836 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
, "%llu\t\t%p\t",
837 _dispatch_absolute_time() - dispatch_log_basetime
,
838 (void *)_dispatch_thread_self());
841 offset
+= _dispatch_object_debug2(dou
, &buf
[offset
], bufsiz
- offset
);
842 dispatch_assert(offset
+ 2 < bufsiz
);
847 offset
+= strlcpy(&buf
[offset
], "NULL: ", bufsiz
- offset
);
849 r
= vsnprintf(&buf
[offset
], bufsiz
- offset
, msg
, ap
);
850 #if !DISPATCH_USE_OS_DEBUG_LOG
851 size_t len
= offset
+ (r
< 0 ? 0 : (size_t)r
);
852 if (len
> bufsiz
- 1) {
855 _dispatch_logv(buf
, len
, NULL
);
857 _dispatch_log("%s", buf
);
863 dispatch_debugv(dispatch_object_t dou
, const char *msg
, va_list ap
)
865 _dispatch_debugv(dou
, msg
, ap
);
870 dispatch_debug(dispatch_object_t dou
, const char *msg
, ...)
875 _dispatch_debugv(dou
, msg
, ap
);
882 _dispatch_object_debug(dispatch_object_t dou
, const char *msg
, ...)
887 _dispatch_debugv(dou
._do
, msg
, ap
);
893 #pragma mark dispatch_calloc
897 _dispatch_temporary_resource_shortage(void)
900 asm(""); // prevent tailcall
904 _dispatch_calloc(size_t num_items
, size_t size
)
907 while (!fastpath(buf
= calloc(num_items
, size
))) {
908 _dispatch_temporary_resource_shortage();
914 * If the source string is mutable, allocates memory and copies the contents.
915 * Otherwise returns the source string.
918 _dispatch_strdup_if_mutable(const char *str
)
920 #if HAVE_DYLD_IS_MEMORY_IMMUTABLE
921 size_t size
= strlen(str
) + 1;
922 if (slowpath(!_dyld_is_memory_immutable(str
, size
))) {
923 char *clone
= (char *) malloc(size
);
924 if (dispatch_assume(clone
)) {
925 memcpy(clone
, str
, size
);
936 #pragma mark dispatch_block_t
941 (_dispatch_Block_copy
)(void *db
)
943 dispatch_block_t rval
;
946 while (!fastpath(rval
= Block_copy(db
))) {
947 _dispatch_temporary_resource_shortage();
951 DISPATCH_CLIENT_CRASH(0, "NULL was passed where a block should have been");
955 _dispatch_call_block_and_release(void *block
)
957 void (^b
)(void) = block
;
965 #pragma mark dispatch_client_callout
967 // Abort on uncaught exceptions thrown from client callouts rdar://8577499
968 #if DISPATCH_USE_CLIENT_CALLOUT && (__USING_SJLJ_EXCEPTIONS__ || !USE_OBJC || \
969 OS_OBJECT_HAVE_OBJC1)
970 // On platforms with SjLj exceptions, avoid the SjLj overhead on every callout
971 // by clearing the unwinder's TSD pointer to the handler stack around callouts
973 #define _dispatch_get_tsd_base()
974 #define _dispatch_get_unwind_tsd() (NULL)
975 #define _dispatch_set_unwind_tsd(u) do {(void)(u);} while (0)
976 #define _dispatch_free_unwind_tsd()
978 #undef _dispatch_client_callout
981 _dispatch_client_callout(void *ctxt
, dispatch_function_t f
)
983 _dispatch_get_tsd_base();
984 void *u
= _dispatch_get_unwind_tsd();
985 if (fastpath(!u
)) return f(ctxt
);
986 _dispatch_set_unwind_tsd(NULL
);
988 _dispatch_free_unwind_tsd();
989 _dispatch_set_unwind_tsd(u
);
992 #undef _dispatch_client_callout2
995 _dispatch_client_callout2(void *ctxt
, size_t i
, void (*f
)(void *, size_t))
997 _dispatch_get_tsd_base();
998 void *u
= _dispatch_get_unwind_tsd();
999 if (fastpath(!u
)) return f(ctxt
, i
);
1000 _dispatch_set_unwind_tsd(NULL
);
1002 _dispatch_free_unwind_tsd();
1003 _dispatch_set_unwind_tsd(u
);
1008 #undef _dispatch_client_callout3
1011 _dispatch_client_callout3(void *ctxt
, dispatch_mach_reason_t reason
,
1012 dispatch_mach_msg_t dmsg
, dispatch_mach_async_reply_callback_t f
)
1014 _dispatch_get_tsd_base();
1015 void *u
= _dispatch_get_unwind_tsd();
1016 if (fastpath(!u
)) return f(ctxt
, reason
, dmsg
);
1017 _dispatch_set_unwind_tsd(NULL
);
1018 f(ctxt
, reason
, dmsg
);
1019 _dispatch_free_unwind_tsd();
1020 _dispatch_set_unwind_tsd(u
);
1023 #undef _dispatch_client_callout4
1025 _dispatch_client_callout4(void *ctxt
, dispatch_mach_reason_t reason
,
1026 dispatch_mach_msg_t dmsg
, mach_error_t error
,
1027 dispatch_mach_handler_function_t f
)
1029 _dispatch_get_tsd_base();
1030 void *u
= _dispatch_get_unwind_tsd();
1031 if (fastpath(!u
)) return f(ctxt
, reason
, dmsg
, error
);
1032 _dispatch_set_unwind_tsd(NULL
);
1033 f(ctxt
, reason
, dmsg
, error
);
1034 _dispatch_free_unwind_tsd();
1035 _dispatch_set_unwind_tsd(u
);
1039 #endif // DISPATCH_USE_CLIENT_CALLOUT
1042 #pragma mark _os_object_t no_objc
1046 static const _os_object_vtable_s _os_object_vtable
;
1049 _os_object_init(void)
1055 _os_object_alloc_realized(const void *cls
, size_t size
)
1058 dispatch_assert(size
>= sizeof(struct _os_object_s
));
1059 while (!fastpath(obj
= calloc(1u, size
))) {
1060 _dispatch_temporary_resource_shortage();
1062 obj
->os_obj_isa
= cls
;
1067 _os_object_alloc(const void *cls
, size_t size
)
1069 if (!cls
) cls
= &_os_object_vtable
;
1070 return _os_object_alloc_realized(cls
, size
);
1074 _os_object_dealloc(_os_object_t obj
)
1076 *((void *volatile*)&obj
->os_obj_isa
) = (void *)0x200;
1081 _os_object_xref_dispose(_os_object_t obj
)
1083 _os_object_xrefcnt_dispose_barrier(obj
);
1084 if (fastpath(obj
->os_obj_isa
->_os_obj_xref_dispose
)) {
1085 return obj
->os_obj_isa
->_os_obj_xref_dispose(obj
);
1087 return _os_object_release_internal(obj
);
1091 _os_object_dispose(_os_object_t obj
)
1093 _os_object_refcnt_dispose_barrier(obj
);
1094 if (fastpath(obj
->os_obj_isa
->_os_obj_dispose
)) {
1095 return obj
->os_obj_isa
->_os_obj_dispose(obj
);
1097 return _os_object_dealloc(obj
);
1101 os_retain(void *obj
)
1103 if (fastpath(obj
)) {
1104 return _os_object_retain(obj
);
1111 os_release(void *obj
)
1113 if (fastpath(obj
)) {
1114 return _os_object_release(obj
);
1119 _os_object_atfork_prepare(void)
1125 _os_object_atfork_parent(void)
1131 _os_object_atfork_child(void)
1137 #pragma mark dispatch_autorelease_pool no_objc
1139 #if DISPATCH_COCOA_COMPAT
1142 _dispatch_autorelease_pool_push(void)
1145 if (_dispatch_begin_NSAutoReleasePool
) {
1146 pool
= _dispatch_begin_NSAutoReleasePool();
1152 _dispatch_autorelease_pool_pop(void *pool
)
1154 if (_dispatch_end_NSAutoReleasePool
) {
1155 _dispatch_end_NSAutoReleasePool(pool
);
1160 _dispatch_last_resort_autorelease_pool_push(dispatch_invoke_context_t dic
)
1162 dic
->dic_autorelease_pool
= _dispatch_autorelease_pool_push();
1166 _dispatch_last_resort_autorelease_pool_pop(dispatch_invoke_context_t dic
)
1168 _dispatch_autorelease_pool_pop(dic
->dic_autorelease_pool
);
1169 dic
->dic_autorelease_pool
= NULL
;
1172 #endif // DISPATCH_COCOA_COMPAT
1176 #pragma mark dispatch_mig
1180 dispatch_mach_msg_get_context(mach_msg_header_t
*msg
)
1182 mach_msg_context_trailer_t
*tp
;
1183 void *context
= NULL
;
1185 tp
= (mach_msg_context_trailer_t
*)((uint8_t *)msg
+
1186 round_msg(msg
->msgh_size
));
1187 if (tp
->msgh_trailer_size
>=
1188 (mach_msg_size_t
)sizeof(mach_msg_context_trailer_t
)) {
1189 context
= (void *)(uintptr_t)tp
->msgh_context
;
1195 _dispatch_wakeup_runloop_thread(mach_port_t mp DISPATCH_UNUSED
)
1197 // dummy function just to pop a runloop thread out of mach_msg()
1202 _dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED
)
1204 // dummy function to consume a send-once right
1209 _dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED
,
1212 DISPATCH_INTERNAL_CRASH(name
, "unexpected receipt of port-destroyed");
1213 return KERN_FAILURE
;
1217 _dispatch_mach_notify_no_senders(mach_port_t notify DISPATCH_UNUSED
,
1218 mach_port_mscount_t mscnt
)
1220 DISPATCH_INTERNAL_CRASH(mscnt
, "unexpected receipt of no-more-senders");
1221 return KERN_FAILURE
;
1225 _dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED
)
1227 // we only register for dead-name notifications
1228 // some code deallocated our send-once right without consuming it
1230 _dispatch_log("Corruption: An app/library deleted a libdispatch "
1231 "dead-name notification");
1233 return KERN_SUCCESS
;