2 * Copyright (c) 2008-2011 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)
64 dummy_function_r0(void)
70 #pragma mark dispatch_globals
72 #if DISPATCH_COCOA_COMPAT
73 // dispatch_begin_thread_4GC having non-default value triggers GC-only slow
74 // paths and is checked frequently, testing against NULL is faster than
75 // comparing for equality with "dummy_function"
76 void (*dispatch_begin_thread_4GC
)(void) = NULL
;
77 void (*dispatch_end_thread_4GC
)(void) = dummy_function
;
78 void (*dispatch_no_worker_threads_4GC
)(void) = NULL
;
79 void *(*_dispatch_begin_NSAutoReleasePool
)(void) = (void *)dummy_function
;
80 void (*_dispatch_end_NSAutoReleasePool
)(void *) = (void *)dummy_function
;
83 struct _dispatch_hw_config_s _dispatch_hw_config
;
84 bool _dispatch_safe_fork
= true;
86 const struct dispatch_queue_offsets_s dispatch_queue_offsets
= {
88 .dqo_label
= offsetof(struct dispatch_queue_s
, dq_label
),
89 .dqo_label_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_label
),
92 .dqo_width
= offsetof(struct dispatch_queue_s
, dq_width
),
93 .dqo_width_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_width
),
94 .dqo_serialnum
= offsetof(struct dispatch_queue_s
, dq_serialnum
),
95 .dqo_serialnum_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_serialnum
),
96 .dqo_running
= offsetof(struct dispatch_queue_s
, dq_running
),
97 .dqo_running_size
= sizeof(((dispatch_queue_t
)NULL
)->dq_running
),
100 // 6618342 Contact the team that owns the Instrument DTrace probe before
101 // renaming this symbol
102 DISPATCH_CACHELINE_ALIGN
103 struct dispatch_queue_s _dispatch_main_q
= {
104 #if !DISPATCH_USE_RESOLVERS
105 .do_vtable
= &_dispatch_queue_vtable
,
106 .do_targetq
= &_dispatch_root_queues
[
107 DISPATCH_ROOT_QUEUE_IDX_DEFAULT_OVERCOMMIT_PRIORITY
],
109 .do_ref_cnt
= DISPATCH_OBJECT_GLOBAL_REFCNT
,
110 .do_xref_cnt
= DISPATCH_OBJECT_GLOBAL_REFCNT
,
111 .do_suspend_cnt
= DISPATCH_OBJECT_SUSPEND_LOCK
,
112 .dq_label
= "com.apple.main-thread",
118 const struct dispatch_queue_attr_vtable_s dispatch_queue_attr_vtable
= {
119 .do_type
= DISPATCH_QUEUE_ATTR_TYPE
,
120 .do_kind
= "queue-attr",
123 struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent
= {
124 .do_vtable
= &dispatch_queue_attr_vtable
,
125 .do_ref_cnt
= DISPATCH_OBJECT_GLOBAL_REFCNT
,
126 .do_xref_cnt
= DISPATCH_OBJECT_GLOBAL_REFCNT
,
127 .do_next
= DISPATCH_OBJECT_LISTLESS
,
130 struct dispatch_data_s _dispatch_data_empty
= {
131 #if !DISPATCH_USE_RESOLVERS
132 .do_vtable
= &_dispatch_data_vtable
,
134 .do_ref_cnt
= DISPATCH_OBJECT_GLOBAL_REFCNT
,
135 .do_xref_cnt
= DISPATCH_OBJECT_GLOBAL_REFCNT
,
136 .do_next
= DISPATCH_OBJECT_LISTLESS
,
139 const dispatch_block_t _dispatch_data_destructor_free
= ^{
140 DISPATCH_CRASH("free destructor called");
144 #pragma mark dispatch_log
146 static char _dispatch_build
[16];
149 _dispatch_bug_init(void *context DISPATCH_UNUSED
)
152 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
153 size_t bufsz
= sizeof(_dispatch_build
);
155 sysctl(mib
, 2, _dispatch_build
, &bufsz
, NULL
, 0);
158 * XXXRW: What to do here for !Mac OS X?
160 memset(_dispatch_build
, 0, sizeof(_dispatch_build
));
165 _dispatch_bug(size_t line
, long val
)
167 static dispatch_once_t pred
;
168 static void *last_seen
;
169 void *ra
= __builtin_return_address(0);
171 dispatch_once_f(&pred
, NULL
, _dispatch_bug_init
);
172 if (last_seen
!= ra
) {
174 _dispatch_log("BUG in libdispatch: %s - %lu - 0x%lx",
175 _dispatch_build
, (unsigned long)line
, val
);
180 _dispatch_bug_mach_client(const char* msg
, mach_msg_return_t kr
)
182 static void *last_seen
;
183 void *ra
= __builtin_return_address(0);
184 if (last_seen
!= ra
) {
186 _dispatch_log("BUG in libdispatch client: %s %s - 0x%x", msg
,
187 mach_error_string(kr
), kr
);
192 _dispatch_abort(size_t line
, long val
)
194 _dispatch_bug(line
, val
);
199 _dispatch_log(const char *msg
, ...)
204 _dispatch_logv(msg
, ap
);
208 static FILE *dispatch_logfile
;
209 static bool dispatch_log_disabled
;
212 _dispatch_logv_init(void *context DISPATCH_UNUSED
)
215 bool log_to_file
= true;
217 bool log_to_file
= false;
219 char *e
= getenv("LIBDISPATCH_LOG");
221 if (strcmp(e
, "YES") == 0) {
223 } else if (strcmp(e
, "NO") == 0) {
224 dispatch_log_disabled
= true;
225 } else if (strcmp(e
, "syslog") == 0) {
227 } else if (strcmp(e
, "file") == 0) {
229 } else if (strcmp(e
, "stderr") == 0) {
231 dispatch_logfile
= stderr
;
234 if (!dispatch_log_disabled
) {
235 if (log_to_file
&& !dispatch_logfile
) {
237 snprintf(path
, sizeof(path
), "/var/tmp/libdispatch.%d.log",
239 dispatch_logfile
= fopen(path
, "a");
241 if (dispatch_logfile
) {
243 gettimeofday(&tv
, NULL
);
244 fprintf(dispatch_logfile
, "=== log file opened for %s[%u] at "
245 "%ld.%06u ===\n", getprogname() ?: "", getpid(),
246 tv
.tv_sec
, tv
.tv_usec
);
247 fflush(dispatch_logfile
);
253 _dispatch_logv(const char *msg
, va_list ap
)
255 static dispatch_once_t pred
;
256 dispatch_once_f(&pred
, NULL
, _dispatch_logv_init
);
258 if (slowpath(dispatch_log_disabled
)) {
261 if (slowpath(dispatch_logfile
)) {
262 vfprintf(dispatch_logfile
, msg
, ap
);
263 // TODO: May cause interleaving with another thread's log
264 fputc('\n', dispatch_logfile
);
265 fflush(dispatch_logfile
);
268 vsyslog(LOG_NOTICE
, msg
, ap
);
272 #pragma mark dispatch_debug
275 dispatch_debug(dispatch_object_t dou
, const char *msg
, ...)
280 dispatch_debugv(dou
._do
, msg
, ap
);
285 dispatch_debugv(dispatch_object_t dou
, const char *msg
, va_list ap
)
290 if (dou
._do
&& dou
._do
->do_vtable
->do_debug
) {
291 offs
= dx_debug(dou
._do
, buf
, sizeof(buf
));
293 offs
= snprintf(buf
, sizeof(buf
), "NULL vtable slot");
296 snprintf(buf
+ offs
, sizeof(buf
) - offs
, ": %s", msg
);
297 _dispatch_logv(buf
, ap
);
301 #pragma mark dispatch_block_t
305 #undef _dispatch_Block_copy
307 _dispatch_Block_copy(dispatch_block_t db
)
309 dispatch_block_t rval
;
311 while (!(rval
= Block_copy(db
))) {
318 _dispatch_call_block_and_release(void *block
)
320 void (^b
)(void) = block
;
328 #pragma mark dispatch_client_callout
330 #if DISPATCH_USE_CLIENT_CALLOUT
332 #undef _dispatch_client_callout
333 #undef _dispatch_client_callout2
337 _dispatch_client_callout(void *ctxt
, dispatch_function_t f
)
344 _dispatch_client_callout2(void *ctxt
, size_t i
, void (*f
)(void *, size_t))
352 #pragma mark dispatch_source_types
355 dispatch_source_type_timer_init(dispatch_source_t ds
,
356 dispatch_source_type_t type DISPATCH_UNUSED
,
357 uintptr_t handle DISPATCH_UNUSED
,
359 dispatch_queue_t q DISPATCH_UNUSED
)
361 ds
->ds_refs
= calloc(1ul, sizeof(struct dispatch_timer_source_refs_s
));
362 if (slowpath(!ds
->ds_refs
)) return;
363 ds
->ds_needs_rearm
= true;
364 ds
->ds_is_timer
= true;
365 ds_timer(ds
->ds_refs
).flags
= mask
;
368 const struct dispatch_source_type_s _dispatch_source_type_timer
= {
370 .filter
= DISPATCH_EVFILT_TIMER
,
372 .mask
= DISPATCH_TIMER_WALL_CLOCK
,
373 .init
= dispatch_source_type_timer_init
,
376 const struct dispatch_source_type_s _dispatch_source_type_read
= {
378 .filter
= EVFILT_READ
,
379 .flags
= EV_DISPATCH
,
383 const struct dispatch_source_type_s _dispatch_source_type_write
= {
385 .filter
= EVFILT_WRITE
,
386 .flags
= EV_DISPATCH
,
390 #if DISPATCH_USE_VM_PRESSURE
391 #if TARGET_IPHONE_SIMULATOR // rdar://problem/9219483
392 static int _dispatch_ios_simulator_memory_warnings_fd
= -1;
394 _dispatch_ios_simulator_vm_source_init(void *context DISPATCH_UNUSED
)
396 char *e
= getenv("IPHONE_SIMULATOR_MEMORY_WARNINGS");
398 _dispatch_ios_simulator_memory_warnings_fd
= open(e
, O_EVTONLY
);
399 if (_dispatch_ios_simulator_memory_warnings_fd
== -1) {
400 (void)dispatch_assume_zero(errno
);
404 dispatch_source_type_vm_init(dispatch_source_t ds
,
405 dispatch_source_type_t type DISPATCH_UNUSED
,
406 uintptr_t handle DISPATCH_UNUSED
,
408 dispatch_queue_t q DISPATCH_UNUSED
)
410 static dispatch_once_t pred
;
411 dispatch_once_f(&pred
, NULL
, _dispatch_ios_simulator_vm_source_init
);
412 ds
->ds_dkev
->dk_kevent
.ident
= (mask
& DISPATCH_VM_PRESSURE
?
413 _dispatch_ios_simulator_memory_warnings_fd
: -1);
416 const struct dispatch_source_type_s _dispatch_source_type_vm
= {
418 .filter
= EVFILT_VNODE
,
422 .init
= dispatch_source_type_vm_init
,
426 dispatch_source_type_vm_init(dispatch_source_t ds
,
427 dispatch_source_type_t type DISPATCH_UNUSED
,
428 uintptr_t handle DISPATCH_UNUSED
,
429 unsigned long mask DISPATCH_UNUSED
,
430 dispatch_queue_t q DISPATCH_UNUSED
)
432 ds
->ds_is_level
= false;
435 const struct dispatch_source_type_s _dispatch_source_type_vm
= {
438 .flags
= EV_DISPATCH
,
440 .mask
= NOTE_VM_PRESSURE
,
441 .init
= dispatch_source_type_vm_init
,
446 const struct dispatch_source_type_s _dispatch_source_type_proc
= {
448 .filter
= EVFILT_PROC
,
451 .mask
= NOTE_EXIT
|NOTE_FORK
|NOTE_EXEC
452 #if HAVE_DECL_NOTE_SIGNAL
455 #if HAVE_DECL_NOTE_REAP
461 const struct dispatch_source_type_s _dispatch_source_type_signal
= {
463 .filter
= EVFILT_SIGNAL
,
467 const struct dispatch_source_type_s _dispatch_source_type_vnode
= {
469 .filter
= EVFILT_VNODE
,
472 .mask
= NOTE_DELETE
|NOTE_WRITE
|NOTE_EXTEND
|NOTE_ATTRIB
|NOTE_LINK
|
473 NOTE_RENAME
|NOTE_REVOKE
474 #if HAVE_DECL_NOTE_NONE
480 const struct dispatch_source_type_s _dispatch_source_type_vfs
= {
485 .mask
= VQ_NOTRESP
|VQ_NEEDAUTH
|VQ_LOWDISK
|VQ_MOUNT
|VQ_UNMOUNT
|VQ_DEAD
|
486 VQ_ASSIST
|VQ_NOTRESPLOCK
487 #if HAVE_DECL_VQ_UPDATE
490 #if HAVE_DECL_VQ_VERYLOWDISK
496 const struct dispatch_source_type_s _dispatch_source_type_data_add
= {
498 .filter
= DISPATCH_EVFILT_CUSTOM_ADD
,
502 const struct dispatch_source_type_s _dispatch_source_type_data_or
= {
504 .filter
= DISPATCH_EVFILT_CUSTOM_OR
,
513 dispatch_source_type_mach_send_init(dispatch_source_t ds
,
514 dispatch_source_type_t type DISPATCH_UNUSED
,
515 uintptr_t handle DISPATCH_UNUSED
, unsigned long mask
,
516 dispatch_queue_t q DISPATCH_UNUSED
)
518 static dispatch_once_t pred
;
519 dispatch_once_f(&pred
, NULL
, _dispatch_mach_notify_source_init
);
521 // Preserve legacy behavior that (mask == 0) => DISPATCH_MACH_SEND_DEAD
522 ds
->ds_dkev
->dk_kevent
.fflags
= DISPATCH_MACH_SEND_DEAD
;
523 ds
->ds_pending_data_mask
= DISPATCH_MACH_SEND_DEAD
;
527 const struct dispatch_source_type_s _dispatch_source_type_mach_send
= {
529 .filter
= EVFILT_MACHPORT
,
532 .mask
= DISPATCH_MACH_SEND_DEAD
|DISPATCH_MACH_SEND_POSSIBLE
,
533 .init
= dispatch_source_type_mach_send_init
,
537 dispatch_source_type_mach_recv_init(dispatch_source_t ds
,
538 dispatch_source_type_t type DISPATCH_UNUSED
,
539 uintptr_t handle DISPATCH_UNUSED
,
540 unsigned long mask DISPATCH_UNUSED
,
541 dispatch_queue_t q DISPATCH_UNUSED
)
543 ds
->ds_is_level
= false;
546 const struct dispatch_source_type_s _dispatch_source_type_mach_recv
= {
548 .filter
= EVFILT_MACHPORT
,
549 .flags
= EV_DISPATCH
,
550 .fflags
= DISPATCH_MACH_RECV_MESSAGE
,
552 .init
= dispatch_source_type_mach_recv_init
,
556 #pragma mark dispatch_mig
559 dispatch_mach_msg_get_context(mach_msg_header_t
*msg
)
561 mach_msg_context_trailer_t
*tp
;
562 void *context
= NULL
;
564 tp
= (mach_msg_context_trailer_t
*)((uint8_t *)msg
+
565 round_msg(msg
->msgh_size
));
566 if (tp
->msgh_trailer_size
>=
567 (mach_msg_size_t
)sizeof(mach_msg_context_trailer_t
)) {
568 context
= (void *)(uintptr_t)tp
->msgh_context
;
574 _dispatch_wakeup_main_thread(mach_port_t mp DISPATCH_UNUSED
)
576 // dummy function just to pop out the main thread out of mach_msg()
581 _dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED
)
583 // dummy function to consume a send-once right
588 _dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED
,
592 // this function should never be called
593 (void)dispatch_assume_zero(name
);
594 kr
= mach_port_mod_refs(mach_task_self(), name
, MACH_PORT_RIGHT_RECEIVE
,-1);
595 DISPATCH_VERIFY_MIG(kr
);
596 (void)dispatch_assume_zero(kr
);
601 _dispatch_mach_notify_no_senders(mach_port_t notify
,
602 mach_port_mscount_t mscnt DISPATCH_UNUSED
)
604 // this function should never be called
605 (void)dispatch_assume_zero(notify
);
610 _dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED
)
612 // we only register for dead-name notifications
613 // some code deallocated our send-once right without consuming it
615 _dispatch_log("Corruption: An app/library deleted a libdispatch "
616 "dead-name notification");