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