]> git.saurik.com Git - apple/libdispatch.git/blob - src/init.c
libdispatch-228.23.tar.gz
[apple/libdispatch.git] / src / init.c
1 /*
2 * Copyright (c) 2008-2011 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 void
59 dummy_function(void)
60 {
61 }
62
63 long
64 dummy_function_r0(void)
65 {
66 return 0;
67 }
68
69 #pragma mark -
70 #pragma mark dispatch_globals
71
72 #if DISPATCH_COCOA_COMPAT
73 void (*dispatch_begin_thread_4GC)(void);
74 void (*dispatch_end_thread_4GC)(void);
75 void (*dispatch_no_worker_threads_4GC)(void);
76 void *(*_dispatch_begin_NSAutoReleasePool)(void);
77 void (*_dispatch_end_NSAutoReleasePool)(void *);
78 #endif
79
80 #if !DISPATCH_USE_DIRECT_TSD
81 pthread_key_t dispatch_queue_key;
82 pthread_key_t dispatch_sema4_key;
83 pthread_key_t dispatch_cache_key;
84 pthread_key_t dispatch_io_key;
85 pthread_key_t dispatch_apply_key;
86 #if DISPATCH_PERF_MON
87 pthread_key_t dispatch_bcounter_key;
88 #endif
89 #endif // !DISPATCH_USE_DIRECT_TSD
90
91 struct _dispatch_hw_config_s _dispatch_hw_config;
92 bool _dispatch_safe_fork = true;
93
94 DISPATCH_NOINLINE
95 bool
96 _dispatch_is_multithreaded(void)
97 {
98 return !_dispatch_safe_fork;
99 }
100
101 const struct dispatch_queue_offsets_s dispatch_queue_offsets = {
102 .dqo_version = 3,
103 .dqo_label = offsetof(struct dispatch_queue_s, dq_label),
104 .dqo_label_size = sizeof(((dispatch_queue_t)NULL)->dq_label),
105 .dqo_flags = 0,
106 .dqo_flags_size = 0,
107 .dqo_width = offsetof(struct dispatch_queue_s, dq_width),
108 .dqo_width_size = sizeof(((dispatch_queue_t)NULL)->dq_width),
109 .dqo_serialnum = offsetof(struct dispatch_queue_s, dq_serialnum),
110 .dqo_serialnum_size = sizeof(((dispatch_queue_t)NULL)->dq_serialnum),
111 .dqo_running = offsetof(struct dispatch_queue_s, dq_running),
112 .dqo_running_size = sizeof(((dispatch_queue_t)NULL)->dq_running),
113 };
114
115 // 6618342 Contact the team that owns the Instrument DTrace probe before
116 // renaming this symbol
117 DISPATCH_CACHELINE_ALIGN
118 struct dispatch_queue_s _dispatch_main_q = {
119 .do_vtable = DISPATCH_VTABLE(queue),
120 #if !DISPATCH_USE_RESOLVERS
121 .do_targetq = &_dispatch_root_queues[
122 DISPATCH_ROOT_QUEUE_IDX_DEFAULT_OVERCOMMIT_PRIORITY],
123 #endif
124 .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT,
125 .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT,
126 .do_suspend_cnt = DISPATCH_OBJECT_SUSPEND_LOCK,
127 .dq_label = "com.apple.main-thread",
128 .dq_running = 1,
129 .dq_width = 1,
130 .dq_serialnum = 1,
131 };
132
133 struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent = {
134 .do_vtable = DISPATCH_VTABLE(queue_attr),
135 .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT,
136 .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT,
137 .do_next = DISPATCH_OBJECT_LISTLESS,
138 };
139
140 #pragma mark -
141 #pragma mark dispatch_vtables
142
143 DISPATCH_VTABLE_INSTANCE(semaphore,
144 .do_type = DISPATCH_SEMAPHORE_TYPE,
145 .do_kind = "semaphore",
146 .do_dispose = _dispatch_semaphore_dispose,
147 .do_debug = _dispatch_semaphore_debug,
148 );
149
150 DISPATCH_VTABLE_INSTANCE(group,
151 .do_type = DISPATCH_GROUP_TYPE,
152 .do_kind = "group",
153 .do_dispose = _dispatch_semaphore_dispose,
154 .do_debug = _dispatch_semaphore_debug,
155 );
156
157 DISPATCH_VTABLE_INSTANCE(queue,
158 .do_type = DISPATCH_QUEUE_TYPE,
159 .do_kind = "queue",
160 .do_dispose = _dispatch_queue_dispose,
161 .do_invoke = NULL,
162 .do_probe = (void *)dummy_function_r0,
163 .do_debug = dispatch_queue_debug,
164 );
165
166 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_root, queue,
167 .do_type = DISPATCH_QUEUE_GLOBAL_TYPE,
168 .do_kind = "global-queue",
169 .do_debug = dispatch_queue_debug,
170 .do_probe = _dispatch_queue_probe_root,
171 );
172
173 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_mgr, queue,
174 .do_type = DISPATCH_QUEUE_MGR_TYPE,
175 .do_kind = "mgr-queue",
176 .do_invoke = _dispatch_mgr_thread,
177 .do_debug = dispatch_queue_debug,
178 .do_probe = _dispatch_mgr_wakeup,
179 );
180
181 DISPATCH_VTABLE_INSTANCE(queue_specific_queue,
182 .do_type = DISPATCH_QUEUE_SPECIFIC_TYPE,
183 .do_kind = "queue-context",
184 .do_dispose = _dispatch_queue_specific_queue_dispose,
185 .do_invoke = NULL,
186 .do_probe = (void *)dummy_function_r0,
187 .do_debug = (void *)dispatch_queue_debug,
188 );
189
190 DISPATCH_VTABLE_INSTANCE(queue_attr,
191 .do_type = DISPATCH_QUEUE_ATTR_TYPE,
192 .do_kind = "queue-attr",
193 );
194
195 DISPATCH_VTABLE_INSTANCE(source,
196 .do_type = DISPATCH_SOURCE_KEVENT_TYPE,
197 .do_kind = "kevent-source",
198 .do_invoke = _dispatch_source_invoke,
199 .do_dispose = _dispatch_source_dispose,
200 .do_probe = _dispatch_source_probe,
201 .do_debug = _dispatch_source_debug,
202 );
203
204 DISPATCH_VTABLE_INSTANCE(data,
205 .do_type = DISPATCH_DATA_TYPE,
206 .do_kind = "data",
207 .do_dispose = _dispatch_data_dispose,
208 .do_invoke = NULL,
209 .do_probe = (void *)dummy_function_r0,
210 .do_debug = _dispatch_data_debug,
211 );
212
213 DISPATCH_VTABLE_INSTANCE(io,
214 .do_type = DISPATCH_IO_TYPE,
215 .do_kind = "channel",
216 .do_dispose = _dispatch_io_dispose,
217 .do_invoke = NULL,
218 .do_probe = (void *)dummy_function_r0,
219 .do_debug = (void *)dummy_function_r0,
220 );
221
222 DISPATCH_VTABLE_INSTANCE(operation,
223 .do_type = DISPATCH_OPERATION_TYPE,
224 .do_kind = "operation",
225 .do_dispose = _dispatch_operation_dispose,
226 .do_invoke = NULL,
227 .do_probe = (void *)dummy_function_r0,
228 .do_debug = (void *)dummy_function_r0,
229 );
230
231 DISPATCH_VTABLE_INSTANCE(disk,
232 .do_type = DISPATCH_DISK_TYPE,
233 .do_kind = "disk",
234 .do_dispose = _dispatch_disk_dispose,
235 .do_invoke = NULL,
236 .do_probe = (void *)dummy_function_r0,
237 .do_debug = (void *)dummy_function_r0,
238 );
239
240 void
241 _dispatch_vtable_init(void)
242 {
243 #if USE_OBJC
244 // ObjC classes and dispatch vtables are co-located via linker order and
245 // alias files, verify correct layout during initialization rdar://10640168
246 #define DISPATCH_OBJC_CLASS(name) \
247 DISPATCH_CONCAT(OBJC_CLASS_$_,DISPATCH_CLASS(name))
248 extern void *DISPATCH_OBJC_CLASS(semaphore);
249 dispatch_assert((char*)DISPATCH_VTABLE(semaphore) -
250 (char*)&DISPATCH_OBJC_CLASS(semaphore) == 0);
251 dispatch_assert((char*)&DISPATCH_CONCAT(_,DISPATCH_CLASS(semaphore_vtable))
252 - (char*)&DISPATCH_OBJC_CLASS(semaphore) ==
253 sizeof(_os_object_class_s));
254 #endif
255 }
256
257 #pragma mark -
258 #pragma mark dispatch_bug
259
260 static char _dispatch_build[16];
261
262 static void
263 _dispatch_build_init(void *context DISPATCH_UNUSED)
264 {
265 #ifdef __APPLE__
266 int mib[] = { CTL_KERN, KERN_OSVERSION };
267 size_t bufsz = sizeof(_dispatch_build);
268
269 sysctl(mib, 2, _dispatch_build, &bufsz, NULL, 0);
270 #else
271 /*
272 * XXXRW: What to do here for !Mac OS X?
273 */
274 memset(_dispatch_build, 0, sizeof(_dispatch_build));
275 #endif
276 }
277
278 #define _dispatch_bug_log(msg, ...) do { \
279 static void *last_seen; \
280 void *ra = __builtin_return_address(0); \
281 if (last_seen != ra) { \
282 last_seen = ra; \
283 _dispatch_log((msg), ##__VA_ARGS__); \
284 } \
285 } while(0)
286
287 void
288 _dispatch_bug(size_t line, long val)
289 {
290 static dispatch_once_t pred;
291
292 dispatch_once_f(&pred, NULL, _dispatch_build_init);
293 _dispatch_bug_log("BUG in libdispatch: %s - %lu - 0x%lx",
294 _dispatch_build, (unsigned long)line, val);
295 }
296
297 void
298 _dispatch_bug_client(const char* msg)
299 {
300 _dispatch_bug_log("BUG in libdispatch client: %s", msg);
301 }
302
303 void
304 _dispatch_bug_mach_client(const char* msg, mach_msg_return_t kr)
305 {
306 _dispatch_bug_log("BUG in libdispatch client: %s %s - 0x%x", msg,
307 mach_error_string(kr), kr);
308 }
309
310 void
311 _dispatch_abort(size_t line, long val)
312 {
313 _dispatch_bug(line, val);
314 abort();
315 }
316
317 #pragma mark -
318 #pragma mark dispatch_log
319
320 static FILE *dispatch_logfile;
321 static bool dispatch_log_disabled;
322 static dispatch_once_t _dispatch_logv_pred;
323
324 static void
325 _dispatch_logv_init(void *context DISPATCH_UNUSED)
326 {
327 #if DISPATCH_DEBUG
328 bool log_to_file = true;
329 #else
330 bool log_to_file = false;
331 #endif
332 char *e = getenv("LIBDISPATCH_LOG");
333 if (e) {
334 if (strcmp(e, "YES") == 0) {
335 // default
336 } else if (strcmp(e, "NO") == 0) {
337 dispatch_log_disabled = true;
338 } else if (strcmp(e, "syslog") == 0) {
339 log_to_file = false;
340 } else if (strcmp(e, "file") == 0) {
341 log_to_file = true;
342 } else if (strcmp(e, "stderr") == 0) {
343 log_to_file = true;
344 dispatch_logfile = stderr;
345 }
346 }
347 if (!dispatch_log_disabled) {
348 if (log_to_file && !dispatch_logfile) {
349 char path[PATH_MAX];
350 snprintf(path, sizeof(path), "/var/tmp/libdispatch.%d.log",
351 getpid());
352 dispatch_logfile = fopen(path, "a");
353 }
354 if (dispatch_logfile) {
355 struct timeval tv;
356 gettimeofday(&tv, NULL);
357 fprintf(dispatch_logfile, "=== log file opened for %s[%u] at "
358 "%ld.%06u ===\n", getprogname() ?: "", getpid(),
359 tv.tv_sec, tv.tv_usec);
360 fflush(dispatch_logfile);
361 }
362 }
363 }
364
365 DISPATCH_NOINLINE
366 static void
367 _dispatch_logv_file(const char *msg, va_list ap)
368 {
369 char *buf;
370 size_t len;
371
372 len = vasprintf(&buf, msg, ap);
373 buf[len++] = '\n';
374 fwrite(buf, 1, len, dispatch_logfile);
375 fflush(dispatch_logfile);
376 free(buf);
377 }
378
379 static inline void
380 _dispatch_logv(const char *msg, va_list ap)
381 {
382 dispatch_once_f(&_dispatch_logv_pred, NULL, _dispatch_logv_init);
383 if (slowpath(dispatch_log_disabled)) {
384 return;
385 }
386 if (slowpath(dispatch_logfile)) {
387 return _dispatch_logv_file(msg, ap);
388 }
389 vsyslog(LOG_NOTICE, msg, ap);
390 }
391
392 DISPATCH_NOINLINE
393 void
394 _dispatch_log(const char *msg, ...)
395 {
396 va_list ap;
397
398 va_start(ap, msg);
399 _dispatch_logv(msg, ap);
400 va_end(ap);
401 }
402
403 #pragma mark -
404 #pragma mark dispatch_debug
405
406 DISPATCH_NOINLINE
407 void
408 dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
409 {
410 char buf[4096];
411 size_t offs;
412
413 if (dou._do && dou._do->do_vtable->do_debug) {
414 offs = dx_debug(dou._do, buf, sizeof(buf));
415 } else {
416 offs = snprintf(buf, sizeof(buf), "NULL vtable slot");
417 }
418
419 snprintf(buf + offs, sizeof(buf) - offs, ": %s", msg);
420 _dispatch_logv(buf, ap);
421 }
422
423 DISPATCH_NOINLINE
424 void
425 dispatch_debug(dispatch_object_t dou, const char *msg, ...)
426 {
427 va_list ap;
428
429 va_start(ap, msg);
430 dispatch_debugv(dou._do, msg, ap);
431 va_end(ap);
432 }
433
434 #pragma mark -
435 #pragma mark dispatch_block_t
436
437 #ifdef __BLOCKS__
438
439 #undef _dispatch_Block_copy
440 dispatch_block_t
441 _dispatch_Block_copy(dispatch_block_t db)
442 {
443 dispatch_block_t rval;
444
445 if (fastpath(db)) {
446 while (!fastpath(rval = Block_copy(db))) {
447 sleep(1);
448 }
449 return rval;
450 }
451 DISPATCH_CLIENT_CRASH("NULL was passed where a block should have been");
452 }
453
454 void
455 _dispatch_call_block_and_release(void *block)
456 {
457 void (^b)(void) = block;
458 b();
459 Block_release(b);
460 }
461
462 #endif // __BLOCKS__
463
464 #pragma mark -
465 #pragma mark dispatch_client_callout
466
467 // Abort on uncaught exceptions thrown from client callouts rdar://8577499
468 #if DISPATCH_USE_CLIENT_CALLOUT && (__arm__ || !USE_OBJC)
469 // On platforms with SjLj exceptions, avoid the SjLj overhead on every callout
470 // by clearing the unwinder's TSD pointer to the handler stack around callouts
471
472 #define _dispatch_get_tsd_base()
473 #define _dispatch_get_unwind_tsd() (NULL)
474 #define _dispatch_set_unwind_tsd(u) do {(void)(u);} while (0)
475 #define _dispatch_free_unwind_tsd()
476
477 #undef _dispatch_client_callout
478 DISPATCH_NOINLINE
479 void
480 _dispatch_client_callout(void *ctxt, dispatch_function_t f)
481 {
482 _dispatch_get_tsd_base();
483 void *u = _dispatch_get_unwind_tsd();
484 _dispatch_set_unwind_tsd(NULL);
485 f(ctxt);
486 _dispatch_free_unwind_tsd();
487 _dispatch_set_unwind_tsd(u);
488 }
489
490 #undef _dispatch_client_callout2
491 DISPATCH_NOINLINE
492 void
493 _dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
494 {
495 _dispatch_get_tsd_base();
496 void *u = _dispatch_get_unwind_tsd();
497 _dispatch_set_unwind_tsd(NULL);
498 f(ctxt, i);
499 _dispatch_free_unwind_tsd();
500 _dispatch_set_unwind_tsd(u);
501 }
502
503 #endif // DISPATCH_USE_CLIENT_CALLOUT
504
505 #pragma mark -
506 #pragma mark _os_object_t no_objc
507
508 #if !USE_OBJC
509
510 static const _os_object_class_s _os_object_class;
511
512 void
513 _os_object_init(void)
514 {
515 return;
516 }
517
518 _os_object_t
519 _os_object_alloc(const void *cls, size_t size)
520 {
521 _os_object_t obj;
522 dispatch_assert(size >= sizeof(struct _os_object_s));
523 if (!cls) cls = &_os_object_class;
524 while (!fastpath(obj = calloc(1u, size))) {
525 sleep(1); // Temporary resource shortage
526 }
527 obj->os_obj_isa = cls;
528 return obj;
529 }
530
531 void
532 _os_object_dealloc(_os_object_t obj)
533 {
534 *((void *volatile*)&obj->os_obj_isa) = (void *)0x200;
535 return free(obj);
536 }
537
538 void
539 _os_object_xref_dispose(_os_object_t obj)
540 {
541 if (fastpath(obj->os_obj_isa->_os_obj_xref_dispose)) {
542 return obj->os_obj_isa->_os_obj_xref_dispose(obj);
543 }
544 return _os_object_release_internal(obj);
545 }
546
547 void
548 _os_object_dispose(_os_object_t obj)
549 {
550 if (fastpath(obj->os_obj_isa->_os_obj_dispose)) {
551 return obj->os_obj_isa->_os_obj_dispose(obj);
552 }
553 return _os_object_dealloc(obj);
554 }
555
556 #pragma mark -
557 #pragma mark dispatch_autorelease_pool no_objc
558
559 #if DISPATCH_COCOA_COMPAT
560
561 void *_dispatch_autorelease_pool_push(void) {
562 void *pool = NULL;
563 if (_dispatch_begin_NSAutoReleasePool) {
564 pool = _dispatch_begin_NSAutoReleasePool();
565 }
566 return pool;
567 }
568
569 void _dispatch_autorelease_pool_pop(void *pool) {
570 if (_dispatch_end_NSAutoReleasePool) {
571 _dispatch_end_NSAutoReleasePool(pool);
572 }
573 }
574
575 #endif // DISPATCH_COCOA_COMPAT
576 #endif // !USE_OBJC
577
578 #pragma mark -
579 #pragma mark dispatch_source_types
580
581 static void
582 dispatch_source_type_timer_init(dispatch_source_t ds,
583 dispatch_source_type_t type DISPATCH_UNUSED,
584 uintptr_t handle DISPATCH_UNUSED,
585 unsigned long mask,
586 dispatch_queue_t q DISPATCH_UNUSED)
587 {
588 ds->ds_refs = calloc(1ul, sizeof(struct dispatch_timer_source_refs_s));
589 if (slowpath(!ds->ds_refs)) return;
590 ds->ds_needs_rearm = true;
591 ds->ds_is_timer = true;
592 ds_timer(ds->ds_refs).flags = mask;
593 }
594
595 const struct dispatch_source_type_s _dispatch_source_type_timer = {
596 .ke = {
597 .filter = DISPATCH_EVFILT_TIMER,
598 },
599 .mask = DISPATCH_TIMER_WALL_CLOCK,
600 .init = dispatch_source_type_timer_init,
601 };
602
603 const struct dispatch_source_type_s _dispatch_source_type_read = {
604 .ke = {
605 .filter = EVFILT_READ,
606 .flags = EV_DISPATCH,
607 },
608 };
609
610 const struct dispatch_source_type_s _dispatch_source_type_write = {
611 .ke = {
612 .filter = EVFILT_WRITE,
613 .flags = EV_DISPATCH,
614 },
615 };
616
617 #if DISPATCH_USE_VM_PRESSURE
618 #if TARGET_IPHONE_SIMULATOR // rdar://problem/9219483
619 static int _dispatch_ios_simulator_memory_warnings_fd = -1;
620 static void
621 _dispatch_ios_simulator_vm_source_init(void *context DISPATCH_UNUSED)
622 {
623 char *e = getenv("IPHONE_SIMULATOR_MEMORY_WARNINGS");
624 if (!e) return;
625 _dispatch_ios_simulator_memory_warnings_fd = open(e, O_EVTONLY);
626 if (_dispatch_ios_simulator_memory_warnings_fd == -1) {
627 (void)dispatch_assume_zero(errno);
628 }
629 }
630 static void
631 dispatch_source_type_vm_init(dispatch_source_t ds,
632 dispatch_source_type_t type DISPATCH_UNUSED,
633 uintptr_t handle DISPATCH_UNUSED,
634 unsigned long mask,
635 dispatch_queue_t q DISPATCH_UNUSED)
636 {
637 static dispatch_once_t pred;
638 dispatch_once_f(&pred, NULL, _dispatch_ios_simulator_vm_source_init);
639 ds->ds_dkev->dk_kevent.ident = (mask & DISPATCH_VM_PRESSURE ?
640 _dispatch_ios_simulator_memory_warnings_fd : -1);
641 }
642
643 const struct dispatch_source_type_s _dispatch_source_type_vm = {
644 .ke = {
645 .filter = EVFILT_VNODE,
646 .flags = EV_CLEAR,
647 },
648 .mask = NOTE_ATTRIB,
649 .init = dispatch_source_type_vm_init,
650 };
651 #else
652 static void
653 dispatch_source_type_vm_init(dispatch_source_t ds,
654 dispatch_source_type_t type DISPATCH_UNUSED,
655 uintptr_t handle DISPATCH_UNUSED,
656 unsigned long mask DISPATCH_UNUSED,
657 dispatch_queue_t q DISPATCH_UNUSED)
658 {
659 ds->ds_is_level = false;
660 }
661
662 const struct dispatch_source_type_s _dispatch_source_type_vm = {
663 .ke = {
664 .filter = EVFILT_VM,
665 .flags = EV_DISPATCH,
666 },
667 .mask = NOTE_VM_PRESSURE,
668 .init = dispatch_source_type_vm_init,
669 };
670 #endif
671 #endif
672
673 const struct dispatch_source_type_s _dispatch_source_type_proc = {
674 .ke = {
675 .filter = EVFILT_PROC,
676 .flags = EV_CLEAR,
677 },
678 .mask = NOTE_EXIT|NOTE_FORK|NOTE_EXEC
679 #if HAVE_DECL_NOTE_SIGNAL
680 |NOTE_SIGNAL
681 #endif
682 #if HAVE_DECL_NOTE_REAP
683 |NOTE_REAP
684 #endif
685 ,
686 };
687
688 const struct dispatch_source_type_s _dispatch_source_type_signal = {
689 .ke = {
690 .filter = EVFILT_SIGNAL,
691 },
692 };
693
694 const struct dispatch_source_type_s _dispatch_source_type_vnode = {
695 .ke = {
696 .filter = EVFILT_VNODE,
697 .flags = EV_CLEAR,
698 },
699 .mask = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|
700 NOTE_RENAME|NOTE_REVOKE
701 #if HAVE_DECL_NOTE_NONE
702 |NOTE_NONE
703 #endif
704 ,
705 };
706
707 const struct dispatch_source_type_s _dispatch_source_type_vfs = {
708 .ke = {
709 .filter = EVFILT_FS,
710 .flags = EV_CLEAR,
711 },
712 .mask = VQ_NOTRESP|VQ_NEEDAUTH|VQ_LOWDISK|VQ_MOUNT|VQ_UNMOUNT|VQ_DEAD|
713 VQ_ASSIST|VQ_NOTRESPLOCK
714 #if HAVE_DECL_VQ_UPDATE
715 |VQ_UPDATE
716 #endif
717 #if HAVE_DECL_VQ_VERYLOWDISK
718 |VQ_VERYLOWDISK
719 #endif
720 ,
721 };
722
723 const struct dispatch_source_type_s _dispatch_source_type_data_add = {
724 .ke = {
725 .filter = DISPATCH_EVFILT_CUSTOM_ADD,
726 },
727 };
728
729 const struct dispatch_source_type_s _dispatch_source_type_data_or = {
730 .ke = {
731 .filter = DISPATCH_EVFILT_CUSTOM_OR,
732 .flags = EV_CLEAR,
733 .fflags = ~0,
734 },
735 };
736
737 #if HAVE_MACH
738
739 static void
740 dispatch_source_type_mach_send_init(dispatch_source_t ds,
741 dispatch_source_type_t type DISPATCH_UNUSED,
742 uintptr_t handle DISPATCH_UNUSED, unsigned long mask,
743 dispatch_queue_t q DISPATCH_UNUSED)
744 {
745 static dispatch_once_t pred;
746 dispatch_once_f(&pred, NULL, _dispatch_mach_notify_source_init);
747 if (!mask) {
748 // Preserve legacy behavior that (mask == 0) => DISPATCH_MACH_SEND_DEAD
749 ds->ds_dkev->dk_kevent.fflags = DISPATCH_MACH_SEND_DEAD;
750 ds->ds_pending_data_mask = DISPATCH_MACH_SEND_DEAD;
751 }
752 }
753
754 const struct dispatch_source_type_s _dispatch_source_type_mach_send = {
755 .ke = {
756 .filter = EVFILT_MACHPORT,
757 .flags = EV_CLEAR,
758 },
759 .mask = DISPATCH_MACH_SEND_DEAD|DISPATCH_MACH_SEND_POSSIBLE,
760 .init = dispatch_source_type_mach_send_init,
761 };
762
763 static void
764 dispatch_source_type_mach_recv_init(dispatch_source_t ds,
765 dispatch_source_type_t type DISPATCH_UNUSED,
766 uintptr_t handle DISPATCH_UNUSED,
767 unsigned long mask DISPATCH_UNUSED,
768 dispatch_queue_t q DISPATCH_UNUSED)
769 {
770 ds->ds_is_level = false;
771 }
772
773 const struct dispatch_source_type_s _dispatch_source_type_mach_recv = {
774 .ke = {
775 .filter = EVFILT_MACHPORT,
776 .flags = EV_DISPATCH,
777 .fflags = DISPATCH_MACH_RECV_MESSAGE,
778 },
779 .init = dispatch_source_type_mach_recv_init,
780 };
781
782 const struct dispatch_source_type_s _dispatch_source_type_sock = {
783 #ifdef EVFILT_SOCK
784 .ke = {
785 .filter = EVFILT_SOCK,
786 .flags = EV_CLEAR,
787 },
788 .mask = NOTE_CONNRESET | NOTE_READCLOSED | NOTE_WRITECLOSED |
789 NOTE_TIMEOUT | NOTE_NOSRCADDR | NOTE_IFDENIED | NOTE_SUSPEND |
790 NOTE_RESUME | NOTE_KEEPALIVE,
791 #endif
792 };
793
794 #pragma mark -
795 #pragma mark dispatch_mig
796
797 void *
798 dispatch_mach_msg_get_context(mach_msg_header_t *msg)
799 {
800 mach_msg_context_trailer_t *tp;
801 void *context = NULL;
802
803 tp = (mach_msg_context_trailer_t *)((uint8_t *)msg +
804 round_msg(msg->msgh_size));
805 if (tp->msgh_trailer_size >=
806 (mach_msg_size_t)sizeof(mach_msg_context_trailer_t)) {
807 context = (void *)(uintptr_t)tp->msgh_context;
808 }
809 return context;
810 }
811
812 kern_return_t
813 _dispatch_wakeup_main_thread(mach_port_t mp DISPATCH_UNUSED)
814 {
815 // dummy function just to pop out the main thread out of mach_msg()
816 return 0;
817 }
818
819 kern_return_t
820 _dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED)
821 {
822 // dummy function to consume a send-once right
823 return 0;
824 }
825
826 kern_return_t
827 _dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED,
828 mach_port_t name)
829 {
830 kern_return_t kr;
831 // this function should never be called
832 (void)dispatch_assume_zero(name);
833 kr = mach_port_mod_refs(mach_task_self(), name, MACH_PORT_RIGHT_RECEIVE,-1);
834 DISPATCH_VERIFY_MIG(kr);
835 (void)dispatch_assume_zero(kr);
836 return KERN_SUCCESS;
837 }
838
839 kern_return_t
840 _dispatch_mach_notify_no_senders(mach_port_t notify,
841 mach_port_mscount_t mscnt DISPATCH_UNUSED)
842 {
843 // this function should never be called
844 (void)dispatch_assume_zero(notify);
845 return KERN_SUCCESS;
846 }
847
848 kern_return_t
849 _dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED)
850 {
851 // we only register for dead-name notifications
852 // some code deallocated our send-once right without consuming it
853 #if DISPATCH_DEBUG
854 _dispatch_log("Corruption: An app/library deleted a libdispatch "
855 "dead-name notification");
856 #endif
857 return KERN_SUCCESS;
858 }
859
860 #endif // HAVE_MACH