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