2 * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
21 // Contains exported global data and initialization & other routines that must
22 // only exist once in the shared library even when resolvers are used.
27 #include "protocolServer.h"
31 #pragma mark dispatch_init
33 #if USE_LIBDISPATCH_INIT_CONSTRUCTOR
34 DISPATCH_NOTHROW
__attribute__((constructor
))
36 _libdispatch_init(void);
38 DISPATCH_EXPORT DISPATCH_NOTHROW
40 _libdispatch_init(void)
46 DISPATCH_EXPORT DISPATCH_NOTHROW
48 dispatch_atfork_prepare(void)
52 DISPATCH_EXPORT DISPATCH_NOTHROW
54 dispatch_atfork_parent(void)
59 #pragma mark dispatch_globals
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 *);
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
;
80 #endif // !DISPATCH_USE_DIRECT_TSD
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
;
87 voucher_activity_mode_t _voucher_activity_mode
;
88 int _dispatch_set_qos_class_enabled
;
92 voucher_activity_mode_t
93 voucher_activity_get_mode(void)
95 return _voucher_activity_mode
;
99 voucher_activity_set_mode_4libtrace(voucher_activity_mode_t mode
)
101 if (_voucher_activity_disabled()) return;
102 _voucher_activity_mode
= mode
;
105 DISPATCH_HW_CONFIG();
106 bool _dispatch_safe_fork
= true, _dispatch_child_of_unsafe_fork
;
110 _dispatch_is_multithreaded(void)
112 return !_dispatch_safe_fork
;
117 _dispatch_is_fork_of_multithreaded_parent(void)
119 return _dispatch_child_of_unsafe_fork
;
122 const struct dispatch_queue_offsets_s dispatch_queue_offsets
= {
124 .dqo_label
= offsetof(struct dispatch_queue_s
, dq_label
),
125 .dqo_label_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_label
),
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
),
142 #if VOUCHER_USE_MACH_VOUCHER
143 const struct voucher_offsets_s voucher_offsets
= {
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
),
150 #else // VOUCHER_USE_MACH_VOUCHER
151 const struct voucher_offsets_s voucher_offsets
= {
154 #endif // VOUCHER_USE_MACH_VOUCHER
156 #if DISPATCH_USE_DIRECT_TSD
157 const struct dispatch_tsd_indexes_s dispatch_tsd_indexes
= {
159 .dti_queue_index
= dispatch_queue_key
,
160 .dti_voucher_index
= dispatch_voucher_key
,
161 .dti_qos_class_index
= dispatch_priority_key
,
163 #else // DISPATCH_USE_DIRECT_TSD
164 #error Not implemented on this platform
165 #endif // DISPATCH_USE_DIRECT_TSD
167 // 6618342 Contact the team that owns the Instrument DTrace probe before
168 // renaming this symbol
169 DISPATCH_CACHELINE_ALIGN
170 struct 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
],
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",
182 .dq_is_thread_bound
= 1,
187 #pragma mark dispatch_queue_attr_t
189 #define DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, overcommit, concurrent) \
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), \
201 #define DISPATCH_QUEUE_ATTR_KIND_INIT(qos, prio) \
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), \
213 #define DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, prio) \
214 [prio] = DISPATCH_QUEUE_ATTR_KIND_INIT(qos, -(prio))
216 #define DISPATCH_QUEUE_ATTR_PRIO_INIT(qos) \
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), \
236 #define DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(qos) \
237 [DQA_INDEX_QOS_CLASS_##qos] = \
238 DISPATCH_QUEUE_ATTR_PRIO_INIT(_DISPATCH_QOS_CLASS_##qos)
240 const 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
),
253 #pragma mark dispatch_vtables
255 DISPATCH_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
,
262 DISPATCH_VTABLE_INSTANCE(group
,
263 .do_type
= DISPATCH_GROUP_TYPE
,
265 .do_dispose
= _dispatch_semaphore_dispose
,
266 .do_debug
= _dispatch_semaphore_debug
,
269 DISPATCH_VTABLE_INSTANCE(queue
,
270 .do_type
= DISPATCH_QUEUE_TYPE
,
272 .do_dispose
= _dispatch_queue_dispose
,
273 .do_invoke
= _dispatch_queue_invoke
,
274 .do_probe
= _dispatch_queue_probe
,
275 .do_debug
= dispatch_queue_debug
,
278 DISPATCH_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
,
286 DISPATCH_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
,
295 DISPATCH_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
,
303 DISPATCH_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
,
312 DISPATCH_VTABLE_INSTANCE(queue_attr
,
313 .do_type
= DISPATCH_QUEUE_ATTR_TYPE
,
314 .do_kind
= "queue-attr",
317 DISPATCH_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
,
326 DISPATCH_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
,
335 DISPATCH_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
,
344 DISPATCH_VTABLE_INSTANCE(data
,
345 .do_type
= DISPATCH_DATA_TYPE
,
347 .do_dispose
= _dispatch_data_dispose
,
348 .do_debug
= _dispatch_data_debug
,
352 DISPATCH_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
,
359 DISPATCH_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
,
366 DISPATCH_VTABLE_INSTANCE(disk
,
367 .do_type
= DISPATCH_DISK_TYPE
,
369 .do_dispose
= _dispatch_disk_dispose
,
373 _dispatch_vtable_init(void)
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
));
388 #pragma mark dispatch_bug
390 static char _dispatch_build
[16];
393 _dispatch_build_init(void *context DISPATCH_UNUSED
)
396 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
397 size_t bufsz
= sizeof(_dispatch_build
);
399 sysctl(mib
, 2, _dispatch_build
, &bufsz
, NULL
, 0);
402 * XXXRW: What to do here for !Mac OS X?
404 memset(_dispatch_build
, 0, sizeof(_dispatch_build
));
408 static dispatch_once_t _dispatch_build_pred
;
411 _dispatch_get_build(void)
413 dispatch_once_f(&_dispatch_build_pred
, NULL
, _dispatch_build_init
);
414 return _dispatch_build
;
417 #define _dispatch_bug_log(msg, ...) do { \
418 static void *last_seen; \
419 void *ra = __builtin_return_address(0); \
420 if (last_seen != ra) { \
422 _dispatch_log(msg, ##__VA_ARGS__); \
427 _dispatch_bug(size_t line
, long val
)
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
);
435 _dispatch_bug_client(const char* msg
)
437 _dispatch_bug_log("BUG in libdispatch client: %s", msg
);
441 _dispatch_bug_mach_client(const char* msg
, mach_msg_return_t kr
)
443 _dispatch_bug_log("BUG in libdispatch client: %s %s - 0x%x", msg
,
444 mach_error_string(kr
), kr
);
448 _dispatch_bug_kevent_client(const char* msg
, const char* filter
,
449 const char *operation
, int err
)
451 _dispatch_bug_log("BUG in libdispatch client: %s[%s] %s: \"%s\" - 0x%x",
452 msg
, filter
, operation
, strerror(err
), err
);
456 _dispatch_abort(size_t line
, long val
)
458 _dispatch_bug(line
, val
);
462 #if !DISPATCH_USE_OS_DEBUG_LOG
465 #pragma mark dispatch_log
467 static int dispatch_logfile
= -1;
468 static bool dispatch_log_disabled
;
469 static dispatch_once_t _dispatch_logv_pred
;
472 _dispatch_logv_init(void *context DISPATCH_UNUSED
)
475 bool log_to_file
= true;
477 bool log_to_file
= false;
479 char *e
= getenv("LIBDISPATCH_LOG");
481 if (strcmp(e
, "YES") == 0) {
483 } else if (strcmp(e
, "NO") == 0) {
484 dispatch_log_disabled
= true;
485 } else if (strcmp(e
, "syslog") == 0) {
487 } else if (strcmp(e
, "file") == 0) {
489 } else if (strcmp(e
, "stderr") == 0) {
491 dispatch_logfile
= STDERR_FILENO
;
494 if (!dispatch_log_disabled
) {
495 if (log_to_file
&& dispatch_logfile
== -1) {
497 snprintf(path
, sizeof(path
), "/var/tmp/libdispatch.%d.log",
499 dispatch_logfile
= open(path
, O_WRONLY
| O_APPEND
| O_CREAT
|
500 O_NOFOLLOW
| O_CLOEXEC
, 0666);
502 if (dispatch_logfile
!= -1) {
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
);
513 _dispatch_log_file(char *buf
, size_t len
)
519 r
= write(dispatch_logfile
, buf
, len
);
520 if (slowpath(r
== -1) && errno
== EINTR
) {
527 _dispatch_logv_file(const char *msg
, va_list ap
)
530 int r
= vsnprintf(buf
, sizeof(buf
), msg
, ap
);
532 size_t len
= (size_t)r
;
533 if (len
> sizeof(buf
) - 1) {
534 len
= sizeof(buf
) - 1;
536 _dispatch_log_file(buf
, len
);
539 #if DISPATCH_USE_SIMPLE_ASL
541 _dispatch_syslog(const char *msg
)
543 _simple_asl_log(ASL_LEVEL_NOTICE
, "com.apple.libsystem.libdispatch", msg
);
547 _dispatch_vsyslog(const char *msg
, va_list ap
)
550 vasprintf(&str
, msg
, ap
);
552 _dispatch_syslog(str
);
556 #else // DISPATCH_USE_SIMPLE_ASL
558 _dispatch_syslog(const char *msg
)
560 syslog(LOG_NOTICE
, "%s", msg
);
564 _dispatch_vsyslog(const char *msg
, va_list ap
)
566 vsyslog(LOG_NOTICE
, msg
, *ap_ptr
);
568 #endif // DISPATCH_USE_SIMPLE_ASL
570 DISPATCH_ALWAYS_INLINE
572 _dispatch_logv(const char *msg
, size_t len
, va_list *ap_ptr
)
574 dispatch_once_f(&_dispatch_logv_pred
, NULL
, _dispatch_logv_init
);
575 if (slowpath(dispatch_log_disabled
)) {
578 if (slowpath(dispatch_logfile
!= -1)) {
580 return _dispatch_log_file((char*)msg
, len
);
582 return _dispatch_logv_file(msg
, *ap_ptr
);
585 return _dispatch_syslog(msg
);
587 return _dispatch_vsyslog(msg
, *ap_ptr
);
592 _dispatch_log(const char *msg
, ...)
597 _dispatch_logv(msg
, 0, &ap
);
601 #endif // DISPATCH_USE_OS_DEBUG_LOG
604 #pragma mark dispatch_debug
607 _dispatch_object_debug2(dispatch_object_t dou
, char* buf
, size_t bufsiz
)
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
);
613 return strlcpy(buf
, "NULL vtable slot: ", bufsiz
);
618 _dispatch_debugv(dispatch_object_t dou
, const char *msg
, va_list ap
)
624 offs
= _dispatch_object_debug2(dou
, buf
, sizeof(buf
));
625 dispatch_assert(offs
+ 2 < sizeof(buf
));
630 offs
= strlcpy(buf
, "NULL: ", sizeof(buf
));
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;
638 _dispatch_logv(buf
, len
, NULL
);
640 _dispatch_log("%s", buf
);
646 dispatch_debugv(dispatch_object_t dou
, const char *msg
, va_list ap
)
648 _dispatch_debugv(dou
, msg
, ap
);
653 dispatch_debug(dispatch_object_t dou
, const char *msg
, ...)
658 _dispatch_debugv(dou
, msg
, ap
);
665 _dispatch_object_debug(dispatch_object_t dou
, const char *msg
, ...)
670 _dispatch_debugv(dou
._do
, msg
, ap
);
676 #pragma mark dispatch_calloc
680 _dispatch_temporary_resource_shortage(void)
686 _dispatch_calloc(size_t num_items
, size_t size
)
689 while (!fastpath(buf
= calloc(num_items
, size
))) {
690 _dispatch_temporary_resource_shortage();
696 #pragma mark dispatch_block_t
700 #undef _dispatch_Block_copy
702 _dispatch_Block_copy(dispatch_block_t db
)
704 dispatch_block_t rval
;
707 while (!fastpath(rval
= Block_copy(db
))) {
708 _dispatch_temporary_resource_shortage();
712 DISPATCH_CLIENT_CRASH("NULL was passed where a block should have been");
716 _dispatch_call_block_and_release(void *block
)
718 void (^b
)(void) = block
;
724 #pragma mark _dispatch_block_create no_objc
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.
730 extern void DISPATCH_BLOCK_SPECIAL_INVOKE(void *)
731 asm("____dispatch_block_create_block_invoke");
732 void (*_dispatch_block_special_invoke
)(void*) = DISPATCH_BLOCK_SPECIAL_INVOKE
;
735 _dispatch_block_create(dispatch_block_flags_t flags
, voucher_t voucher
,
736 pthread_priority_t pri
, dispatch_block_t block
)
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.
749 _dispatch_block_invoke(&dbpds
);
751 Block_release(copy_block
);
760 #pragma mark dispatch_client_callout
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
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()
772 #undef _dispatch_client_callout
775 _dispatch_client_callout(void *ctxt
, dispatch_function_t f
)
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
);
782 _dispatch_free_unwind_tsd();
783 _dispatch_set_unwind_tsd(u
);
786 #undef _dispatch_client_callout2
789 _dispatch_client_callout2(void *ctxt
, size_t i
, void (*f
)(void *, size_t))
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
);
796 _dispatch_free_unwind_tsd();
797 _dispatch_set_unwind_tsd(u
);
800 #undef _dispatch_client_callout3
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
)
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
);
815 #undef _dispatch_client_callout4
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
)
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
);
830 #endif // DISPATCH_USE_CLIENT_CALLOUT
833 #pragma mark _os_object_t no_objc
837 static const _os_object_class_s _os_object_class
;
840 _os_object_init(void)
846 _os_object_alloc_realized(const void *cls
, size_t size
)
849 dispatch_assert(size
>= sizeof(struct _os_object_s
));
850 while (!fastpath(obj
= calloc(1u, size
))) {
851 _dispatch_temporary_resource_shortage();
853 obj
->os_obj_isa
= cls
;
858 _os_object_alloc(const void *cls
, size_t size
)
860 if (!cls
) cls
= &_os_object_class
;
861 return _os_object_alloc_realized(cls
, size
);
865 _os_object_dealloc(_os_object_t obj
)
867 *((void *volatile*)&obj
->os_obj_isa
) = (void *)0x200;
872 _os_object_xref_dispose(_os_object_t obj
)
874 if (fastpath(obj
->os_obj_isa
->_os_obj_xref_dispose
)) {
875 return obj
->os_obj_isa
->_os_obj_xref_dispose(obj
);
877 return _os_object_release_internal(obj
);
881 _os_object_dispose(_os_object_t obj
)
883 if (fastpath(obj
->os_obj_isa
->_os_obj_dispose
)) {
884 return obj
->os_obj_isa
->_os_obj_dispose(obj
);
886 return _os_object_dealloc(obj
);
893 return _os_object_retain(obj
);
900 os_release(void *obj
)
903 return _os_object_release(obj
);
908 #pragma mark dispatch_autorelease_pool no_objc
910 #if DISPATCH_COCOA_COMPAT
912 void *_dispatch_autorelease_pool_push(void) {
914 if (_dispatch_begin_NSAutoReleasePool
) {
915 pool
= _dispatch_begin_NSAutoReleasePool();
920 void _dispatch_autorelease_pool_pop(void *pool
) {
921 if (_dispatch_end_NSAutoReleasePool
) {
922 _dispatch_end_NSAutoReleasePool(pool
);
926 #endif // DISPATCH_COCOA_COMPAT
930 #pragma mark dispatch_source_types
933 dispatch_source_type_timer_init(dispatch_source_t ds
,
934 dispatch_source_type_t type DISPATCH_UNUSED
,
935 uintptr_t handle DISPATCH_UNUSED
,
939 if (fastpath(!ds
->ds_refs
)) {
940 ds
->ds_refs
= _dispatch_calloc(1ul,
941 sizeof(struct dispatch_timer_source_refs_s
));
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>
950 ds_timer(ds
->ds_refs
).flags
= mask
;
953 const struct dispatch_source_type_s _dispatch_source_type_timer
= {
955 .filter
= DISPATCH_EVFILT_TIMER
,
957 .mask
= DISPATCH_TIMER_STRICT
|DISPATCH_TIMER_BACKGROUND
|
958 DISPATCH_TIMER_WALL_CLOCK
,
959 .init
= dispatch_source_type_timer_init
,
963 dispatch_source_type_timer_with_aggregate_init(dispatch_source_t ds
,
964 dispatch_source_type_t type
, uintptr_t handle
, unsigned long mask
,
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
);
975 const struct dispatch_source_type_s _dispatch_source_type_timer_with_aggregate
={
977 .filter
= DISPATCH_EVFILT_TIMER
,
980 .mask
= DISPATCH_TIMER_STRICT
|DISPATCH_TIMER_BACKGROUND
,
981 .init
= dispatch_source_type_timer_with_aggregate_init
,
985 dispatch_source_type_interval_init(dispatch_source_t ds
,
986 dispatch_source_type_t type
, uintptr_t handle
, unsigned long mask
,
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
);
996 const struct dispatch_source_type_s _dispatch_source_type_interval
= {
998 .filter
= DISPATCH_EVFILT_TIMER
,
1001 .mask
= DISPATCH_TIMER_STRICT
|DISPATCH_TIMER_BACKGROUND
|
1002 DISPATCH_INTERVAL_UI_ANIMATION
,
1003 .init
= dispatch_source_type_interval_init
,
1006 const struct dispatch_source_type_s _dispatch_source_type_read
= {
1008 .filter
= EVFILT_READ
,
1009 .flags
= EV_DISPATCH
,
1013 const struct dispatch_source_type_s _dispatch_source_type_write
= {
1015 .filter
= EVFILT_WRITE
,
1016 .flags
= EV_DISPATCH
,
1020 #if DISPATCH_USE_MEMORYSTATUS
1022 #if TARGET_IPHONE_SIMULATOR // rdar://problem/9219483
1023 static int _dispatch_ios_simulator_memory_warnings_fd
= -1;
1025 _dispatch_ios_simulator_memorypressure_init(void *context DISPATCH_UNUSED
)
1027 char *e
= getenv("SIMULATOR_MEMORY_WARNINGS");
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
);
1037 dispatch_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
)
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
;
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;
1056 ds
->ds_is_level
= false;
1059 #ifndef NOTE_MEMORYSTATUS_LOW_SWAP
1060 #define NOTE_MEMORYSTATUS_LOW_SWAP 0x8
1063 const struct dispatch_source_type_s _dispatch_source_type_memorystatus
= {
1065 .filter
= EVFILT_MEMORYSTATUS
,
1066 .flags
= EV_DISPATCH
,
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
,
1074 dispatch_source_type_vm_init(dispatch_source_t ds
,
1075 dispatch_source_type_t type
,
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
);
1088 const struct dispatch_source_type_s _dispatch_source_type_vm
= {
1090 .filter
= EVFILT_MEMORYSTATUS
,
1091 .flags
= EV_DISPATCH
,
1093 .mask
= NOTE_VM_PRESSURE
,
1094 .init
= dispatch_source_type_vm_init
,
1097 #elif DISPATCH_USE_VM_PRESSURE
1100 dispatch_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
)
1106 ds
->ds_is_level
= false;
1109 const struct dispatch_source_type_s _dispatch_source_type_vm
= {
1111 .filter
= EVFILT_VM
,
1112 .flags
= EV_DISPATCH
,
1114 .mask
= NOTE_VM_PRESSURE
,
1115 .init
= dispatch_source_type_vm_init
,
1118 #endif // DISPATCH_USE_VM_PRESSURE
1120 const struct dispatch_source_type_s _dispatch_source_type_proc
= {
1122 .filter
= EVFILT_PROC
,
1125 .mask
= NOTE_EXIT
|NOTE_FORK
|NOTE_EXEC
1126 #if HAVE_DECL_NOTE_SIGNAL
1129 #if HAVE_DECL_NOTE_REAP
1135 const struct dispatch_source_type_s _dispatch_source_type_signal
= {
1137 .filter
= EVFILT_SIGNAL
,
1141 const struct dispatch_source_type_s _dispatch_source_type_vnode
= {
1143 .filter
= EVFILT_VNODE
,
1146 .mask
= NOTE_DELETE
|NOTE_WRITE
|NOTE_EXTEND
|NOTE_ATTRIB
|NOTE_LINK
|
1147 NOTE_RENAME
|NOTE_REVOKE
1148 #if HAVE_DECL_NOTE_NONE
1154 const struct dispatch_source_type_s _dispatch_source_type_vfs
= {
1156 .filter
= EVFILT_FS
,
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
1164 #if HAVE_DECL_VQ_VERYLOWDISK
1170 const struct dispatch_source_type_s _dispatch_source_type_sock
= {
1173 .filter
= EVFILT_SOCK
,
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
1182 #ifdef NOTE_CONNECTED
1183 | NOTE_CONNECTED
| NOTE_DISCONNECTED
| NOTE_CONNINFO_UPDATED
1186 #endif // EVFILT_SOCK
1189 const struct dispatch_source_type_s _dispatch_source_type_data_add
= {
1191 .filter
= DISPATCH_EVFILT_CUSTOM_ADD
,
1195 const struct dispatch_source_type_s _dispatch_source_type_data_or
= {
1197 .filter
= DISPATCH_EVFILT_CUSTOM_OR
,
1206 dispatch_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
)
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
;
1218 const struct dispatch_source_type_s _dispatch_source_type_mach_send
= {
1220 .filter
= DISPATCH_EVFILT_MACH_NOTIFICATION
,
1223 .mask
= DISPATCH_MACH_SEND_DEAD
|DISPATCH_MACH_SEND_POSSIBLE
,
1224 .init
= dispatch_source_type_mach_send_init
,
1228 dispatch_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
)
1234 ds
->ds_is_level
= false;
1237 const struct dispatch_source_type_s _dispatch_source_type_mach_recv
= {
1239 .filter
= EVFILT_MACHPORT
,
1240 .flags
= EV_DISPATCH
,
1241 .fflags
= DISPATCH_MACH_RECV_MESSAGE
,
1243 .init
= dispatch_source_type_mach_recv_init
,
1247 #pragma mark dispatch_mig
1250 dispatch_mach_msg_get_context(mach_msg_header_t
*msg
)
1252 mach_msg_context_trailer_t
*tp
;
1253 void *context
= NULL
;
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
;
1265 _dispatch_wakeup_runloop_thread(mach_port_t mp DISPATCH_UNUSED
)
1267 // dummy function just to pop a runloop thread out of mach_msg()
1272 _dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED
)
1274 // dummy function to consume a send-once right
1279 _dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED
,
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
;
1292 _dispatch_mach_notify_no_senders(mach_port_t notify
,
1293 mach_port_mscount_t mscnt DISPATCH_UNUSED
)
1295 // this function should never be called
1296 (void)dispatch_assume_zero(notify
);
1297 return KERN_SUCCESS
;
1301 _dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED
)
1303 // we only register for dead-name notifications
1304 // some code deallocated our send-once right without consuming it
1306 _dispatch_log("Corruption: An app/library deleted a libdispatch "
1307 "dead-name notification");
1309 return KERN_SUCCESS
;