]> git.saurik.com Git - apple/libdispatch.git/blob - src/init.c
libdispatch-913.1.6.tar.gz
[apple/libdispatch.git] / src / init.c
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 // NOTE: this file must not contain any atomic operations
25
26 #include "internal.h"
27
28 #if HAVE_MACH
29 #include "protocolServer.h"
30 #endif
31
32 #pragma mark -
33 #pragma mark dispatch_init
34
35 #if USE_LIBDISPATCH_INIT_CONSTRUCTOR
36 DISPATCH_NOTHROW __attribute__((constructor))
37 void
38 _libdispatch_init(void);
39
40 DISPATCH_EXPORT DISPATCH_NOTHROW
41 void
42 _libdispatch_init(void)
43 {
44 libdispatch_init();
45 }
46 #endif
47
48 DISPATCH_EXPORT DISPATCH_NOTHROW
49 void
50 dispatch_atfork_prepare(void)
51 {
52 _os_object_atfork_prepare();
53 }
54
55 DISPATCH_EXPORT DISPATCH_NOTHROW
56 void
57 dispatch_atfork_parent(void)
58 {
59 _os_object_atfork_parent();
60 }
61
62 DISPATCH_EXPORT DISPATCH_NOTHROW
63 void
64 dispatch_atfork_child(void)
65 {
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;
71 }
72 _dispatch_queue_atfork_child();
73 // clear the _PROHIBIT and _MULTITHREADED bits if set
74 _dispatch_unsafe_fork = 0;
75 }
76
77 int
78 _dispatch_sigmask(void)
79 {
80 sigset_t mask;
81 int r = 0;
82
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);
87 #if HAVE_DECL_SIGEMT
88 r |= sigdelset(&mask, SIGEMT);
89 #endif
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);
98 }
99
100 #pragma mark -
101 #pragma mark dispatch_globals
102
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);
106
107 #if DISPATCH_COCOA_COMPAT
108 void *(*_dispatch_begin_NSAutoReleasePool)(void);
109 void (*_dispatch_end_NSAutoReleasePool)(void *);
110 #endif
111
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;
126 #endif
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
131
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;
137 #endif
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;
144 #endif
145 #if HAVE_PTHREAD_WORKQUEUE_QOS && DISPATCH_DEBUG
146 int _dispatch_set_qos_class_enabled;
147 #endif
148 #if DISPATCH_USE_KEVENT_WORKQUEUE && DISPATCH_USE_MGR_THREAD
149 int _dispatch_kevent_workqueue_enabled;
150 #endif
151
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;
158 #endif
159
160 DISPATCH_NOINLINE
161 bool
162 _dispatch_is_multithreaded(void)
163 {
164 return _dispatch_is_multithreaded_inline();
165 }
166
167 DISPATCH_NOINLINE
168 bool
169 _dispatch_is_fork_of_multithreaded_parent(void)
170 {
171 return _dispatch_child_of_unsafe_fork;
172 }
173
174 const struct dispatch_queue_offsets_s dispatch_queue_offsets = {
175 .dqo_version = 6,
176 .dqo_label = offsetof(struct dispatch_queue_s, dq_label),
177 .dqo_label_size = sizeof(((dispatch_queue_t)NULL)->dq_label),
178 .dqo_flags = 0,
179 .dqo_flags_size = 0,
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),
184 .dqo_running = 0,
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),
190 .dqo_priority = 0,
191 .dqo_priority_size = 0,
192 };
193
194 #if DISPATCH_USE_DIRECT_TSD
195 const struct dispatch_tsd_indexes_s dispatch_tsd_indexes = {
196 .dti_version = 2,
197 .dti_queue_index = dispatch_queue_key,
198 .dti_voucher_index = dispatch_voucher_key,
199 .dti_qos_class_index = dispatch_priority_key,
200 };
201 #endif // DISPATCH_USE_DIRECT_TSD
202
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],
211 #endif
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),
216 .dq_serialnum = 1,
217 };
218
219 #pragma mark -
220 #pragma mark dispatch_queue_attr_t
221
222 #define DISPATCH_QUEUE_ATTR_INIT(qos, prio, overcommit, freq, concurrent, \
223 inactive) \
224 { \
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), \
232 }
233
234 #define DISPATCH_QUEUE_ATTR_ACTIVE_INIT(qos, prio, overcommit, freq, \
235 concurrent) \
236 { \
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), \
241 }
242
243 #define DISPATCH_QUEUE_ATTR_OVERCOMMIT_INIT(qos, prio, overcommit) \
244 { \
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), \
263 }
264
265 #define DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, prio) \
266 [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), \
273 }
274
275 #define DISPATCH_QUEUE_ATTR_PRIO_INIT(qos) \
276 { \
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), \
293 }
294
295 #define DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(qos) \
296 [DQA_INDEX_QOS_CLASS_##qos] = \
297 DISPATCH_QUEUE_ATTR_PRIO_INIT(DISPATCH_QOS_##qos)
298
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),
314 };
315
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
322
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.
326 #ifndef __APPLE__
327 extern struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent
328 __attribute__((__alias__("_dispatch_queue_attrs")));
329 #endif
330
331 #pragma mark -
332 #pragma mark dispatch_vtables
333
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,
339 );
340
341 DISPATCH_VTABLE_INSTANCE(group,
342 .do_type = DISPATCH_GROUP_TYPE,
343 .do_kind = "group",
344 .do_dispose = _dispatch_group_dispose,
345 .do_debug = _dispatch_group_debug,
346 );
347
348 DISPATCH_VTABLE_INSTANCE(queue,
349 .do_type = DISPATCH_QUEUE_LEGACY_TYPE,
350 .do_kind = "queue",
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,
359 );
360
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,
373 );
374
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,
387 );
388
389
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,
395 .do_invoke = NULL,
396 .do_wakeup = _dispatch_root_queue_wakeup,
397 .do_debug = dispatch_queue_debug,
398 );
399
400
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,
409 );
410
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,
419 );
420
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,
428 );
429
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,
438 );
439
440 DISPATCH_VTABLE_INSTANCE(queue_attr,
441 .do_type = DISPATCH_QUEUE_ATTR_TYPE,
442 .do_kind = "queue-attr",
443 );
444
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,
457 );
458
459 #if HAVE_MACH
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,
472 );
473
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,
480 );
481 #endif // HAVE_MACH
482
483 #if !DISPATCH_DATA_IS_BRIDGED_TO_NSDATA
484 DISPATCH_VTABLE_INSTANCE(data,
485 .do_type = DISPATCH_DATA_TYPE,
486 .do_kind = "data",
487 .do_dispose = _dispatch_data_dispose,
488 .do_debug = _dispatch_data_debug,
489 .do_set_targetq = (void*)_dispatch_data_set_target_queue,
490 );
491 #endif
492
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,
499 );
500
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,
506 );
507
508 DISPATCH_VTABLE_INSTANCE(disk,
509 .do_type = DISPATCH_DISK_TYPE,
510 .do_kind = "disk",
511 .do_dispose = _dispatch_disk_dispose,
512 );
513
514
515 void
516 _dispatch_vtable_init(void)
517 {
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));
524 #endif // USE_OBJC
525 }
526
527 #pragma mark -
528 #pragma mark dispatch_data globals
529
530 const dispatch_block_t _dispatch_data_destructor_free = ^{
531 DISPATCH_INTERNAL_CRASH(0, "free destructor called");
532 };
533
534 const dispatch_block_t _dispatch_data_destructor_none = ^{
535 DISPATCH_INTERNAL_CRASH(0, "none destructor called");
536 };
537
538 #if !HAVE_MACH
539 const dispatch_block_t _dispatch_data_destructor_munmap = ^{
540 DISPATCH_INTERNAL_CRASH(0, "munmap destructor called");
541 };
542 #else
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");
546 };
547 #endif
548
549 const dispatch_block_t _dispatch_data_destructor_inline = ^{
550 DISPATCH_INTERNAL_CRASH(0, "inline destructor called");
551 };
552
553 struct dispatch_data_s _dispatch_data_empty = {
554 #if DISPATCH_DATA_IS_BRIDGED_TO_NSDATA
555 .do_vtable = DISPATCH_DATA_EMPTY_CLASS,
556 #else
557 DISPATCH_GLOBAL_OBJECT_HEADER(data),
558 .do_next = DISPATCH_OBJECT_LISTLESS,
559 #endif
560 };
561
562 #pragma mark -
563 #pragma mark dispatch_bug
564
565 static char _dispatch_build[16];
566
567 static void
568 _dispatch_build_init(void *context DISPATCH_UNUSED)
569 {
570 #ifdef __APPLE__
571 int mib[] = { CTL_KERN, KERN_OSVERSION };
572 size_t bufsz = sizeof(_dispatch_build);
573
574 sysctl(mib, 2, _dispatch_build, &bufsz, NULL, 0);
575 #if TARGET_IPHONE_SIMULATOR
576 char *sim_version = getenv("SIMULATOR_RUNTIME_BUILD_VERSION");
577 if (sim_version) {
578 (void)strlcat(_dispatch_build, " ", sizeof(_dispatch_build));
579 (void)strlcat(_dispatch_build, sim_version, sizeof(_dispatch_build));
580 }
581 #endif // TARGET_IPHONE_SIMULATOR
582
583 #else
584 /*
585 * XXXRW: What to do here for !Mac OS X?
586 */
587 memset(_dispatch_build, 0, sizeof(_dispatch_build));
588 #endif // __APPLE__
589 }
590
591 static dispatch_once_t _dispatch_build_pred;
592
593 char*
594 _dispatch_get_build(void)
595 {
596 dispatch_once_f(&_dispatch_build_pred, NULL, _dispatch_build_init);
597 return _dispatch_build;
598 }
599
600 #define _dispatch_bug_log(msg, ...) do { \
601 static void *last_seen; \
602 void *ra = __builtin_return_address(0); \
603 if (last_seen != ra) { \
604 last_seen = ra; \
605 _dispatch_log(msg, ##__VA_ARGS__); \
606 } \
607 } while(0)
608
609 void
610 _dispatch_bug(size_t line, long val)
611 {
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);
615 }
616
617 void
618 _dispatch_bug_client(const char* msg)
619 {
620 _dispatch_bug_log("BUG in libdispatch client: %s", msg);
621 }
622
623 #if HAVE_MACH
624 void
625 _dispatch_bug_mach_client(const char* msg, mach_msg_return_t kr)
626 {
627 _dispatch_bug_log("BUG in libdispatch client: %s %s - 0x%x", msg,
628 mach_error_string(kr), kr);
629 }
630 #endif
631
632 void
633 _dispatch_bug_kevent_client(const char* msg, const char* filter,
634 const char *operation, int err)
635 {
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);
642 } else {
643 _dispatch_bug_log("BUG in libdispatch: %s[%s]: \"%s\" - 0x%x",
644 msg, filter, strerror(err), err);
645 }
646 }
647
648 void
649 _dispatch_bug_deprecated(const char *msg)
650 {
651 _dispatch_bug_log("DEPRECATED USE in libdispatch client: %s", msg);
652 }
653
654 void
655 _dispatch_abort(size_t line, long val)
656 {
657 _dispatch_bug(line, val);
658 abort();
659 }
660
661 #if !DISPATCH_USE_OS_DEBUG_LOG
662
663 #pragma mark -
664 #pragma mark dispatch_log
665
666 static int dispatch_logfile = -1;
667 static bool dispatch_log_disabled;
668 #if DISPATCH_DEBUG
669 static uint64_t dispatch_log_basetime;
670 #endif
671 static dispatch_once_t _dispatch_logv_pred;
672
673 static void
674 _dispatch_logv_init(void *context DISPATCH_UNUSED)
675 {
676 #if DISPATCH_DEBUG
677 bool log_to_file = true;
678 #else
679 bool log_to_file = false;
680 #endif
681 char *e = getenv("LIBDISPATCH_LOG");
682 if (e) {
683 if (strcmp(e, "YES") == 0) {
684 // default
685 } else if (strcmp(e, "NO") == 0) {
686 dispatch_log_disabled = true;
687 } else if (strcmp(e, "syslog") == 0) {
688 log_to_file = false;
689 } else if (strcmp(e, "file") == 0) {
690 log_to_file = true;
691 } else if (strcmp(e, "stderr") == 0) {
692 log_to_file = true;
693 dispatch_logfile = STDERR_FILENO;
694 }
695 }
696 if (!dispatch_log_disabled) {
697 if (log_to_file && dispatch_logfile == -1) {
698 char path[PATH_MAX];
699 snprintf(path, sizeof(path), "/var/tmp/libdispatch.%d.log",
700 getpid());
701 dispatch_logfile = open(path, O_WRONLY | O_APPEND | O_CREAT |
702 O_NOFOLLOW | O_CLOEXEC, 0666);
703 }
704 if (dispatch_logfile != -1) {
705 struct timeval tv;
706 gettimeofday(&tv, NULL);
707 #if DISPATCH_DEBUG
708 dispatch_log_basetime = _dispatch_absolute_time();
709 #endif
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);
713 }
714 }
715 }
716
717 static inline void
718 _dispatch_log_file(char *buf, size_t len)
719 {
720 ssize_t r;
721
722 buf[len++] = '\n';
723 retry:
724 r = write(dispatch_logfile, buf, len);
725 if (slowpath(r == -1) && errno == EINTR) {
726 goto retry;
727 }
728 }
729
730 DISPATCH_NOINLINE
731 static void
732 _dispatch_logv_file(const char *msg, va_list ap)
733 {
734 char buf[2048];
735 size_t bufsiz = sizeof(buf), offset = 0;
736 int r;
737
738 #if DISPATCH_DEBUG
739 offset += dsnprintf(&buf[offset], bufsiz - offset, "%llu\t",
740 _dispatch_absolute_time() - dispatch_log_basetime);
741 #endif
742 r = vsnprintf(&buf[offset], bufsiz - offset, msg, ap);
743 if (r < 0) return;
744 offset += (size_t)r;
745 if (offset > bufsiz - 1) {
746 offset = bufsiz - 1;
747 }
748 _dispatch_log_file(buf, offset);
749 }
750
751 #if DISPATCH_USE_SIMPLE_ASL
752 static inline void
753 _dispatch_syslog(const char *msg)
754 {
755 _simple_asl_log(ASL_LEVEL_NOTICE, "com.apple.libsystem.libdispatch", msg);
756 }
757
758 static inline void
759 _dispatch_vsyslog(const char *msg, va_list ap)
760 {
761 char *str;
762 vasprintf(&str, msg, ap);
763 if (str) {
764 _dispatch_syslog(str);
765 free(str);
766 }
767 }
768 #else // DISPATCH_USE_SIMPLE_ASL
769 static inline void
770 _dispatch_syslog(const char *msg)
771 {
772 syslog(LOG_NOTICE, "%s", msg);
773 }
774
775 static inline void
776 _dispatch_vsyslog(const char *msg, va_list ap)
777 {
778 vsyslog(LOG_NOTICE, msg, ap);
779 }
780 #endif // DISPATCH_USE_SIMPLE_ASL
781
782 DISPATCH_ALWAYS_INLINE
783 static inline void
784 _dispatch_logv(const char *msg, size_t len, va_list *ap_ptr)
785 {
786 dispatch_once_f(&_dispatch_logv_pred, NULL, _dispatch_logv_init);
787 if (slowpath(dispatch_log_disabled)) {
788 return;
789 }
790 if (slowpath(dispatch_logfile != -1)) {
791 if (!ap_ptr) {
792 return _dispatch_log_file((char*)msg, len);
793 }
794 return _dispatch_logv_file(msg, *ap_ptr);
795 }
796 if (!ap_ptr) {
797 return _dispatch_syslog(msg);
798 }
799 return _dispatch_vsyslog(msg, *ap_ptr);
800 }
801
802 DISPATCH_NOINLINE
803 void
804 _dispatch_log(const char *msg, ...)
805 {
806 va_list ap;
807
808 va_start(ap, msg);
809 _dispatch_logv(msg, 0, &ap);
810 va_end(ap);
811 }
812
813 #endif // DISPATCH_USE_OS_DEBUG_LOG
814
815 #pragma mark -
816 #pragma mark dispatch_debug
817
818 static size_t
819 _dispatch_object_debug2(dispatch_object_t dou, char* buf, size_t bufsiz)
820 {
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);
824 }
825 return strlcpy(buf, "NULL vtable slot: ", bufsiz);
826 }
827
828 DISPATCH_NOINLINE
829 static void
830 _dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
831 {
832 char buf[2048];
833 size_t bufsiz = sizeof(buf), offset = 0;
834 int r;
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());
839 #endif
840 if (dou._do) {
841 offset += _dispatch_object_debug2(dou, &buf[offset], bufsiz - offset);
842 dispatch_assert(offset + 2 < bufsiz);
843 buf[offset++] = ':';
844 buf[offset++] = ' ';
845 buf[offset] = '\0';
846 } else {
847 offset += strlcpy(&buf[offset], "NULL: ", bufsiz - offset);
848 }
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) {
853 len = bufsiz - 1;
854 }
855 _dispatch_logv(buf, len, NULL);
856 #else
857 _dispatch_log("%s", buf);
858 #endif
859 }
860
861 DISPATCH_NOINLINE
862 void
863 dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
864 {
865 _dispatch_debugv(dou, msg, ap);
866 }
867
868 DISPATCH_NOINLINE
869 void
870 dispatch_debug(dispatch_object_t dou, const char *msg, ...)
871 {
872 va_list ap;
873
874 va_start(ap, msg);
875 _dispatch_debugv(dou, msg, ap);
876 va_end(ap);
877 }
878
879 #if DISPATCH_DEBUG
880 DISPATCH_NOINLINE
881 void
882 _dispatch_object_debug(dispatch_object_t dou, const char *msg, ...)
883 {
884 va_list ap;
885
886 va_start(ap, msg);
887 _dispatch_debugv(dou._do, msg, ap);
888 va_end(ap);
889 }
890 #endif
891
892 #pragma mark -
893 #pragma mark dispatch_calloc
894
895 DISPATCH_NOINLINE
896 void
897 _dispatch_temporary_resource_shortage(void)
898 {
899 sleep(1);
900 asm(""); // prevent tailcall
901 }
902
903 void *
904 _dispatch_calloc(size_t num_items, size_t size)
905 {
906 void *buf;
907 while (!fastpath(buf = calloc(num_items, size))) {
908 _dispatch_temporary_resource_shortage();
909 }
910 return buf;
911 }
912
913 /**
914 * If the source string is mutable, allocates memory and copies the contents.
915 * Otherwise returns the source string.
916 */
917 const char *
918 _dispatch_strdup_if_mutable(const char *str)
919 {
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);
926 }
927 return clone;
928 }
929 return str;
930 #else
931 return strdup(str);
932 #endif
933 }
934
935 #pragma mark -
936 #pragma mark dispatch_block_t
937
938 #ifdef __BLOCKS__
939
940 void *
941 (_dispatch_Block_copy)(void *db)
942 {
943 dispatch_block_t rval;
944
945 if (fastpath(db)) {
946 while (!fastpath(rval = Block_copy(db))) {
947 _dispatch_temporary_resource_shortage();
948 }
949 return rval;
950 }
951 DISPATCH_CLIENT_CRASH(0, "NULL was passed where a block should have been");
952 }
953
954 void
955 _dispatch_call_block_and_release(void *block)
956 {
957 void (^b)(void) = block;
958 b();
959 Block_release(b);
960 }
961
962 #endif // __BLOCKS__
963
964 #pragma mark -
965 #pragma mark dispatch_client_callout
966
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
972
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()
977
978 #undef _dispatch_client_callout
979 DISPATCH_NOINLINE
980 void
981 _dispatch_client_callout(void *ctxt, dispatch_function_t f)
982 {
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);
987 f(ctxt);
988 _dispatch_free_unwind_tsd();
989 _dispatch_set_unwind_tsd(u);
990 }
991
992 #undef _dispatch_client_callout2
993 DISPATCH_NOINLINE
994 void
995 _dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
996 {
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);
1001 f(ctxt, i);
1002 _dispatch_free_unwind_tsd();
1003 _dispatch_set_unwind_tsd(u);
1004 }
1005
1006 #if HAVE_MACH
1007
1008 #undef _dispatch_client_callout3
1009 DISPATCH_NOINLINE
1010 void
1011 _dispatch_client_callout3(void *ctxt, dispatch_mach_reason_t reason,
1012 dispatch_mach_msg_t dmsg, dispatch_mach_async_reply_callback_t f)
1013 {
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);
1021 }
1022
1023 #undef _dispatch_client_callout4
1024 void
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)
1028 {
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);
1036 }
1037 #endif // HAVE_MACH
1038
1039 #endif // DISPATCH_USE_CLIENT_CALLOUT
1040
1041 #pragma mark -
1042 #pragma mark _os_object_t no_objc
1043
1044 #if !USE_OBJC
1045
1046 static const _os_object_vtable_s _os_object_vtable;
1047
1048 void
1049 _os_object_init(void)
1050 {
1051 return;
1052 }
1053
1054 inline _os_object_t
1055 _os_object_alloc_realized(const void *cls, size_t size)
1056 {
1057 _os_object_t obj;
1058 dispatch_assert(size >= sizeof(struct _os_object_s));
1059 while (!fastpath(obj = calloc(1u, size))) {
1060 _dispatch_temporary_resource_shortage();
1061 }
1062 obj->os_obj_isa = cls;
1063 return obj;
1064 }
1065
1066 _os_object_t
1067 _os_object_alloc(const void *cls, size_t size)
1068 {
1069 if (!cls) cls = &_os_object_vtable;
1070 return _os_object_alloc_realized(cls, size);
1071 }
1072
1073 void
1074 _os_object_dealloc(_os_object_t obj)
1075 {
1076 *((void *volatile*)&obj->os_obj_isa) = (void *)0x200;
1077 return free(obj);
1078 }
1079
1080 void
1081 _os_object_xref_dispose(_os_object_t obj)
1082 {
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);
1086 }
1087 return _os_object_release_internal(obj);
1088 }
1089
1090 void
1091 _os_object_dispose(_os_object_t obj)
1092 {
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);
1096 }
1097 return _os_object_dealloc(obj);
1098 }
1099
1100 void*
1101 os_retain(void *obj)
1102 {
1103 if (fastpath(obj)) {
1104 return _os_object_retain(obj);
1105 }
1106 return obj;
1107 }
1108
1109 #undef os_release
1110 void
1111 os_release(void *obj)
1112 {
1113 if (fastpath(obj)) {
1114 return _os_object_release(obj);
1115 }
1116 }
1117
1118 void
1119 _os_object_atfork_prepare(void)
1120 {
1121 return;
1122 }
1123
1124 void
1125 _os_object_atfork_parent(void)
1126 {
1127 return;
1128 }
1129
1130 void
1131 _os_object_atfork_child(void)
1132 {
1133 return;
1134 }
1135
1136 #pragma mark -
1137 #pragma mark dispatch_autorelease_pool no_objc
1138
1139 #if DISPATCH_COCOA_COMPAT
1140
1141 void*
1142 _dispatch_autorelease_pool_push(void)
1143 {
1144 void *pool = NULL;
1145 if (_dispatch_begin_NSAutoReleasePool) {
1146 pool = _dispatch_begin_NSAutoReleasePool();
1147 }
1148 return pool;
1149 }
1150
1151 void
1152 _dispatch_autorelease_pool_pop(void *pool)
1153 {
1154 if (_dispatch_end_NSAutoReleasePool) {
1155 _dispatch_end_NSAutoReleasePool(pool);
1156 }
1157 }
1158
1159 void
1160 _dispatch_last_resort_autorelease_pool_push(dispatch_invoke_context_t dic)
1161 {
1162 dic->dic_autorelease_pool = _dispatch_autorelease_pool_push();
1163 }
1164
1165 void
1166 _dispatch_last_resort_autorelease_pool_pop(dispatch_invoke_context_t dic)
1167 {
1168 _dispatch_autorelease_pool_pop(dic->dic_autorelease_pool);
1169 dic->dic_autorelease_pool = NULL;
1170 }
1171
1172 #endif // DISPATCH_COCOA_COMPAT
1173 #endif // !USE_OBJC
1174
1175 #pragma mark -
1176 #pragma mark dispatch_mig
1177 #if HAVE_MACH
1178
1179 void *
1180 dispatch_mach_msg_get_context(mach_msg_header_t *msg)
1181 {
1182 mach_msg_context_trailer_t *tp;
1183 void *context = NULL;
1184
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;
1190 }
1191 return context;
1192 }
1193
1194 kern_return_t
1195 _dispatch_wakeup_runloop_thread(mach_port_t mp DISPATCH_UNUSED)
1196 {
1197 // dummy function just to pop a runloop thread out of mach_msg()
1198 return 0;
1199 }
1200
1201 kern_return_t
1202 _dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED)
1203 {
1204 // dummy function to consume a send-once right
1205 return 0;
1206 }
1207
1208 kern_return_t
1209 _dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED,
1210 mach_port_t name)
1211 {
1212 DISPATCH_INTERNAL_CRASH(name, "unexpected receipt of port-destroyed");
1213 return KERN_FAILURE;
1214 }
1215
1216 kern_return_t
1217 _dispatch_mach_notify_no_senders(mach_port_t notify DISPATCH_UNUSED,
1218 mach_port_mscount_t mscnt)
1219 {
1220 DISPATCH_INTERNAL_CRASH(mscnt, "unexpected receipt of no-more-senders");
1221 return KERN_FAILURE;
1222 }
1223
1224 kern_return_t
1225 _dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED)
1226 {
1227 // we only register for dead-name notifications
1228 // some code deallocated our send-once right without consuming it
1229 #if DISPATCH_DEBUG
1230 _dispatch_log("Corruption: An app/library deleted a libdispatch "
1231 "dead-name notification");
1232 #endif
1233 return KERN_SUCCESS;
1234 }
1235
1236 #endif // HAVE_MACH