]> git.saurik.com Git - apple/libdispatch.git/blob - src/init.c
libdispatch-187.9.tar.gz
[apple/libdispatch.git] / src / init.c
1 /*
2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21 // Contains exported global data and initialization & other routines that must
22 // only exist once in the shared library even when resolvers are used.
23
24 #include "internal.h"
25
26 #if HAVE_MACH
27 #include "protocolServer.h"
28 #endif
29
30 #pragma mark -
31 #pragma mark dispatch_init
32
33 #if USE_LIBDISPATCH_INIT_CONSTRUCTOR
34 DISPATCH_NOTHROW __attribute__((constructor))
35 void
36 _libdispatch_init(void);
37
38 DISPATCH_EXPORT DISPATCH_NOTHROW
39 void
40 _libdispatch_init(void)
41 {
42 libdispatch_init();
43 }
44 #endif
45
46 DISPATCH_EXPORT DISPATCH_NOTHROW
47 void
48 dispatch_atfork_prepare(void)
49 {
50 }
51
52 DISPATCH_EXPORT DISPATCH_NOTHROW
53 void
54 dispatch_atfork_parent(void)
55 {
56 }
57
58 void
59 dummy_function(void)
60 {
61 }
62
63 long
64 dummy_function_r0(void)
65 {
66 return 0;
67 }
68
69 #pragma mark -
70 #pragma mark dispatch_globals
71
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;
81 #endif
82
83 struct _dispatch_hw_config_s _dispatch_hw_config;
84 bool _dispatch_safe_fork = true;
85
86 const struct dispatch_queue_offsets_s dispatch_queue_offsets = {
87 .dqo_version = 3,
88 .dqo_label = offsetof(struct dispatch_queue_s, dq_label),
89 .dqo_label_size = sizeof(((dispatch_queue_t)NULL)->dq_label),
90 .dqo_flags = 0,
91 .dqo_flags_size = 0,
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),
98 };
99
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],
108 #endif
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",
113 .dq_running = 1,
114 .dq_width = 1,
115 .dq_serialnum = 1,
116 };
117
118 const struct dispatch_queue_attr_vtable_s dispatch_queue_attr_vtable = {
119 .do_type = DISPATCH_QUEUE_ATTR_TYPE,
120 .do_kind = "queue-attr",
121 };
122
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,
128 };
129
130 struct dispatch_data_s _dispatch_data_empty = {
131 #if !DISPATCH_USE_RESOLVERS
132 .do_vtable = &_dispatch_data_vtable,
133 #endif
134 .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT,
135 .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT,
136 .do_next = DISPATCH_OBJECT_LISTLESS,
137 };
138
139 const dispatch_block_t _dispatch_data_destructor_free = ^{
140 DISPATCH_CRASH("free destructor called");
141 };
142
143 #pragma mark -
144 #pragma mark dispatch_log
145
146 static char _dispatch_build[16];
147
148 static void
149 _dispatch_bug_init(void *context DISPATCH_UNUSED)
150 {
151 #ifdef __APPLE__
152 int mib[] = { CTL_KERN, KERN_OSVERSION };
153 size_t bufsz = sizeof(_dispatch_build);
154
155 sysctl(mib, 2, _dispatch_build, &bufsz, NULL, 0);
156 #else
157 /*
158 * XXXRW: What to do here for !Mac OS X?
159 */
160 memset(_dispatch_build, 0, sizeof(_dispatch_build));
161 #endif
162 }
163
164 void
165 _dispatch_bug(size_t line, long val)
166 {
167 static dispatch_once_t pred;
168 static void *last_seen;
169 void *ra = __builtin_return_address(0);
170
171 dispatch_once_f(&pred, NULL, _dispatch_bug_init);
172 if (last_seen != ra) {
173 last_seen = ra;
174 _dispatch_log("BUG in libdispatch: %s - %lu - 0x%lx",
175 _dispatch_build, (unsigned long)line, val);
176 }
177 }
178
179 void
180 _dispatch_bug_mach_client(const char* msg, mach_msg_return_t kr)
181 {
182 static void *last_seen;
183 void *ra = __builtin_return_address(0);
184 if (last_seen != ra) {
185 last_seen = ra;
186 _dispatch_log("BUG in libdispatch client: %s %s - 0x%x", msg,
187 mach_error_string(kr), kr);
188 }
189 }
190
191 void
192 _dispatch_abort(size_t line, long val)
193 {
194 _dispatch_bug(line, val);
195 abort();
196 }
197
198 void
199 _dispatch_log(const char *msg, ...)
200 {
201 va_list ap;
202
203 va_start(ap, msg);
204 _dispatch_logv(msg, ap);
205 va_end(ap);
206 }
207
208 static FILE *dispatch_logfile;
209 static bool dispatch_log_disabled;
210
211 static void
212 _dispatch_logv_init(void *context DISPATCH_UNUSED)
213 {
214 #if DISPATCH_DEBUG
215 bool log_to_file = true;
216 #else
217 bool log_to_file = false;
218 #endif
219 char *e = getenv("LIBDISPATCH_LOG");
220 if (e) {
221 if (strcmp(e, "YES") == 0) {
222 // default
223 } else if (strcmp(e, "NO") == 0) {
224 dispatch_log_disabled = true;
225 } else if (strcmp(e, "syslog") == 0) {
226 log_to_file = false;
227 } else if (strcmp(e, "file") == 0) {
228 log_to_file = true;
229 } else if (strcmp(e, "stderr") == 0) {
230 log_to_file = true;
231 dispatch_logfile = stderr;
232 }
233 }
234 if (!dispatch_log_disabled) {
235 if (log_to_file && !dispatch_logfile) {
236 char path[PATH_MAX];
237 snprintf(path, sizeof(path), "/var/tmp/libdispatch.%d.log",
238 getpid());
239 dispatch_logfile = fopen(path, "a");
240 }
241 if (dispatch_logfile) {
242 struct timeval tv;
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);
248 }
249 }
250 }
251
252 void
253 _dispatch_logv(const char *msg, va_list ap)
254 {
255 static dispatch_once_t pred;
256 dispatch_once_f(&pred, NULL, _dispatch_logv_init);
257
258 if (slowpath(dispatch_log_disabled)) {
259 return;
260 }
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);
266 return;
267 }
268 vsyslog(LOG_NOTICE, msg, ap);
269 }
270
271 #pragma mark -
272 #pragma mark dispatch_debug
273
274 void
275 dispatch_debug(dispatch_object_t dou, const char *msg, ...)
276 {
277 va_list ap;
278
279 va_start(ap, msg);
280 dispatch_debugv(dou._do, msg, ap);
281 va_end(ap);
282 }
283
284 void
285 dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
286 {
287 char buf[4096];
288 size_t offs;
289
290 if (dou._do && dou._do->do_vtable->do_debug) {
291 offs = dx_debug(dou._do, buf, sizeof(buf));
292 } else {
293 offs = snprintf(buf, sizeof(buf), "NULL vtable slot");
294 }
295
296 snprintf(buf + offs, sizeof(buf) - offs, ": %s", msg);
297 _dispatch_logv(buf, ap);
298 }
299
300 #pragma mark -
301 #pragma mark dispatch_block_t
302
303 #ifdef __BLOCKS__
304
305 #undef _dispatch_Block_copy
306 dispatch_block_t
307 _dispatch_Block_copy(dispatch_block_t db)
308 {
309 dispatch_block_t rval;
310
311 while (!(rval = Block_copy(db))) {
312 sleep(1);
313 }
314 return rval;
315 }
316
317 void
318 _dispatch_call_block_and_release(void *block)
319 {
320 void (^b)(void) = block;
321 b();
322 Block_release(b);
323 }
324
325 #endif // __BLOCKS__
326
327 #pragma mark -
328 #pragma mark dispatch_client_callout
329
330 #if DISPATCH_USE_CLIENT_CALLOUT
331
332 #undef _dispatch_client_callout
333 #undef _dispatch_client_callout2
334
335 DISPATCH_NOINLINE
336 void
337 _dispatch_client_callout(void *ctxt, dispatch_function_t f)
338 {
339 return f(ctxt);
340 }
341
342 DISPATCH_NOINLINE
343 void
344 _dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
345 {
346 return f(ctxt, i);
347 }
348
349 #endif
350
351 #pragma mark -
352 #pragma mark dispatch_source_types
353
354 static void
355 dispatch_source_type_timer_init(dispatch_source_t ds,
356 dispatch_source_type_t type DISPATCH_UNUSED,
357 uintptr_t handle DISPATCH_UNUSED,
358 unsigned long mask,
359 dispatch_queue_t q DISPATCH_UNUSED)
360 {
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;
366 }
367
368 const struct dispatch_source_type_s _dispatch_source_type_timer = {
369 .ke = {
370 .filter = DISPATCH_EVFILT_TIMER,
371 },
372 .mask = DISPATCH_TIMER_WALL_CLOCK,
373 .init = dispatch_source_type_timer_init,
374 };
375
376 const struct dispatch_source_type_s _dispatch_source_type_read = {
377 .ke = {
378 .filter = EVFILT_READ,
379 .flags = EV_DISPATCH,
380 },
381 };
382
383 const struct dispatch_source_type_s _dispatch_source_type_write = {
384 .ke = {
385 .filter = EVFILT_WRITE,
386 .flags = EV_DISPATCH,
387 },
388 };
389
390 #if DISPATCH_USE_VM_PRESSURE
391 #if TARGET_IPHONE_SIMULATOR // rdar://problem/9219483
392 static int _dispatch_ios_simulator_memory_warnings_fd = -1;
393 static void
394 _dispatch_ios_simulator_vm_source_init(void *context DISPATCH_UNUSED)
395 {
396 char *e = getenv("IPHONE_SIMULATOR_MEMORY_WARNINGS");
397 if (!e) return;
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);
401 }
402 }
403 static void
404 dispatch_source_type_vm_init(dispatch_source_t ds,
405 dispatch_source_type_t type DISPATCH_UNUSED,
406 uintptr_t handle DISPATCH_UNUSED,
407 unsigned long mask,
408 dispatch_queue_t q DISPATCH_UNUSED)
409 {
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);
414 }
415
416 const struct dispatch_source_type_s _dispatch_source_type_vm = {
417 .ke = {
418 .filter = EVFILT_VNODE,
419 .flags = EV_CLEAR,
420 },
421 .mask = NOTE_ATTRIB,
422 .init = dispatch_source_type_vm_init,
423 };
424 #else
425 static void
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)
431 {
432 ds->ds_is_level = false;
433 }
434
435 const struct dispatch_source_type_s _dispatch_source_type_vm = {
436 .ke = {
437 .filter = EVFILT_VM,
438 .flags = EV_DISPATCH,
439 },
440 .mask = NOTE_VM_PRESSURE,
441 .init = dispatch_source_type_vm_init,
442 };
443 #endif
444 #endif
445
446 const struct dispatch_source_type_s _dispatch_source_type_proc = {
447 .ke = {
448 .filter = EVFILT_PROC,
449 .flags = EV_CLEAR,
450 },
451 .mask = NOTE_EXIT|NOTE_FORK|NOTE_EXEC
452 #if HAVE_DECL_NOTE_SIGNAL
453 |NOTE_SIGNAL
454 #endif
455 #if HAVE_DECL_NOTE_REAP
456 |NOTE_REAP
457 #endif
458 ,
459 };
460
461 const struct dispatch_source_type_s _dispatch_source_type_signal = {
462 .ke = {
463 .filter = EVFILT_SIGNAL,
464 },
465 };
466
467 const struct dispatch_source_type_s _dispatch_source_type_vnode = {
468 .ke = {
469 .filter = EVFILT_VNODE,
470 .flags = EV_CLEAR,
471 },
472 .mask = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|
473 NOTE_RENAME|NOTE_REVOKE
474 #if HAVE_DECL_NOTE_NONE
475 |NOTE_NONE
476 #endif
477 ,
478 };
479
480 const struct dispatch_source_type_s _dispatch_source_type_vfs = {
481 .ke = {
482 .filter = EVFILT_FS,
483 .flags = EV_CLEAR,
484 },
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
488 |VQ_UPDATE
489 #endif
490 #if HAVE_DECL_VQ_VERYLOWDISK
491 |VQ_VERYLOWDISK
492 #endif
493 ,
494 };
495
496 const struct dispatch_source_type_s _dispatch_source_type_data_add = {
497 .ke = {
498 .filter = DISPATCH_EVFILT_CUSTOM_ADD,
499 },
500 };
501
502 const struct dispatch_source_type_s _dispatch_source_type_data_or = {
503 .ke = {
504 .filter = DISPATCH_EVFILT_CUSTOM_OR,
505 .flags = EV_CLEAR,
506 .fflags = ~0,
507 },
508 };
509
510 #if HAVE_MACH
511
512 static void
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)
517 {
518 static dispatch_once_t pred;
519 dispatch_once_f(&pred, NULL, _dispatch_mach_notify_source_init);
520 if (!mask) {
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;
524 }
525 }
526
527 const struct dispatch_source_type_s _dispatch_source_type_mach_send = {
528 .ke = {
529 .filter = EVFILT_MACHPORT,
530 .flags = EV_CLEAR,
531 },
532 .mask = DISPATCH_MACH_SEND_DEAD|DISPATCH_MACH_SEND_POSSIBLE,
533 .init = dispatch_source_type_mach_send_init,
534 };
535
536 static void
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)
542 {
543 ds->ds_is_level = false;
544 }
545
546 const struct dispatch_source_type_s _dispatch_source_type_mach_recv = {
547 .ke = {
548 .filter = EVFILT_MACHPORT,
549 .flags = EV_DISPATCH,
550 .fflags = DISPATCH_MACH_RECV_MESSAGE,
551 },
552 .init = dispatch_source_type_mach_recv_init,
553 };
554
555 #pragma mark -
556 #pragma mark dispatch_mig
557
558 void *
559 dispatch_mach_msg_get_context(mach_msg_header_t *msg)
560 {
561 mach_msg_context_trailer_t *tp;
562 void *context = NULL;
563
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;
569 }
570 return context;
571 }
572
573 kern_return_t
574 _dispatch_wakeup_main_thread(mach_port_t mp DISPATCH_UNUSED)
575 {
576 // dummy function just to pop out the main thread out of mach_msg()
577 return 0;
578 }
579
580 kern_return_t
581 _dispatch_consume_send_once_right(mach_port_t mp DISPATCH_UNUSED)
582 {
583 // dummy function to consume a send-once right
584 return 0;
585 }
586
587 kern_return_t
588 _dispatch_mach_notify_port_destroyed(mach_port_t notify DISPATCH_UNUSED,
589 mach_port_t name)
590 {
591 kern_return_t kr;
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);
597 return KERN_SUCCESS;
598 }
599
600 kern_return_t
601 _dispatch_mach_notify_no_senders(mach_port_t notify,
602 mach_port_mscount_t mscnt DISPATCH_UNUSED)
603 {
604 // this function should never be called
605 (void)dispatch_assume_zero(notify);
606 return KERN_SUCCESS;
607 }
608
609 kern_return_t
610 _dispatch_mach_notify_send_once(mach_port_t notify DISPATCH_UNUSED)
611 {
612 // we only register for dead-name notifications
613 // some code deallocated our send-once right without consuming it
614 #if DISPATCH_DEBUG
615 _dispatch_log("Corruption: An app/library deleted a libdispatch "
616 "dead-name notification");
617 #endif
618 return KERN_SUCCESS;
619 }
620
621
622 #endif // HAVE_MACH