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