xref: /trueos/lib/libdispatch/src/init.c (revision b8b6ef70f63ac612e5cd67f64f3c877e14221e84)
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