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_atm_t _voucher_task_atm
;
86 _voucher_activity_t _voucher_activity_default
;
88 voucher_activity_mode_t _voucher_activity_mode
;
89 int _dispatch_set_qos_class_enabled
;
93 voucher_activity_mode_t
94 voucher_activity_get_mode(void)
96 return _voucher_activity_mode
;
100 voucher_activity_set_mode_4libtrace(voucher_activity_mode_t mode
)
102 if (_voucher_activity_disabled()) return;
103 _voucher_activity_mode
= mode
;
106 DISPATCH_HW_CONFIG();
107 bool _dispatch_safe_fork
= true, _dispatch_child_of_unsafe_fork
;
111 _dispatch_is_multithreaded(void)
113 return !_dispatch_safe_fork
;
118 _dispatch_is_fork_of_multithreaded_parent(void)
120 return _dispatch_child_of_unsafe_fork
;
123 const struct dispatch_queue_offsets_s dispatch_queue_offsets
= {
125 .dqo_label
= offsetof(struct dispatch_queue_s
, dq_label
),
126 .dqo_label_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_label
),
129 .dqo_serialnum
= offsetof(struct dispatch_queue_s
, dq_serialnum
),
130 .dqo_serialnum_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_serialnum
),
131 .dqo_width
= offsetof(struct dispatch_queue_s
, dq_width
),
132 .dqo_width_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_width
),
133 .dqo_running
= offsetof(struct dispatch_queue_s
, dq_running
),
134 .dqo_running_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_running
),
135 .dqo_suspend_cnt
= offsetof(struct dispatch_queue_s
, do_suspend_cnt
),
136 .dqo_suspend_cnt_size
= sizeof(((dispatch_queue_t
)NULL
)->do_suspend_cnt
),
137 .dqo_target_queue
= offsetof(struct dispatch_queue_s
, do_targetq
),
138 .dqo_target_queue_size
= sizeof(((dispatch_queue_t
)NULL
)->do_targetq
),
139 .dqo_priority
= offsetof(struct dispatch_queue_s
, dq_priority
),
140 .dqo_priority_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_priority
),
143 #if VOUCHER_USE_MACH_VOUCHER
144 const struct voucher_offsets_s voucher_offsets
= {
146 .vo_activity_ids_count
= offsetof(struct voucher_s
, v_activities
),
147 .vo_activity_ids_count_size
= sizeof(((voucher_t
)NULL
)->v_activities
),
148 .vo_activity_ids_array
= (uint16_t)_voucher_activity_ids((voucher_t
)(NULL
)),
149 .vo_activity_ids_array_entry_size
= sizeof(voucher_activity_id_t
),
151 #else // VOUCHER_USE_MACH_VOUCHER
152 const struct voucher_offsets_s voucher_offsets
= {
155 #endif // VOUCHER_USE_MACH_VOUCHER
157 #if DISPATCH_USE_DIRECT_TSD
158 const struct dispatch_tsd_indexes_s dispatch_tsd_indexes
= {
160 .dti_queue_index
= dispatch_queue_key
,
161 .dti_voucher_index
= dispatch_voucher_key
,
162 .dti_qos_class_index
= dispatch_priority_key
,
164 #else // DISPATCH_USE_DIRECT_TSD
165 #error Not implemented on this platform
166 #endif // DISPATCH_USE_DIRECT_TSD
168 // 6618342 Contact the team that owns the Instrument DTrace probe before
169 // renaming this symbol
170 DISPATCH_CACHELINE_ALIGN
171 struct dispatch_queue_s _dispatch_main_q
= {
172 .do_vtable
= DISPATCH_VTABLE(queue
),
173 #if !DISPATCH_USE_RESOLVERS
174 .do_targetq
= &_dispatch_root_queues
[
175 DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT
],
177 .do_ref_cnt
= DISPATCH_OBJECT_GLOBAL_REFCNT
,
178 .do_xref_cnt
= DISPATCH_OBJECT_GLOBAL_REFCNT
,
179 .do_suspend_cnt
= DISPATCH_OBJECT_SUSPEND_LOCK
,
180 .dq_label
= "com.apple.main-thread",
183 .dq_is_thread_bound
= 1,
184 .dq_override_voucher
= DISPATCH_NO_VOUCHER
,
189 #pragma mark dispatch_queue_attr_t
191 #define DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, overcommit, concurrent) \
193 .do_vtable = DISPATCH_VTABLE(queue_attr), \
194 .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, \
195 .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, \
196 .do_next = DISPATCH_OBJECT_LISTLESS, \
197 .dqa_qos_class = (qos), \
198 .dqa_relative_priority = (qos) ? (prio) : 0, \
199 .dqa_overcommit = _dispatch_queue_attr_overcommit_##overcommit, \
200 .dqa_concurrent = (concurrent), \
203 #define DISPATCH_QUEUE_ATTR_KIND_INIT(qos, prio) \
205 [DQA_INDEX_NON_OVERCOMMIT][DQA_INDEX_CONCURRENT] = \
206 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, disabled, 1), \
207 [DQA_INDEX_NON_OVERCOMMIT][DQA_INDEX_SERIAL] = \
208 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, disabled, 0), \
209 [DQA_INDEX_OVERCOMMIT][DQA_INDEX_CONCURRENT] = \
210 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, enabled, 1), \
211 [DQA_INDEX_OVERCOMMIT][DQA_INDEX_SERIAL] = \
212 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, enabled, 0), \
213 [DQA_INDEX_UNSPECIFIED_OVERCOMMIT][DQA_INDEX_CONCURRENT] = \
214 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, unspecified, 1),\
215 [DQA_INDEX_UNSPECIFIED_OVERCOMMIT][DQA_INDEX_SERIAL] = \
216 DISPATCH_QUEUE_ATTR_INITIALIZER(qos, prio, unspecified, 0),\
219 #define DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, prio) \
220 [prio] = DISPATCH_QUEUE_ATTR_KIND_INIT(qos, -(prio))
222 #define DISPATCH_QUEUE_ATTR_PRIO_INIT(qos) \
224 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 0), \
225 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 1), \
226 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 2), \
227 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 3), \
228 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 4), \
229 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 5), \
230 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 6), \
231 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 7), \
232 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 8), \
233 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 9), \
234 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 10), \
235 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 11), \
236 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 12), \
237 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 13), \
238 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 14), \
239 DISPATCH_QUEUE_ATTR_PRIO_INITIALIZER(qos, 15), \
242 #define DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(qos) \
243 [DQA_INDEX_QOS_CLASS_##qos] = \
244 DISPATCH_QUEUE_ATTR_PRIO_INIT(_DISPATCH_QOS_CLASS_##qos)
246 // DISPATCH_QUEUE_CONCURRENT resp. _dispatch_queue_attr_concurrent is aliased
247 // to array member [0][0][0][0] and their properties must match!
248 const struct dispatch_queue_attr_s _dispatch_queue_attrs
[]
249 [DISPATCH_QUEUE_ATTR_PRIO_COUNT
]
250 [DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT
]
251 [DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT
] = {
252 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(UNSPECIFIED
),
253 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(MAINTENANCE
),
254 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(BACKGROUND
),
255 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(UTILITY
),
256 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(DEFAULT
),
257 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(USER_INITIATED
),
258 DISPATCH_QUEUE_ATTR_QOS_INITIALIZER(USER_INTERACTIVE
),
263 #pragma mark dispatch_vtables
265 DISPATCH_VTABLE_INSTANCE(semaphore
,
266 .do_type
= DISPATCH_SEMAPHORE_TYPE
,
267 .do_kind
= "semaphore",
268 .do_dispose
= _dispatch_semaphore_dispose
,
269 .do_debug
= _dispatch_semaphore_debug
,
272 DISPATCH_VTABLE_INSTANCE(group
,
273 .do_type
= DISPATCH_GROUP_TYPE
,
275 .do_dispose
= _dispatch_semaphore_dispose
,
276 .do_debug
= _dispatch_semaphore_debug
,
279 DISPATCH_VTABLE_INSTANCE(queue
,
280 .do_type
= DISPATCH_QUEUE_TYPE
,
282 .do_dispose
= _dispatch_queue_dispose
,
283 .do_invoke
= _dispatch_queue_invoke
,
284 .do_probe
= _dispatch_queue_probe
,
285 .do_debug
= dispatch_queue_debug
,
288 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_root
, queue
,
289 .do_type
= DISPATCH_QUEUE_ROOT_TYPE
,
290 .do_kind
= "global-queue",
291 .do_dispose
= _dispatch_pthread_root_queue_dispose
,
292 .do_probe
= _dispatch_root_queue_probe
,
293 .do_debug
= dispatch_queue_debug
,
296 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_runloop
, queue
,
297 .do_type
= DISPATCH_QUEUE_ROOT_TYPE
,
298 .do_kind
= "runloop-queue",
299 .do_dispose
= _dispatch_runloop_queue_dispose
,
300 .do_invoke
= _dispatch_queue_invoke
,
301 .do_probe
= _dispatch_runloop_queue_probe
,
302 .do_debug
= dispatch_queue_debug
,
305 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_mgr
, queue
,
306 .do_type
= DISPATCH_QUEUE_MGR_TYPE
,
307 .do_kind
= "mgr-queue",
308 .do_invoke
= _dispatch_mgr_thread
,
309 .do_probe
= _dispatch_mgr_queue_probe
,
310 .do_debug
= dispatch_queue_debug
,
313 DISPATCH_VTABLE_INSTANCE(queue_specific_queue
,
314 .do_type
= DISPATCH_QUEUE_SPECIFIC_TYPE
,
315 .do_kind
= "queue-context",
316 .do_dispose
= _dispatch_queue_specific_queue_dispose
,
317 .do_invoke
= (void*)_dispatch_queue_invoke
,
318 .do_probe
= (void *)_dispatch_queue_probe
,
319 .do_debug
= (void *)dispatch_queue_debug
,
322 DISPATCH_VTABLE_INSTANCE(queue_attr
,
323 .do_type
= DISPATCH_QUEUE_ATTR_TYPE
,
324 .do_kind
= "queue-attr",
327 DISPATCH_VTABLE_INSTANCE(source
,
328 .do_type
= DISPATCH_SOURCE_KEVENT_TYPE
,
329 .do_kind
= "kevent-source",
330 .do_dispose
= _dispatch_source_dispose
,
331 .do_invoke
= _dispatch_source_invoke
,
332 .do_probe
= _dispatch_source_probe
,
333 .do_debug
= _dispatch_source_debug
,
336 DISPATCH_VTABLE_INSTANCE(mach
,
337 .do_type
= DISPATCH_MACH_CHANNEL_TYPE
,
338 .do_kind
= "mach-channel",
339 .do_dispose
= _dispatch_mach_dispose
,
340 .do_invoke
= _dispatch_mach_invoke
,
341 .do_probe
= _dispatch_mach_probe
,
342 .do_debug
= _dispatch_mach_debug
,
345 DISPATCH_VTABLE_INSTANCE(mach_msg
,
346 .do_type
= DISPATCH_MACH_MSG_TYPE
,
347 .do_kind
= "mach-msg",
348 .do_dispose
= _dispatch_mach_msg_dispose
,
349 .do_invoke
= _dispatch_mach_msg_invoke
,
350 .do_debug
= _dispatch_mach_msg_debug
,
354 DISPATCH_VTABLE_INSTANCE(data
,
355 .do_type
= DISPATCH_DATA_TYPE
,
357 .do_dispose
= _dispatch_data_dispose
,
358 .do_debug
= _dispatch_data_debug
,
362 DISPATCH_VTABLE_INSTANCE(io
,
363 .do_type
= DISPATCH_IO_TYPE
,
364 .do_kind
= "channel",
365 .do_dispose
= _dispatch_io_dispose
,
366 .do_debug
= _dispatch_io_debug
,
369 DISPATCH_VTABLE_INSTANCE(operation
,
370 .do_type
= DISPATCH_OPERATION_TYPE
,
371 .do_kind
= "operation",
372 .do_dispose
= _dispatch_operation_dispose
,
373 .do_debug
= _dispatch_operation_debug
,
376 DISPATCH_VTABLE_INSTANCE(disk
,
377 .do_type
= DISPATCH_DISK_TYPE
,
379 .do_dispose
= _dispatch_disk_dispose
,
383 _dispatch_vtable_init(void)
386 // ObjC classes and dispatch vtables are co-located via linker order and
387 // alias files, verify correct layout during initialization rdar://10640168
388 DISPATCH_OBJC_CLASS_DECL(semaphore
);
389 dispatch_assert((char*)DISPATCH_VTABLE(semaphore
) -
390 (char*)DISPATCH_OBJC_CLASS(semaphore
) == 0);
391 dispatch_assert((char*)&DISPATCH_CONCAT(_
,DISPATCH_CLASS(semaphore_vtable
))
392 - (char*)DISPATCH_OBJC_CLASS(semaphore
) ==
393 sizeof(_os_object_class_s
));
398 #pragma mark dispatch_bug
400 static char _dispatch_build
[16];
403 _dispatch_build_init(void *context DISPATCH_UNUSED
)
406 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
407 size_t bufsz
= sizeof(_dispatch_build
);
409 sysctl(mib
, 2, _dispatch_build
, &bufsz
, NULL
, 0);
412 * XXXRW: What to do here for !Mac OS X?
414 memset(_dispatch_build
, 0, sizeof(_dispatch_build
));
418 static dispatch_once_t _dispatch_build_pred
;
421 _dispatch_get_build(void)
423 dispatch_once_f(&_dispatch_build_pred
, NULL
, _dispatch_build_init
);
424 return _dispatch_build
;
427 #define _dispatch_bug_log(msg, ...) do { \
428 static void *last_seen; \
429 void *ra = __builtin_return_address(0); \
430 if (last_seen != ra) { \
432 _dispatch_log(msg, ##__VA_ARGS__); \
437 _dispatch_bug(size_t line
, long val
)
439 dispatch_once_f(&_dispatch_build_pred
, NULL
, _dispatch_build_init
);
440 _dispatch_bug_log("BUG in libdispatch: %s - %lu - 0x%lx",
441 _dispatch_build
, (unsigned long)line
, val
);
445 _dispatch_bug_client(const char* msg
)
447 _dispatch_bug_log("BUG in libdispatch client: %s", msg
);
451 _dispatch_bug_mach_client(const char* msg
, mach_msg_return_t kr
)
453 _dispatch_bug_log("BUG in libdispatch client: %s %s - 0x%x", msg
,
454 mach_error_string(kr
), kr
);
458 _dispatch_bug_kevent_client(const char* msg
, const char* filter
,
459 const char *operation
, int err
)
461 _dispatch_bug_log("BUG in libdispatch client: %s[%s] %s: \"%s\" - 0x%x",
462 msg
, filter
, operation
, strerror(err
), err
);
466 _dispatch_abort(size_t line
, long val
)
468 _dispatch_bug(line
, val
);
472 #if !DISPATCH_USE_OS_DEBUG_LOG
475 #pragma mark dispatch_log
477 static int dispatch_logfile
= -1;
478 static bool dispatch_log_disabled
;
480 static uint64_t dispatch_log_basetime
;
482 static dispatch_once_t _dispatch_logv_pred
;
485 _dispatch_logv_init(void *context DISPATCH_UNUSED
)
488 bool log_to_file
= true;
490 bool log_to_file
= false;
492 char *e
= getenv("LIBDISPATCH_LOG");
494 if (strcmp(e
, "YES") == 0) {
496 } else if (strcmp(e
, "NO") == 0) {
497 dispatch_log_disabled
= true;
498 } else if (strcmp(e
, "syslog") == 0) {
500 } else if (strcmp(e
, "file") == 0) {
502 } else if (strcmp(e
, "stderr") == 0) {
504 dispatch_logfile
= STDERR_FILENO
;
507 if (!dispatch_log_disabled
) {
508 if (log_to_file
&& dispatch_logfile
== -1) {
510 snprintf(path
, sizeof(path
), "/var/tmp/libdispatch.%d.log",
512 dispatch_logfile
= open(path
, O_WRONLY
| O_APPEND
| O_CREAT
|
513 O_NOFOLLOW
| O_CLOEXEC
, 0666);
515 if (dispatch_logfile
!= -1) {
517 gettimeofday(&tv
, NULL
);
519 dispatch_log_basetime
= mach_absolute_time();
521 dprintf(dispatch_logfile
, "=== log file opened for %s[%u] at "
522 "%ld.%06u ===\n", getprogname() ?: "", getpid(),
523 tv
.tv_sec
, tv
.tv_usec
);
529 _dispatch_log_file(char *buf
, size_t len
)
535 r
= write(dispatch_logfile
, buf
, len
);
536 if (slowpath(r
== -1) && errno
== EINTR
) {
543 _dispatch_logv_file(const char *msg
, va_list ap
)
546 size_t bufsiz
= sizeof(buf
), offset
= 0;
550 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
, "%llu\t",
551 mach_absolute_time() - dispatch_log_basetime
);
553 r
= vsnprintf(&buf
[offset
], bufsiz
- offset
, msg
, ap
);
556 if (offset
> bufsiz
- 1) {
559 _dispatch_log_file(buf
, offset
);
562 #if DISPATCH_USE_SIMPLE_ASL
564 _dispatch_syslog(const char *msg
)
566 _simple_asl_log(ASL_LEVEL_NOTICE
, "com.apple.libsystem.libdispatch", msg
);
570 _dispatch_vsyslog(const char *msg
, va_list ap
)
573 vasprintf(&str
, msg
, ap
);
575 _dispatch_syslog(str
);
579 #else // DISPATCH_USE_SIMPLE_ASL
581 _dispatch_syslog(const char *msg
)
583 syslog(LOG_NOTICE
, "%s", msg
);
587 _dispatch_vsyslog(const char *msg
, va_list ap
)
589 vsyslog(LOG_NOTICE
, msg
, *ap_ptr
);
591 #endif // DISPATCH_USE_SIMPLE_ASL
593 DISPATCH_ALWAYS_INLINE
595 _dispatch_logv(const char *msg
, size_t len
, va_list *ap_ptr
)
597 dispatch_once_f(&_dispatch_logv_pred
, NULL
, _dispatch_logv_init
);
598 if (slowpath(dispatch_log_disabled
)) {
601 if (slowpath(dispatch_logfile
!= -1)) {
603 return _dispatch_log_file((char*)msg
, len
);
605 return _dispatch_logv_file(msg
, *ap_ptr
);
608 return _dispatch_syslog(msg
);
610 return _dispatch_vsyslog(msg
, *ap_ptr
);
615 _dispatch_log(const char *msg
, ...)
620 _dispatch_logv(msg
, 0, &ap
);
624 #endif // DISPATCH_USE_OS_DEBUG_LOG
627 #pragma mark dispatch_debug
630 _dispatch_object_debug2(dispatch_object_t dou
, char* buf
, size_t bufsiz
)
632 DISPATCH_OBJECT_TFB(_dispatch_objc_debug
, dou
, buf
, bufsiz
);
633 if (dou
._do
->do_vtable
->do_debug
) {
634 return dx_debug(dou
._do
, buf
, bufsiz
);
636 return strlcpy(buf
, "NULL vtable slot: ", bufsiz
);
641 _dispatch_debugv(dispatch_object_t dou
, const char *msg
, va_list ap
)
644 size_t bufsiz
= sizeof(buf
), offset
= 0;
646 #if DISPATCH_DEBUG && !DISPATCH_USE_OS_DEBUG_LOG
647 offset
+= dsnprintf(&buf
[offset
], bufsiz
- offset
, "%llu\t\t%p\t",
648 mach_absolute_time() - dispatch_log_basetime
,
649 (void *)_dispatch_thread_self());
652 offset
+= _dispatch_object_debug2(dou
, &buf
[offset
], bufsiz
- offset
);
653 dispatch_assert(offset
+ 2 < bufsiz
);
658 offset
+= strlcpy(&buf
[offset
], "NULL: ", bufsiz
- offset
);
660 r
= vsnprintf(&buf
[offset
], bufsiz
- offset
, msg
, ap
);
661 #if !DISPATCH_USE_OS_DEBUG_LOG
662 size_t len
= offset
+ (r
< 0 ? 0 : (size_t)r
);
663 if (len
> bufsiz
- 1) {
666 _dispatch_logv(buf
, len
, NULL
);
668 _dispatch_log("%s", buf
);
674 dispatch_debugv(dispatch_object_t dou
, const char *msg
, va_list ap
)
676 _dispatch_debugv(dou
, msg
, ap
);
681 dispatch_debug(dispatch_object_t dou
, const char *msg
, ...)
686 _dispatch_debugv(dou
, msg
, ap
);
693 _dispatch_object_debug(dispatch_object_t dou
, const char *msg
, ...)
698 _dispatch_debugv(dou
._do
, msg
, ap
);
704 #pragma mark dispatch_calloc
708 _dispatch_temporary_resource_shortage(void)
714 _dispatch_calloc(size_t num_items
, size_t size
)
717 while (!fastpath(buf
= calloc(num_items
, size
))) {
718 _dispatch_temporary_resource_shortage();
724 #pragma mark dispatch_block_t
728 #undef _dispatch_Block_copy
730 _dispatch_Block_copy(dispatch_block_t db
)
732 dispatch_block_t rval
;
735 while (!fastpath(rval
= Block_copy(db
))) {
736 _dispatch_temporary_resource_shortage();
740 DISPATCH_CLIENT_CRASH("NULL was passed where a block should have been");
744 _dispatch_call_block_and_release(void *block
)
746 void (^b
)(void) = block
;
754 #pragma mark dispatch_client_callout
756 // Abort on uncaught exceptions thrown from client callouts rdar://8577499
757 #if DISPATCH_USE_CLIENT_CALLOUT && (__USING_SJLJ_EXCEPTIONS__ || !USE_OBJC)
758 // On platforms with SjLj exceptions, avoid the SjLj overhead on every callout
759 // by clearing the unwinder's TSD pointer to the handler stack around callouts
761 #define _dispatch_get_tsd_base()
762 #define _dispatch_get_unwind_tsd() (NULL)
763 #define _dispatch_set_unwind_tsd(u) do {(void)(u);} while (0)
764 #define _dispatch_free_unwind_tsd()
766 #undef _dispatch_client_callout
769 _dispatch_client_callout(void *ctxt
, dispatch_function_t f
)
771 _dispatch_get_tsd_base();
772 void *u
= _dispatch_get_unwind_tsd();
773 if (fastpath(!u
)) return f(ctxt
);
774 _dispatch_set_unwind_tsd(NULL
);
776 _dispatch_free_unwind_tsd();
777 _dispatch_set_unwind_tsd(u
);
780 #undef _dispatch_client_callout2
783 _dispatch_client_callout2(void *ctxt
, size_t i
, void (*f
)(void *, size_t))
785 _dispatch_get_tsd_base();
786 void *u
= _dispatch_get_unwind_tsd();
787 if (fastpath(!u
)) return f(ctxt
, i
);
788 _dispatch_set_unwind_tsd(NULL
);
790 _dispatch_free_unwind_tsd();
791 _dispatch_set_unwind_tsd(u
);
794 #undef _dispatch_client_callout4
796 _dispatch_client_callout4(void *ctxt
, dispatch_mach_reason_t reason
,
797 dispatch_mach_msg_t dmsg
, mach_error_t error
,
798 dispatch_mach_handler_function_t f
)
800 _dispatch_get_tsd_base();
801 void *u
= _dispatch_get_unwind_tsd();
802 if (fastpath(!u
)) return f(ctxt
, reason
, dmsg
, error
);
803 _dispatch_set_unwind_tsd(NULL
);
804 f(ctxt
, reason
, dmsg
, error
);
805 _dispatch_free_unwind_tsd();
806 _dispatch_set_unwind_tsd(u
);
809 #endif // DISPATCH_USE_CLIENT_CALLOUT
812 #pragma mark _os_object_t no_objc
816 static const _os_object_class_s _os_object_class
;
819 _os_object_init(void)
825 _os_object_alloc_realized(const void *cls
, size_t size
)
828 dispatch_assert(size
>= sizeof(struct _os_object_s
));
829 while (!fastpath(obj
= calloc(1u, size
))) {
830 _dispatch_temporary_resource_shortage();
832 obj
->os_obj_isa
= cls
;
837 _os_object_alloc(const void *cls
, size_t size
)
839 if (!cls
) cls
= &_os_object_class
;
840 return _os_object_alloc_realized(cls
, size
);
844 _os_object_dealloc(_os_object_t obj
)
846 *((void *volatile*)&obj
->os_obj_isa
) = (void *)0x200;
851 _os_object_xref_dispose(_os_object_t obj
)
853 _os_object_xrefcnt_dispose_barrier(obj
);
854 if (fastpath(obj
->os_obj_isa
->_os_obj_xref_dispose
)) {
855 return obj
->os_obj_isa
->_os_obj_xref_dispose(obj
);
857 return _os_object_release_internal(obj
);
861 _os_object_dispose(_os_object_t obj
)
863 _os_object_refcnt_dispose_barrier(obj
);
864 if (fastpath(obj
->os_obj_isa
->_os_obj_dispose
)) {
865 return obj
->os_obj_isa
->_os_obj_dispose(obj
);
867 return _os_object_dealloc(obj
);
874 return _os_object_retain(obj
);
881 os_release(void *obj
)
884 return _os_object_release(obj
);
889 #pragma mark dispatch_autorelease_pool no_objc
891 #if DISPATCH_COCOA_COMPAT
893 void *_dispatch_autorelease_pool_push(void) {
895 if (_dispatch_begin_NSAutoReleasePool
) {
896 pool
= _dispatch_begin_NSAutoReleasePool();
901 void _dispatch_autorelease_pool_pop(void *pool
) {
902 if (_dispatch_end_NSAutoReleasePool
) {
903 _dispatch_end_NSAutoReleasePool(pool
);
907 #endif // DISPATCH_COCOA_COMPAT
911 #pragma mark dispatch_source_types
914 dispatch_source_type_timer_init(dispatch_source_t ds
,
915 dispatch_source_type_t type DISPATCH_UNUSED
,
916 uintptr_t handle DISPATCH_UNUSED
,
920 if (fastpath(!ds
->ds_refs
)) {
921 ds
->ds_refs
= _dispatch_calloc(1ul,
922 sizeof(struct dispatch_timer_source_refs_s
));
924 ds
->ds_needs_rearm
= true;
925 ds
->ds_is_timer
= true;
926 if (q
== dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND
, 0)
927 || q
== dispatch_get_global_queue(
928 DISPATCH_QUEUE_PRIORITY_BACKGROUND
, DISPATCH_QUEUE_OVERCOMMIT
)){
929 mask
|= DISPATCH_TIMER_BACKGROUND
; // <rdar://problem/12200216>
931 ds_timer(ds
->ds_refs
).flags
= mask
;
934 const struct dispatch_source_type_s _dispatch_source_type_timer
= {
936 .filter
= DISPATCH_EVFILT_TIMER
,
938 .mask
= DISPATCH_TIMER_STRICT
|DISPATCH_TIMER_BACKGROUND
|
939 DISPATCH_TIMER_WALL_CLOCK
,
940 .init
= dispatch_source_type_timer_init
,
944 dispatch_source_type_timer_with_aggregate_init(dispatch_source_t ds
,
945 dispatch_source_type_t type
, uintptr_t handle
, unsigned long mask
,
948 ds
->ds_refs
= _dispatch_calloc(1ul,
949 sizeof(struct dispatch_timer_source_aggregate_refs_s
));
950 dispatch_source_type_timer_init(ds
, type
, handle
, mask
, q
);
951 ds_timer(ds
->ds_refs
).flags
|= DISPATCH_TIMER_WITH_AGGREGATE
;
952 ds
->dq_specific_q
= (void*)handle
;
953 _dispatch_retain(ds
->dq_specific_q
);
956 const struct dispatch_source_type_s _dispatch_source_type_timer_with_aggregate
={
958 .filter
= DISPATCH_EVFILT_TIMER
,
961 .mask
= DISPATCH_TIMER_STRICT
|DISPATCH_TIMER_BACKGROUND
,
962 .init
= dispatch_source_type_timer_with_aggregate_init
,
966 dispatch_source_type_interval_init(dispatch_source_t ds
,
967 dispatch_source_type_t type
, uintptr_t handle
, unsigned long mask
,
970 dispatch_source_type_timer_init(ds
, type
, handle
, mask
, q
);
971 ds_timer(ds
->ds_refs
).flags
|= DISPATCH_TIMER_INTERVAL
;
972 unsigned long ident
= _dispatch_source_timer_idx(ds
->ds_refs
);
973 ds
->ds_dkev
->dk_kevent
.ident
= ds
->ds_ident_hack
= ident
;
974 _dispatch_source_set_interval(ds
, handle
);
977 const struct dispatch_source_type_s _dispatch_source_type_interval
= {
979 .filter
= DISPATCH_EVFILT_TIMER
,
982 .mask
= DISPATCH_TIMER_STRICT
|DISPATCH_TIMER_BACKGROUND
|
983 DISPATCH_INTERVAL_UI_ANIMATION
,
984 .init
= dispatch_source_type_interval_init
,
987 #if !DISPATCH_USE_SELECT_FALLBACK || DISPATCH_DYNAMIC_SELECT_FALLBACK
989 dispatch_source_type_readwrite_init(dispatch_source_t ds
,
990 dispatch_source_type_t type DISPATCH_UNUSED
,
991 uintptr_t handle DISPATCH_UNUSED
,
992 unsigned long mask DISPATCH_UNUSED
,
993 dispatch_queue_t q DISPATCH_UNUSED
)
995 ds
->ds_dkev
->dk_kevent
.flags
|= EV_UDATA_SPECIFIC
;
996 ds
->ds_is_direct_kevent
= true;
997 // bypass kernel check for device kqueue support rdar://19004921
998 ds
->ds_dkev
->dk_kevent
.fflags
= NOTE_LOWAT
;
999 ds
->ds_dkev
->dk_kevent
.data
= 1;
1002 #define dispatch_source_type_readwrite_init NULL
1005 const struct dispatch_source_type_s _dispatch_source_type_read
= {
1007 .filter
= EVFILT_READ
,
1008 .flags
= EV_DISPATCH
,
1010 .init
= dispatch_source_type_readwrite_init
,
1013 const struct dispatch_source_type_s _dispatch_source_type_write
= {
1015 .filter
= EVFILT_WRITE
,
1016 .flags
= EV_DISPATCH
,
1018 .init
= dispatch_source_type_readwrite_init
,
1021 #if DISPATCH_USE_MEMORYSTATUS
1023 #if TARGET_IPHONE_SIMULATOR // rdar://problem/9219483
1024 static int _dispatch_ios_simulator_memory_warnings_fd
= -1;
1026 _dispatch_ios_simulator_memorypressure_init(void *context DISPATCH_UNUSED
)
1028 char *e
= getenv("SIMULATOR_MEMORY_WARNINGS");
1030 _dispatch_ios_simulator_memory_warnings_fd
= open(e
, O_EVTONLY
);
1031 if (_dispatch_ios_simulator_memory_warnings_fd
== -1) {
1032 (void)dispatch_assume_zero(errno
);
1038 dispatch_source_type_memorystatus_init(dispatch_source_t ds
,
1039 dispatch_source_type_t type DISPATCH_UNUSED
,
1040 uintptr_t handle DISPATCH_UNUSED
,
1041 unsigned long mask DISPATCH_UNUSED
,
1042 dispatch_queue_t q DISPATCH_UNUSED
)
1044 #if TARGET_IPHONE_SIMULATOR
1045 static dispatch_once_t pred
;
1046 dispatch_once_f(&pred
, NULL
, _dispatch_ios_simulator_memorypressure_init
);
1047 handle
= (uintptr_t)_dispatch_ios_simulator_memory_warnings_fd
;
1049 ds
->ds_dkev
->dk_kevent
.filter
= EVFILT_VNODE
;
1050 ds
->ds_dkev
->dk_kevent
.ident
= handle
;
1051 ds
->ds_dkev
->dk_kevent
.flags
|= EV_CLEAR
;
1052 ds
->ds_dkev
->dk_kevent
.fflags
= (uint32_t)mask
;
1053 ds
->ds_ident_hack
= handle
;
1054 ds
->ds_pending_data_mask
= mask
;
1055 ds
->ds_memorystatus_override
= 1;
1057 ds
->ds_is_level
= false;
1060 #ifndef NOTE_MEMORYSTATUS_LOW_SWAP
1061 #define NOTE_MEMORYSTATUS_LOW_SWAP 0x8
1064 const struct dispatch_source_type_s _dispatch_source_type_memorystatus
= {
1066 .filter
= EVFILT_MEMORYSTATUS
,
1067 .flags
= EV_DISPATCH
|EV_UDATA_SPECIFIC
,
1069 .mask
= NOTE_MEMORYSTATUS_PRESSURE_NORMAL
|NOTE_MEMORYSTATUS_PRESSURE_WARN
1070 |NOTE_MEMORYSTATUS_PRESSURE_CRITICAL
|NOTE_MEMORYSTATUS_LOW_SWAP
,
1071 .init
= dispatch_source_type_memorystatus_init
,
1075 dispatch_source_type_vm_init(dispatch_source_t ds
,
1076 dispatch_source_type_t type
,
1081 // Map legacy vm pressure to memorystatus warning rdar://problem/15907505
1082 mask
= NOTE_MEMORYSTATUS_PRESSURE_WARN
;
1083 ds
->ds_dkev
->dk_kevent
.fflags
= (uint32_t)mask
;
1084 ds
->ds_pending_data_mask
= mask
;
1085 ds
->ds_vmpressure_override
= 1;
1086 dispatch_source_type_memorystatus_init(ds
, type
, handle
, mask
, q
);
1089 const struct dispatch_source_type_s _dispatch_source_type_vm
= {
1091 .filter
= EVFILT_MEMORYSTATUS
,
1092 .flags
= EV_DISPATCH
|EV_UDATA_SPECIFIC
,
1094 .mask
= NOTE_VM_PRESSURE
,
1095 .init
= dispatch_source_type_vm_init
,
1098 #elif DISPATCH_USE_VM_PRESSURE
1101 dispatch_source_type_vm_init(dispatch_source_t ds
,
1102 dispatch_source_type_t type DISPATCH_UNUSED
,
1103 uintptr_t handle DISPATCH_UNUSED
,
1104 unsigned long mask DISPATCH_UNUSED
,
1105 dispatch_queue_t q DISPATCH_UNUSED
)
1107 ds
->ds_is_level
= false;
1110 const struct dispatch_source_type_s _dispatch_source_type_vm
= {
1112 .filter
= EVFILT_VM
,
1113 .flags
= EV_DISPATCH
|EV_UDATA_SPECIFIC
,
1115 .mask
= NOTE_VM_PRESSURE
,
1116 .init
= dispatch_source_type_vm_init
,
1119 #endif // DISPATCH_USE_VM_PRESSURE
1122 dispatch_source_type_proc_init(dispatch_source_t ds
,
1123 dispatch_source_type_t type DISPATCH_UNUSED
,
1124 uintptr_t handle DISPATCH_UNUSED
,
1125 unsigned long mask DISPATCH_UNUSED
,
1126 dispatch_queue_t q DISPATCH_UNUSED
)
1128 ds
->ds_dkev
->dk_kevent
.fflags
|= NOTE_EXIT
; // rdar://16655831
1131 const struct dispatch_source_type_s _dispatch_source_type_proc
= {
1133 .filter
= EVFILT_PROC
,
1134 .flags
= EV_CLEAR
|EV_UDATA_SPECIFIC
,
1136 .mask
= NOTE_EXIT
|NOTE_FORK
|NOTE_EXEC
1137 #if HAVE_DECL_NOTE_SIGNAL
1140 #if HAVE_DECL_NOTE_REAP
1144 .init
= dispatch_source_type_proc_init
,
1147 const struct dispatch_source_type_s _dispatch_source_type_signal
= {
1149 .filter
= EVFILT_SIGNAL
,
1150 .flags
= EV_UDATA_SPECIFIC
,
1154 const struct dispatch_source_type_s _dispatch_source_type_vnode
= {
1156 .filter
= EVFILT_VNODE
,
1157 .flags
= EV_CLEAR
|EV_UDATA_SPECIFIC
,
1159 .mask
= NOTE_DELETE
|NOTE_WRITE
|NOTE_EXTEND
|NOTE_ATTRIB
|NOTE_LINK
|
1160 NOTE_RENAME
|NOTE_REVOKE
1161 #if HAVE_DECL_NOTE_NONE
1167 const struct dispatch_source_type_s _dispatch_source_type_vfs
= {
1169 .filter
= EVFILT_FS
,
1170 .flags
= EV_CLEAR
|EV_UDATA_SPECIFIC
,
1172 .mask
= VQ_NOTRESP
|VQ_NEEDAUTH
|VQ_LOWDISK
|VQ_MOUNT
|VQ_UNMOUNT
|VQ_DEAD
|
1173 VQ_ASSIST
|VQ_NOTRESPLOCK
1174 #if HAVE_DECL_VQ_UPDATE
1177 #if HAVE_DECL_VQ_VERYLOWDISK
1183 const struct dispatch_source_type_s _dispatch_source_type_sock
= {
1186 .filter
= EVFILT_SOCK
,
1187 .flags
= EV_CLEAR
|EV_UDATA_SPECIFIC
,
1189 .mask
= NOTE_CONNRESET
| NOTE_READCLOSED
| NOTE_WRITECLOSED
|
1190 NOTE_TIMEOUT
| NOTE_NOSRCADDR
| NOTE_IFDENIED
| NOTE_SUSPEND
|
1191 NOTE_RESUME
| NOTE_KEEPALIVE
1192 #ifdef NOTE_ADAPTIVE_WTIMO
1193 | NOTE_ADAPTIVE_WTIMO
| NOTE_ADAPTIVE_RTIMO
1195 #ifdef NOTE_CONNECTED
1196 | NOTE_CONNECTED
| NOTE_DISCONNECTED
| NOTE_CONNINFO_UPDATED
1199 #endif // EVFILT_SOCK
1202 #if DISPATCH_USE_EV_UDATA_SPECIFIC
1204 dispatch_source_type_data_init(dispatch_source_t ds
,
1205 dispatch_source_type_t type DISPATCH_UNUSED
,
1206 uintptr_t handle DISPATCH_UNUSED
,
1207 unsigned long mask DISPATCH_UNUSED
,
1208 dispatch_queue_t q DISPATCH_UNUSED
)
1210 ds
->ds_needs_rearm
= false; // not registered with kevent
1213 #define dispatch_source_type_data_init NULL
1216 const struct dispatch_source_type_s _dispatch_source_type_data_add
= {
1218 .filter
= DISPATCH_EVFILT_CUSTOM_ADD
,
1219 .flags
= EV_UDATA_SPECIFIC
,
1221 .init
= dispatch_source_type_data_init
,
1224 const struct dispatch_source_type_s _dispatch_source_type_data_or
= {
1226 .filter
= DISPATCH_EVFILT_CUSTOM_OR
,
1227 .flags
= EV_CLEAR
|EV_UDATA_SPECIFIC
,
1230 .init
= dispatch_source_type_data_init
,
1236 dispatch_source_type_mach_send_init(dispatch_source_t ds
,
1237 dispatch_source_type_t type DISPATCH_UNUSED
,
1238 uintptr_t handle DISPATCH_UNUSED
, unsigned long mask
,
1239 dispatch_queue_t q DISPATCH_UNUSED
)
1242 // Preserve legacy behavior that (mask == 0) => DISPATCH_MACH_SEND_DEAD
1243 ds
->ds_dkev
->dk_kevent
.fflags
= DISPATCH_MACH_SEND_DEAD
;
1244 ds
->ds_pending_data_mask
= DISPATCH_MACH_SEND_DEAD
;
1248 const struct dispatch_source_type_s _dispatch_source_type_mach_send
= {
1250 .filter
= DISPATCH_EVFILT_MACH_NOTIFICATION
,
1253 .mask
= DISPATCH_MACH_SEND_DEAD
|DISPATCH_MACH_SEND_POSSIBLE
,
1254 .init
= dispatch_source_type_mach_send_init
,
1258 dispatch_source_type_mach_recv_init(dispatch_source_t ds
,
1259 dispatch_source_type_t type DISPATCH_UNUSED
,
1260 uintptr_t handle DISPATCH_UNUSED
,
1261 unsigned long mask DISPATCH_UNUSED
,
1262 dispatch_queue_t q DISPATCH_UNUSED
)
1264 ds
->ds_is_level
= false;
1267 const struct dispatch_source_type_s _dispatch_source_type_mach_recv
= {
1269 .filter
= EVFILT_MACHPORT
,
1270 .flags
= EV_DISPATCH
,
1271 .fflags
= DISPATCH_MACH_RECV_MESSAGE
,
1273 .init
= dispatch_source_type_mach_recv_init
,
1277 #pragma mark dispatch_mig
1280 dispatch_mach_msg_get_context(mach_msg_header_t
*msg
)
1282 mach_msg_context_trailer_t
*tp
;
1283 void *context
= NULL
;
1285 tp
= (mach_msg_context_trailer_t
*)((uint8_t *)msg
+
1286 round_msg(msg
->msgh_size
));
1287 if (tp
->msgh_trailer_size
>=
1288 (mach_msg_size_t
)sizeof(mach_msg_context_trailer_t
)) {
1289 context
= (void *)(uintptr_t)tp
->msgh_context
;
1295 _dispatch_wakeup_runloop_thread(mach_port_t mp DISPATCH_UNUSED
)
1297 // dummy function just to pop a runloop thread out of mach_msg()
1302 _dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED
)
1304 // dummy function to consume a send-once right
1309 _dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED
,
1313 // this function should never be called
1314 (void)dispatch_assume_zero(name
);
1315 kr
= mach_port_mod_refs(mach_task_self(), name
, MACH_PORT_RIGHT_RECEIVE
,-1);
1316 DISPATCH_VERIFY_MIG(kr
);
1317 (void)dispatch_assume_zero(kr
);
1318 return KERN_SUCCESS
;
1322 _dispatch_mach_notify_no_senders(mach_port_t notify
,
1323 mach_port_mscount_t mscnt DISPATCH_UNUSED
)
1325 // this function should never be called
1326 (void)dispatch_assume_zero(notify
);
1327 return KERN_SUCCESS
;
1331 _dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED
)
1333 // we only register for dead-name notifications
1334 // some code deallocated our send-once right without consuming it
1336 _dispatch_log("Corruption: An app/library deleted a libdispatch "
1337 "dead-name notification");
1339 return KERN_SUCCESS
;