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