1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 1997-2020. All Rights Reserved.
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 * %CopyrightEnd%
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include "sys.h"
26 #include <ctype.h>
27 #include "erl_vm.h"
28 #include "global.h"
29 #include "erl_process.h"
30 #include "error.h"
31 #include "erl_version.h"
32 #include "erl_db.h"
33 #include "beam_bp.h"
34 #include "erl_bits.h"
35 #include "erl_binary.h"
36 #include "dist.h"
37 #include "erl_mseg.h"
38 #include "erl_threads.h"
39 #include "erl_hl_timer.h"
40 #include "erl_mtrace.h"
41 #include "erl_printf_term.h"
42 #include "erl_misc_utils.h"
43 #include "packet_parser.h"
44 #include "erl_cpu_topology.h"
45 #include "erl_thr_progress.h"
46 #include "erl_thr_queue.h"
47 #include "erl_async.h"
48 #include "erl_ptab.h"
49 #include "erl_bif_unique.h"
50 #define ERTS_WANT_TIMER_WHEEL_API
51 #include "erl_time.h"
52 #include "erl_check_io.h"
53 #include "erl_osenv.h"
54 #include "erl_proc_sig_queue.h"
55 #include "beam_load.h"
56
57 #include "jit/beam_asm.h"
58
59 #ifdef HAVE_SYS_RESOURCE_H
60 # include <sys/resource.h>
61 #endif
62
63 #define ERTS_DEFAULT_NO_ASYNC_THREADS 1
64
65 #define ERTS_DEFAULT_SCHED_STACK_SIZE 128
66 #define ERTS_DEFAULT_DCPU_SCHED_STACK_SIZE 40
67 #define ERTS_DEFAULT_DIO_SCHED_STACK_SIZE 40
68
69 /*
70 * The variables below (prefixed with etp_) are for erts/etc/unix/etp-commands
71 * only. Do not remove even though they aren't used elsewhere in the emulator!
72 */
73 const int etp_smp_compiled = 1;
74 const int etp_thread_compiled = 1;
75 const char etp_erts_version[] = ERLANG_VERSION;
76 const char etp_otp_release[] = ERLANG_OTP_RELEASE;
77 const char etp_compile_date[] = ERLANG_COMPILE_DATE;
78 const char etp_arch[] = ERLANG_ARCHITECTURE;
79 #if ERTS_ENABLE_KERNEL_POLL
80 const int erts_use_kernel_poll = 1;
81 const int etp_kernel_poll_support = 1;
82 #else
83 const int erts_use_kernel_poll = 0;
84 const int etp_kernel_poll_support = 0;
85 #endif
86 #if defined(ARCH_64)
87 const int etp_arch_bits = 64;
88 #elif defined(ARCH_32)
89 const int etp_arch_bits = 32;
90 #else
91 # error "Not 64-bit, nor 32-bit arch"
92 #endif
93 #ifdef BEAMASM
94 const int etp_beamasm = 1;
95 #else
96 const int etp_beamasm = 0;
97 #endif
98 #ifdef DEBUG
99 const int etp_debug_compiled = 1;
100 #else
101 const int etp_debug_compiled = 0;
102 #endif
103 #ifdef ERTS_ENABLE_LOCK_COUNT
104 const int etp_lock_count = 1;
105 #else
106 const int etp_lock_count = 0;
107 #endif
108 #ifdef ERTS_ENABLE_LOCK_CHECK
109 const int etp_lock_check = 1;
110 #else
111 const int etp_lock_check = 0;
112 #endif
113 const int etp_endianness = ERTS_ENDIANNESS;
114 const Eterm etp_ref_header = ERTS_REF_THING_HEADER;
115 #ifdef ERTS_MAGIC_REF_THING_HEADER
116 const Eterm etp_magic_ref_header = ERTS_MAGIC_REF_THING_HEADER;
117 #else
118 const Eterm etp_magic_ref_header = ERTS_REF_THING_HEADER;
119 #endif
120 const Eterm etp_the_non_value = THE_NON_VALUE;
121 #ifdef TAG_LITERAL_PTR
122 const Eterm etp_ptr_mask = (~(Eterm)7);
123 #else
124 const Eterm etp_ptr_mask = (~(Eterm)3);
125 #endif
126 #ifdef ERTS_HOLE_MARKER
127 const Eterm etp_hole_marker = ERTS_HOLE_MARKER;
128 #else
129 const Eterm etp_hole_marker = 0;
130 #endif
131
132 static int modified_sched_thread_suggested_stack_size = 0;
133
134 Eterm erts_init_process_id = ERTS_INVALID_PID;
135
136 /*
137 * Note about VxWorks: All variables must be initialized by executable code,
138 * not by an initializer. Otherwise a new instance of the emulator will
139 * inherit previous values.
140 */
141
142 extern void erl_crash_dump_v(char *, int, const char *, va_list);
143 #ifdef __WIN32__
144 extern void ConNormalExit(void);
145 extern void ConWaitForExit(void);
146 #endif
147
148 static void erl_init(int ncpu,
149 int proc_tab_sz,
150 int legacy_proc_tab,
151 int port_tab_sz,
152 int port_tab_sz_ignore_files,
153 int legacy_port_tab,
154 int time_correction,
155 ErtsTimeWarpMode time_warp_mode,
156 int node_tab_delete_delay,
157 ErtsDbSpinCount db_spin_count);
158
159 static erts_atomic_t exiting;
160
161 erts_atomic32_t erts_writing_erl_crash_dump;
162 erts_tsd_key_t erts_is_crash_dumping_key;
163 int erts_initialized = 0;
164
165 /*
166 * Configurable parameters.
167 */
168
169 int H_MIN_SIZE; /* The minimum heap grain */
170 int BIN_VH_MIN_SIZE; /* The minimum binary virtual*/
171 int H_MAX_SIZE; /* The maximum heap size */
172 int H_MAX_FLAGS; /* The maximum heap flags */
173
174 Uint32 erts_debug_flags; /* Debug flags. */
175 int erts_backtrace_depth; /* How many functions to show in a backtrace
176 * in error codes.
177 */
178
179 erts_atomic32_t erts_max_gen_gcs;
180
181 Eterm erts_error_logger_warnings; /* What to map warning logs to, am_error,
182 am_info or am_warning, am_error is
183 the default for BC */
184
185 int erts_compat_rel;
186
187 static int no_schedulers;
188 static int no_schedulers_online;
189 static int no_dirty_cpu_schedulers;
190 static int no_dirty_cpu_schedulers_online;
191 static int no_dirty_io_schedulers;
192
193 #ifdef DEBUG
194 Uint32 verbose; /* See erl_debug.h for information about verbose */
195 #endif
196
197 int erts_atom_table_size = ATOM_LIMIT; /* Maximum number of atoms */
198
199 int erts_pd_initial_size = 8; /* must be power of 2 */
200
201 int erts_modified_timing_level;
202
203 int erts_no_crash_dump = 0; /* Use -d to suppress crash dump. */
204
205 int erts_no_line_info = 0; /* -L: Don't load line information */
206
207 #ifdef BEAMASM
208 int erts_jit_asm_dump = 0; /* -JDdump: Dump assembly code */
209 #endif
210
211 /*
212 * Other global variables.
213 */
214
215 ErtsModifiedTimings erts_modified_timings[] = {
216 /* 0 */ {make_small(0), CONTEXT_REDS},
217 /* 1 */ {make_small(0), (3*CONTEXT_REDS)/4},
218 /* 2 */ {make_small(0), CONTEXT_REDS/2},
219 /* 3 */ {make_small(0), (7*CONTEXT_REDS)/8},
220 /* 4 */ {make_small(0), CONTEXT_REDS/3},
221 /* 5 */ {make_small(0), (10*CONTEXT_REDS)/11},
222 /* 6 */ {make_small(1), CONTEXT_REDS/4},
223 /* 7 */ {make_small(1), (5*CONTEXT_REDS)/7},
224 /* 8 */ {make_small(10), CONTEXT_REDS/5},
225 /* 9 */ {make_small(10), (6*CONTEXT_REDS)/7}
226 };
227
228 #define ERTS_MODIFIED_TIMING_LEVELS \
229 (sizeof(erts_modified_timings)/sizeof(ErtsModifiedTimings))
230
231 Export *erts_delay_trap = NULL;
232
233 int ignore_break;
234 int replace_intr;
235
236 static ERTS_INLINE int
has_prefix(const char * prefix,const char * string)237 has_prefix(const char *prefix, const char *string)
238 {
239 int i;
240 for (i = 0; prefix[i]; i++)
241 if (prefix[i] != string[i])
242 return 0;
243 return 1;
244 }
245
246 static char*
progname(char * fullname)247 progname(char *fullname)
248 {
249 int i;
250
251 i = sys_strlen(fullname);
252 while (i >= 0) {
253 if ((fullname[i] != '/') && (fullname[i] != '\\'))
254 i--;
255 else
256 break;
257 }
258 return fullname+i+1;
259 }
260
261 static int
this_rel_num(void)262 this_rel_num(void)
263 {
264 static int this_rel = -1;
265
266 if (this_rel < 1) {
267 int i;
268 char this_rel_str[] = ERLANG_OTP_RELEASE;
269
270 i = 0;
271 while (this_rel_str[i] && !isdigit((int) this_rel_str[i]))
272 i++;
273 this_rel = atoi(&this_rel_str[i]);
274 if (this_rel < 1)
275 erts_exit(1, "Unexpected ERLANG_OTP_RELEASE format\n");
276 }
277 return this_rel;
278 }
279
280 static ERTS_INLINE void
set_default_time_adj(int * time_correction_p,ErtsTimeWarpMode * time_warp_mode_p)281 set_default_time_adj(int *time_correction_p, ErtsTimeWarpMode *time_warp_mode_p)
282 {
283 *time_correction_p = 1;
284 *time_warp_mode_p = ERTS_NO_TIME_WARP_MODE;
285 if (!erts_check_time_adj_support(*time_correction_p,
286 *time_warp_mode_p)) {
287 *time_correction_p = 0;
288 ASSERT(erts_check_time_adj_support(*time_correction_p,
289 *time_warp_mode_p));
290 }
291 }
292
293 /*
294 * Common error printout function, all error messages
295 * that don't go to the error logger go through here.
296 */
297
erl_error(const char * fmt,va_list args)298 void erl_error(const char *fmt, va_list args)
299 {
300 erts_vfprintf(stderr, fmt, args);
301 }
302
303 static int early_init(int *argc, char **argv);
304
305 static void
erl_init(int ncpu,int proc_tab_sz,int legacy_proc_tab,int port_tab_sz,int port_tab_sz_ignore_files,int legacy_port_tab,int time_correction,ErtsTimeWarpMode time_warp_mode,int node_tab_delete_delay,ErtsDbSpinCount db_spin_count)306 erl_init(int ncpu,
307 int proc_tab_sz,
308 int legacy_proc_tab,
309 int port_tab_sz,
310 int port_tab_sz_ignore_files,
311 int legacy_port_tab,
312 int time_correction,
313 ErtsTimeWarpMode time_warp_mode,
314 int node_tab_delete_delay,
315 ErtsDbSpinCount db_spin_count)
316 {
317 erts_monitor_link_init();
318 erts_bif_unique_init();
319 erts_proc_sig_queue_init(); /* Must be after erts_bif_unique_init(); */
320 erts_init_time(time_correction, time_warp_mode);
321 erts_init_sys_common_misc();
322 erts_init_process(ncpu, proc_tab_sz, legacy_proc_tab);
323 erts_init_scheduling(no_schedulers,
324 no_schedulers_online,
325 erts_no_poll_threads,
326 no_dirty_cpu_schedulers,
327 no_dirty_cpu_schedulers_online,
328 no_dirty_io_schedulers
329 );
330 erts_late_init_time_sup();
331 erts_init_cpu_topology(); /* Must be after init_scheduling */
332 erts_init_gc(); /* Must be after init_scheduling */
333 erts_alloc_late_init();
334
335 H_MIN_SIZE = erts_next_heap_size(H_MIN_SIZE, 0);
336 BIN_VH_MIN_SIZE = erts_next_heap_size(BIN_VH_MIN_SIZE, 0);
337
338 erts_init_trace();
339 erts_init_bits();
340 erts_code_ix_init();
341 erts_init_fun_table();
342 init_atom_table();
343 init_export_table();
344 init_module_table();
345 init_register_table();
346 init_message();
347 #ifdef BEAMASM
348 beamasm_init();
349 #endif
350 erts_bif_info_init();
351 erts_ddll_init();
352 init_emulator();
353 erts_ptab_init(); /* Must be after init_emulator() */
354 erts_init_binary(); /* Must be after init_emulator() */
355 erts_bp_init();
356 init_db(db_spin_count); /* Must be after init_emulator */
357 erts_init_node_tables(node_tab_delete_delay);
358 init_dist();
359 erl_drv_thr_init();
360 erts_init_async();
361 erts_init_io(port_tab_sz, port_tab_sz_ignore_files, legacy_port_tab);
362 init_load();
363 erts_init_bif();
364 erts_init_bif_chksum();
365 erts_init_bif_binary();
366 erts_init_bif_guard();
367 erts_init_bif_persistent_term();
368 erts_init_bif_re();
369 erts_init_unicode(); /* after RE to get access to PCRE unicode */
370 erts_init_external();
371 erts_init_map();
372 erts_beam_bif_load_init();
373 erts_delay_trap = erts_export_put(am_erlang, am_delay_trap, 2);
374 erts_late_init_process();
375 #if HAVE_ERTS_MSEG
376 erts_mseg_late_init(); /* Must be after timer (erts_init_time()) and thread
377 initializations */
378 #endif
379 erl_sys_late_init();
380 packet_parser_init();
381 erl_nif_init();
382 erts_msacc_init();
383 }
384
385 static Eterm
386
erl_spawn_system_process(Process * parent,Eterm mod,Eterm func,Eterm args,ErlSpawnOpts * so)387 erl_spawn_system_process(Process* parent, Eterm mod, Eterm func, Eterm args,
388 ErlSpawnOpts *so)
389 {
390 Eterm res;
391 int arity;
392
393 ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(parent));
394 arity = erts_list_length(args);
395
396 if (erts_find_function(mod, func, arity, erts_active_code_ix()) == NULL) {
397 erts_exit(ERTS_ERROR_EXIT, "No function %T:%T/%i\n", mod, func, arity);
398 }
399
400 so->flags |= SPO_SYSTEM_PROC;
401
402 res = erl_create_process(parent, mod, func, args, so);
403
404 return res;
405 }
406
407 static Eterm
erl_first_process_otp(char * mod_name,int argc,char ** argv)408 erl_first_process_otp(char* mod_name, int argc, char** argv)
409 {
410 int i;
411 Eterm args;
412 Eterm res;
413 Eterm* hp;
414 Process parent;
415 ErlSpawnOpts so;
416 Eterm boot_mod;
417
418 /*
419 * We need a dummy parent process to be able to call erl_create_process().
420 */
421
422 erts_init_empty_process(&parent);
423 erts_proc_lock(&parent, ERTS_PROC_LOCK_MAIN);
424
425 hp = HAlloc(&parent, argc*2 + 4);
426 args = NIL;
427 for (i = argc-1; i >= 0; i--) {
428 int len = sys_strlen(argv[i]);
429 args = CONS(hp, new_binary(&parent, (byte*)argv[i], len), args);
430 hp += 2;
431 }
432 boot_mod = erts_atom_put((byte *) mod_name, sys_strlen(mod_name),
433 ERTS_ATOM_ENC_LATIN1, 1);
434 args = CONS(hp, args, NIL);
435 hp += 2;
436 args = CONS(hp, boot_mod, args);
437
438 ERTS_SET_DEFAULT_SPAWN_OPTS(&so);
439 res = erl_spawn_system_process(&parent, am_erl_init, am_start, args, &so);
440 ASSERT(is_internal_pid(res));
441
442 erts_proc_unlock(&parent, ERTS_PROC_LOCK_MAIN);
443 erts_cleanup_empty_process(&parent);
444
445 return res;
446 }
447
448 static Eterm
erl_system_process_otp(Eterm parent_pid,char * modname,int off_heap_msgq,int prio)449 erl_system_process_otp(Eterm parent_pid, char* modname, int off_heap_msgq, int prio)
450 {
451 Process *parent;
452 ErlSpawnOpts so;
453 Eterm mod, res;
454
455 parent = erts_pid2proc(NULL, 0, parent_pid, ERTS_PROC_LOCK_MAIN);
456 mod = erts_atom_put((byte *) modname, sys_strlen(modname),
457 ERTS_ATOM_ENC_LATIN1, 1);
458
459 ERTS_SET_DEFAULT_SPAWN_OPTS(&so);
460
461 so.flags |= SPO_USE_ARGS;
462
463 if (off_heap_msgq) {
464 so.flags |= SPO_OFF_HEAP_MSGQ;
465 }
466
467 so.min_heap_size = H_MIN_SIZE;
468 so.min_vheap_size = BIN_VH_MIN_SIZE;
469 so.max_heap_size = H_MAX_SIZE;
470 so.max_heap_flags = H_MAX_FLAGS;
471 so.priority = prio;
472 so.max_gen_gcs = (Uint16) erts_atomic32_read_nob(&erts_max_gen_gcs);
473 so.scheduler = 0;
474
475 res = erl_spawn_system_process(parent, mod, am_start, NIL, &so);
476 ASSERT(is_internal_pid(res));
477
478 erts_proc_unlock(parent, ERTS_PROC_LOCK_MAIN);
479
480 return res;
481 }
482
erts_internal_spawn_system_process_3(BIF_ALIST_3)483 Eterm erts_internal_spawn_system_process_3(BIF_ALIST_3) {
484 Eterm mod, func, args, res;
485 ErlSpawnOpts so;
486
487 mod = BIF_ARG_1;
488 func = BIF_ARG_2;
489 args = BIF_ARG_3;
490
491 ASSERT(is_atom(mod));
492 ASSERT(is_atom(func));
493 ASSERT(erts_list_length(args) >= 0);
494
495 ERTS_SET_DEFAULT_SPAWN_OPTS(&so);
496 res = erl_spawn_system_process(BIF_P, mod, func, args, &so);
497
498 if (is_non_value(res)) {
499 BIF_ERROR(BIF_P, so.error_code);
500 }
501
502 BIF_RET(res);
503 }
504
505 Eterm
erts_preloaded(Process * p)506 erts_preloaded(Process* p)
507 {
508 Eterm previous;
509 int j;
510 int need;
511 Eterm mod;
512 Eterm* hp;
513 char* name;
514 const Preload *preload = sys_preloaded();
515
516 j = 0;
517 while (preload[j].name != NULL) {
518 j++;
519 }
520 previous = NIL;
521 need = 2*j;
522 hp = HAlloc(p, need);
523 j = 0;
524 while ((name = preload[j].name) != NULL) {
525 mod = am_atom_put(name, sys_strlen(name));
526 previous = CONS(hp, mod, previous);
527 hp += 2;
528 j++;
529 }
530 return previous;
531 }
532
533
534 /* static variables that must not change (use same values at restart) */
535 static char* program;
536 static char* init = "init";
537 static int boot_argc;
538 static char** boot_argv;
539
540 static char *
get_arg(char * rest,char * next,int * ip)541 get_arg(char* rest, char* next, int* ip)
542 {
543 if (*rest == '\0') {
544 if (next == NULL) {
545 erts_fprintf(stderr, "too few arguments\n");
546 erts_usage();
547 }
548 (*ip)++;
549 return next;
550 }
551 return rest;
552 }
553
554 static void
load_preloaded(void)555 load_preloaded(void)
556 {
557 int i;
558 Eterm res;
559 Preload* preload_p;
560 Eterm module_name;
561 byte* code;
562 char* name;
563 int length;
564
565 if ((preload_p = sys_preloaded()) == NULL) {
566 return;
567 }
568 i = 0;
569 while ((name = preload_p[i].name) != NULL) {
570 length = preload_p[i].size;
571 module_name = erts_atom_put((byte *) name, sys_strlen(name), ERTS_ATOM_ENC_LATIN1, 1);
572 if ((code = sys_preload_begin(&preload_p[i])) == 0)
573 erts_exit(ERTS_ERROR_EXIT, "Failed to find preloaded code for module %s\n",
574 name);
575 res = erts_preload_module(NULL, 0, NIL, &module_name, code, length);
576 sys_preload_end(&preload_p[i]);
577 if (res != NIL)
578 erts_exit(ERTS_ERROR_EXIT,"Failed loading preloaded module %s (%T)\n",
579 name, res);
580 i++;
581 }
582 }
583
584 /* be helpful (or maybe downright rude:-) */
erts_usage(void)585 void erts_usage(void)
586 {
587 int this_rel = this_rel_num();
588 erts_fprintf(stderr, "Usage: %s [flags] [ -- [init_args] ]\n", progname(program));
589 erts_fprintf(stderr, "The flags are:\n\n");
590 erts_fprintf(stderr, "-a size suggest stack size in kilo words for threads\n");
591 erts_fprintf(stderr, " in the async-thread pool; valid range is [%d-%d]\n",
592 ERTS_ASYNC_THREAD_MIN_STACK_SIZE,
593 ERTS_ASYNC_THREAD_MAX_STACK_SIZE);
594 erts_fprintf(stderr, "-A number set number of threads in async thread pool;\n");
595 erts_fprintf(stderr, " valid range is [1-%d]\n",
596 ERTS_MAX_NO_OF_ASYNC_THREADS);
597 erts_fprintf(stderr, "\n");
598
599 erts_fprintf(stderr, "-B[c|d|i] set break (Ctrl-C) behavior; valid letters are:\n");
600 erts_fprintf(stderr, " 'c' to have Ctrl-C interrupt the Erlang shell;\n");
601 erts_fprintf(stderr, " 'd' (or no extra option) to disable the break handler;\n");
602 erts_fprintf(stderr, " 'i' to ignore break signals\n");
603 erts_fprintf(stderr, "\n");
604
605 erts_fprintf(stderr, "-c bool enable or disable time correction\n");
606 erts_fprintf(stderr, "-C mode set time warp mode; valid modes are:\n");
607 erts_fprintf(stderr, " no_time_warp | single_time_warp | multi_time_warp\n");
608 erts_fprintf(stderr, "\n");
609
610 erts_fprintf(stderr, "-d don't write a crash dump for internally detected errors\n");
611 erts_fprintf(stderr, " (halt(String) will still produce a crash dump)\n");
612 erts_fprintf(stderr, "-dcg set the limit for the number of decentralized counter groups\n");
613 erts_fprintf(stderr, "\n");
614
615 erts_fprintf(stderr, "-fn[u|a|l] control how filenames are interpreted\n");
616 erts_fprintf(stderr, "\n");
617
618 erts_fprintf(stderr, "-hms size set minimum heap size in words (default %d)\n",
619 H_DEFAULT_SIZE);
620 erts_fprintf(stderr, "-hmbs size set minimum binary virtual heap size in words (default %d)\n",
621 VH_DEFAULT_SIZE);
622 erts_fprintf(stderr, "-hmax size set maximum heap size in words (default %d)\n",
623 H_DEFAULT_MAX_SIZE);
624 erts_fprintf(stderr, "-hmaxk bool enable or disable kill at max heap size (default true)\n");
625 erts_fprintf(stderr, "-hmaxel bool enable or disable error_logger report at max heap size (default true)\n");
626 erts_fprintf(stderr, "-hpds size set initial process dictionary size (default %d)\n",
627 erts_pd_initial_size);
628 erts_fprintf(stderr, "-hmqd val set default message queue data flag for processes;\n");
629 erts_fprintf(stderr, " valid values are: off_heap | on_heap\n");
630 erts_fprintf(stderr, "\n");
631
632 erts_fprintf(stderr, "-IOp number set number of pollsets to be used to poll for I/O\n");
633 erts_fprintf(stderr, " (this value must be equal or smaller than the\n");
634 erts_fprintf(stderr, " number of poll threads; ignored if the current platform\n");
635 erts_fprintf(stderr, " does not support concurrent update of pollsets)\n");
636 erts_fprintf(stderr, "-IOt number set number of threads to be used to poll for I/O\n");
637 erts_fprintf(stderr, "-IOPp number set number of pollsets as a percentage of the\n");
638 erts_fprintf(stderr, " number of poll threads\n");
639 erts_fprintf(stderr, "-IOPt number set number of threads to be used to poll for I/O\n");
640 erts_fprintf(stderr, " as a percentage of the number of schedulers\n");
641 erts_fprintf(stderr, "-i module set the boot module (default init)\n");
642 erts_fprintf(stderr, "\n");
643
644 #ifdef BEAMASM
645 erts_fprintf(stderr, "-JDdump bool enable or disable dumping of generated assembly code for each module loaded\n");
646 erts_fprintf(stderr, "-JDperf bool enable or disable support for perf on Linux\n");
647 erts_fprintf(stderr, "\n");
648 #endif
649
650 erts_fprintf(stderr, "-n[s|a|d] control behavior of signals to ports (this flag is deprecated)\n");
651 erts_fprintf(stderr, "\n");
652
653 erts_fprintf(stderr, "-M<X> <Y> set memory allocator switches;\n");
654 erts_fprintf(stderr, " see the erts_alloc(3) documentation for more info\n");
655 erts_fprintf(stderr, "\n");
656
657 erts_fprintf(stderr, "-pc <set> control what characters are considered printable (default latin1)\n");
658 erts_fprintf(stderr, "-P number set maximum number of processes on this node;\n");
659 erts_fprintf(stderr, " valid range is [%d-%d]\n",
660 ERTS_MIN_PROCESSES, ERTS_MAX_PROCESSES);
661 erts_fprintf(stderr, "\n");
662
663 erts_fprintf(stderr, "-Q number set maximum number of ports on this node;\n");
664 erts_fprintf(stderr, " valid range is [%d-%d]\n",
665 ERTS_MIN_PORTS, ERTS_MAX_PORTS);
666 erts_fprintf(stderr, "\n");
667
668 erts_fprintf(stderr, "-R number set compatibility release number;\n");
669 erts_fprintf(stderr, " valid range [%d-%d]\n",
670 this_rel-2, this_rel);
671 erts_fprintf(stderr, "-r force ets memory block to be moved on realloc\n");
672 erts_fprintf(stderr, "-rg amount set reader groups limit\n");
673 erts_fprintf(stderr, "\n");
674
675 erts_fprintf(stderr, "-sbt type set scheduler bind type; valid types are:\n");
676 erts_fprintf(stderr, " u | ns | ts | ps | s | nnts | nnps| tnnps | db\n");
677 erts_fprintf(stderr, "-sbwt val set scheduler busy wait threshold; valid values are:\n");
678 erts_fprintf(stderr, " none | very_short | short | medium | long | very_long\n");
679 erts_fprintf(stderr, "-sbwtdcpu val set dirty CPU scheduler busy wait threshold; valid values are:\n");
680 erts_fprintf(stderr, " none | very_short | short | medium | long | very_long\n");
681 erts_fprintf(stderr, "-sbwtdio val set dirty IO scheduler busy wait threshold; valid values are:\n");
682 erts_fprintf(stderr, " none | very_short | short | medium | long | very_long\n");
683 erts_fprintf(stderr, "-scl bool enable/disable compaction of scheduler load\n");
684 erts_fprintf(stderr, "-sct cput set cpu topology\n");
685 erts_fprintf(stderr, "-secio bool enable or disable eager check I/O scheduling\n");
686 #if ERTS_HAVE_SCHED_UTIL_BALANCING_SUPPORT_OPT
687 erts_fprintf(stderr, "-sub bool enable or disable scheduler utilization balancing\n");
688 #else
689 erts_fprintf(stderr, "-sub false disable scheduler utilization balancing\n");
690 #endif
691 erts_fprintf(stderr, "-sws val set scheduler wakeup strategy; valid values are:\n");
692 erts_fprintf(stderr, " default | legacy\n");
693 erts_fprintf(stderr, "-swct val set scheduler wake cleanup threshold; valid values are:\n");
694 erts_fprintf(stderr, " very_lazy | lazy | medium | eager | very_eager\n");
695 erts_fprintf(stderr, "-swt val set scheduler wakeup threshold; valid values are:\n");
696 erts_fprintf(stderr, " very_low | low | medium | high | very_high\n");
697 erts_fprintf(stderr, "-swtdcpu val set dirty CPU scheduler wakeup threshold; valid values are:\n");
698 erts_fprintf(stderr, " very_low | low | medium | high | very_high\n");
699 erts_fprintf(stderr, "-swtdio val set dirty IO scheduler wakeup threshold; valid values are:\n");
700 erts_fprintf(stderr, " very_low | low | medium | high | very_high\n");
701 erts_fprintf(stderr, "-sss size suggest stack size in kilo words for scheduler threads;\n");
702 erts_fprintf(stderr, " valid range is [%d-%d] (default %d)\n",
703 ERTS_SCHED_THREAD_MIN_STACK_SIZE,
704 ERTS_SCHED_THREAD_MAX_STACK_SIZE,
705 ERTS_DEFAULT_SCHED_STACK_SIZE);
706 erts_fprintf(stderr, "-sssdcpu size suggest stack size in kilo words for dirty CPU scheduler\n");
707 erts_fprintf(stderr, " threads; valid range is [%d-%d] (default %d)\n",
708 ERTS_SCHED_THREAD_MIN_STACK_SIZE,
709 ERTS_SCHED_THREAD_MAX_STACK_SIZE,
710 ERTS_DEFAULT_DCPU_SCHED_STACK_SIZE);
711 erts_fprintf(stderr, "-sssdio size suggest stack size in kilo words for dirty IO scheduler\n");
712 erts_fprintf(stderr, " threads; valid range is [%d-%d] (default %d)\n",
713 ERTS_SCHED_THREAD_MIN_STACK_SIZE,
714 ERTS_SCHED_THREAD_MAX_STACK_SIZE,
715 ERTS_DEFAULT_DIO_SCHED_STACK_SIZE);
716 erts_fprintf(stderr, "-spp Bool set port parallelism scheduling hint\n");
717 erts_fprintf(stderr, "-S n1:n2 set number of schedulers (n1), and number of\n");
718 erts_fprintf(stderr, " schedulers online (n2); maximum for both\n");
719 erts_fprintf(stderr, " numbers is %d\n",
720 ERTS_MAX_NO_OF_SCHEDULERS);
721 erts_fprintf(stderr, "-SP p1:p2 specify schedulers (p1) and schedulers online (p2)\n");
722 erts_fprintf(stderr, " as percentages of logical processors configured and logical\n");
723 erts_fprintf(stderr, " processors available, respectively\n");
724 erts_fprintf(stderr, "-SDcpu n1:n2 set number of dirty CPU schedulers (n1), and number of\n");
725 erts_fprintf(stderr, " dirty CPU schedulers online (n2); valid range for both\n");
726 erts_fprintf(stderr, " numbers is [1-%d], and n2 must be less than or equal to n1\n",
727 ERTS_MAX_NO_OF_DIRTY_CPU_SCHEDULERS);
728 erts_fprintf(stderr, "-SDPcpu p1:p2 specify dirty CPU schedulers (p1) and dirty CPU schedulers\n");
729 erts_fprintf(stderr, " online (p2) as percentages of logical processors configured\n");
730 erts_fprintf(stderr, " and logical processors available, respectively\n");
731 erts_fprintf(stderr, "-SDio n set number of dirty I/O schedulers; valid range is [1-%d]\n",
732 ERTS_MAX_NO_OF_DIRTY_IO_SCHEDULERS);
733 erts_fprintf(stderr, "-t size set the maximum number of atoms the emulator can handle;\n");
734 erts_fprintf(stderr, " valid range is [%d-%d]\n",
735 MIN_ATOM_TABLE_SIZE, MAX_ATOM_TABLE_SIZE);
736 erts_fprintf(stderr, "\n");
737
738 erts_fprintf(stderr, "-T number set modified timing level; valid range is [0-%d]\n",
739 ERTS_MODIFIED_TIMING_LEVELS-1);
740 erts_fprintf(stderr, "\n");
741
742 erts_fprintf(stderr, "-V print Erlang version\n");
743 erts_fprintf(stderr, "-v turn on chatty mode (GCs will be reported etc)\n");
744 erts_fprintf(stderr, "\n");
745
746 erts_fprintf(stderr, "-W<i|w|e> set error logger warnings mapping;\n");
747 erts_fprintf(stderr, " see error_logger documentation for details\n");
748 erts_fprintf(stderr, "\n");
749
750 erts_fprintf(stderr, "-zdbbl size set the distribution buffer busy limit in kilobytes;\n");
751 erts_fprintf(stderr, " valid range is [1-%d]\n", INT_MAX/1024);
752 erts_fprintf(stderr, "-zdntgc time set delayed node table gc in seconds;\n");
753 erts_fprintf(stderr, " valid values are infinity or integers in the range [0-%d]\n",
754 ERTS_NODE_TAB_DELAY_GC_MAX);
755 erts_fprintf(stderr, "\n");
756 erts_fprintf(stderr, "Note that if the emulator is started with erlexec (typically\n");
757 erts_fprintf(stderr, "from the erl script), these flags should be specified with +.\n");
758 erts_fprintf(stderr, "\n\n");
759 erts_exit(1, "");
760 }
761
762 /*
763 * allocators for thread lib
764 */
765
ethr_std_alloc(size_t size)766 static void *ethr_std_alloc(size_t size)
767 {
768 return erts_alloc_fnf(ERTS_ALC_T_ETHR_STD, (Uint) size);
769 }
ethr_std_realloc(void * ptr,size_t size)770 static void *ethr_std_realloc(void *ptr, size_t size)
771 {
772 return erts_realloc_fnf(ERTS_ALC_T_ETHR_STD, ptr, (Uint) size);
773 }
ethr_std_free(void * ptr)774 static void ethr_std_free(void *ptr)
775 {
776 erts_free(ERTS_ALC_T_ETHR_STD, ptr);
777 }
ethr_sl_alloc(size_t size)778 static void *ethr_sl_alloc(size_t size)
779 {
780 return erts_alloc_fnf(ERTS_ALC_T_ETHR_SL, (Uint) size);
781 }
ethr_sl_realloc(void * ptr,size_t size)782 static void *ethr_sl_realloc(void *ptr, size_t size)
783 {
784 return erts_realloc_fnf(ERTS_ALC_T_ETHR_SL, ptr, (Uint) size);
785 }
ethr_sl_free(void * ptr)786 static void ethr_sl_free(void *ptr)
787 {
788 erts_free(ERTS_ALC_T_ETHR_SL, ptr);
789 }
ethr_ll_alloc(size_t size)790 static void *ethr_ll_alloc(size_t size)
791 {
792 return erts_alloc_fnf(ERTS_ALC_T_ETHR_LL, (Uint) size);
793 }
ethr_ll_realloc(void * ptr,size_t size)794 static void *ethr_ll_realloc(void *ptr, size_t size)
795 {
796 return erts_realloc_fnf(ERTS_ALC_T_ETHR_LL, ptr, (Uint) size);
797 }
ethr_ll_free(void * ptr)798 static void ethr_ll_free(void *ptr)
799 {
800 erts_free(ERTS_ALC_T_ETHR_LL, ptr);
801 }
802
803
804 static int
early_init(int * argc,char ** argv)805 early_init(int *argc, char **argv) /*
806 * Only put things here which are
807 * really important initialize
808 * early!
809 */
810 {
811 ErtsAllocInitOpts alloc_opts = ERTS_ALLOC_INIT_DEF_OPTS_INITER;
812 int ncpu;
813 int ncpuonln;
814 int ncpuavail;
815 int ncpuquota;
816 int schdlrs;
817 int schdlrs_onln;
818 int schdlrs_percentage = 100;
819 int schdlrs_onln_percentage = 100;
820 int max_main_threads;
821 int dirty_cpu_scheds;
822 int dirty_cpu_scheds_online;
823 int dirty_cpu_scheds_pctg = 100;
824 int dirty_cpu_scheds_onln_pctg = 100;
825 int dirty_io_scheds;
826 int max_reader_groups;
827 int reader_groups;
828 int max_decentralized_counter_groups;
829 int decentralized_counter_groups;
830 char envbuf[21]; /* enough for any 64-bit integer */
831 size_t envbufsz;
832
833 erts_save_emu_args(*argc, argv);
834
835 erts_sched_compact_load = 1;
836 erts_printf_eterm_func = erts_printf_term;
837 erts_backtrace_depth = DEFAULT_BACKTRACE_SIZE;
838 erts_async_max_threads = ERTS_DEFAULT_NO_ASYNC_THREADS;
839 erts_async_thread_suggested_stack_size = ERTS_ASYNC_THREAD_MIN_STACK_SIZE;
840 H_MIN_SIZE = H_DEFAULT_SIZE;
841 BIN_VH_MIN_SIZE = VH_DEFAULT_SIZE;
842 H_MAX_SIZE = H_DEFAULT_MAX_SIZE;
843 H_MAX_FLAGS = MAX_HEAP_SIZE_KILL|MAX_HEAP_SIZE_LOG;
844
845 erts_term_init();
846
847 erts_initialized = 0;
848
849 erts_pre_early_init_cpu_topology(&max_decentralized_counter_groups,
850 &max_reader_groups,
851 &ncpu,
852 &ncpuonln,
853 &ncpuavail,
854 &ncpuquota);
855
856 ignore_break = 0;
857 replace_intr = 0;
858 program = argv[0];
859
860 erts_modified_timing_level = -1;
861
862 erts_compat_rel = this_rel_num();
863
864 erts_sys_pre_init();
865 erts_atomic_init_nob(&exiting, 0);
866 erts_thr_progress_pre_init();
867
868 erts_atomic32_init_nob(&erts_writing_erl_crash_dump, 0L);
869 erts_tsd_key_create(&erts_is_crash_dumping_key,"erts_is_crash_dumping_key");
870
871 erts_atomic32_init_nob(&erts_max_gen_gcs,
872 (erts_aint32_t) ((Uint16) -1));
873
874 erts_pre_init_process();
875
876 /*
877 * We need to know the number of schedulers to use before we
878 * can initialize the allocators.
879 */
880 no_schedulers = (Uint) (ncpu > 0 ? ncpu : 1);
881
882 if (ncpuavail > 0) {
883 if (ncpuquota > 0) {
884 no_schedulers_online = MIN(ncpuquota, ncpuavail);
885 } else {
886 no_schedulers_online = ncpuavail;
887 }
888 } else if (ncpuonln > 0) {
889 no_schedulers_online = ncpuonln;
890 } else {
891 no_schedulers_online = no_schedulers;
892 }
893
894 schdlrs = no_schedulers;
895 schdlrs_onln = no_schedulers_online;
896
897 dirty_cpu_scheds = no_schedulers;
898 dirty_cpu_scheds_online = no_schedulers_online;
899 dirty_io_scheds = 10;
900
901 envbufsz = sizeof(envbuf);
902
903 /* erts_osenv hasn't been initialized yet, so we need to fall back to
904 * erts_sys_explicit_host_getenv() */
905 if (erts_sys_explicit_host_getenv("ERL_THREAD_POOL_SIZE", envbuf, &envbufsz) == 1)
906 erts_async_max_threads = atoi(envbuf);
907 else
908 erts_async_max_threads = ERTS_DEFAULT_NO_ASYNC_THREADS;
909 if (erts_async_max_threads > ERTS_MAX_NO_OF_ASYNC_THREADS)
910 erts_async_max_threads = ERTS_MAX_NO_OF_ASYNC_THREADS;
911
912 if (argc && argv) {
913 int i = 1;
914 while (i < *argc) {
915 if (sys_strcmp(argv[i], "--") == 0) { /* end of emulator options */
916 i++;
917 break;
918 }
919 if (argv[i][0] == '-') {
920 switch (argv[i][1]) {
921 case 'd': {
922 char *sub_param = argv[i]+2;
923 if (has_prefix("cg", sub_param)) {
924 char *arg = get_arg(sub_param+2, argv[i+1], &i);
925 if (sscanf(arg, "%d", &max_decentralized_counter_groups) != 1) {
926 erts_fprintf(stderr,
927 "bad decentralized counter groups limit: %s\n", arg);
928 erts_usage();
929 }
930 if (max_decentralized_counter_groups < 0) {
931 erts_fprintf(stderr,
932 "bad decentralized counter groups limit: %d\n",
933 max_decentralized_counter_groups);
934 erts_usage();
935 }
936 }
937 break;
938 }
939 case 'r': {
940 char *sub_param = argv[i]+2;
941 if (has_prefix("g", sub_param)) {
942 char *arg = get_arg(sub_param+1, argv[i+1], &i);
943 if (sscanf(arg, "%d", &max_reader_groups) != 1) {
944 erts_fprintf(stderr,
945 "bad reader groups limit: %s\n", arg);
946 erts_usage();
947 }
948 if (max_reader_groups < 0) {
949 erts_fprintf(stderr,
950 "bad reader groups limit: %d\n",
951 max_reader_groups);
952 erts_usage();
953 }
954 }
955 break;
956 }
957 case 'A': {
958 /* set number of threads in thread pool */
959 char *arg = get_arg(argv[i]+2, argv[i+1], &i);
960 if (((erts_async_max_threads = atoi(arg)) < ERTS_MIN_NO_OF_ASYNC_THREADS) ||
961 (erts_async_max_threads > ERTS_MAX_NO_OF_ASYNC_THREADS)) {
962 erts_fprintf(stderr,
963 "bad number of async threads %s\n",
964 arg);
965 erts_usage();
966 VERBOSE(DEBUG_SYSTEM, ("using %d async-threads\n",
967 erts_async_max_threads));
968 }
969 break;
970 }
971
972 case 'S' :
973 if (argv[i][2] == 'P') {
974 int ptot, ponln;
975 char *arg = get_arg(argv[i]+3, argv[i+1], &i);
976 switch (sscanf(arg, "%d:%d", &ptot, &ponln)) {
977 case 0:
978 switch (sscanf(arg, ":%d", &ponln)) {
979 case 1:
980 if (ponln < 0)
981 goto bad_SP;
982 ptot = 100;
983 goto chk_SP;
984 default:
985 goto bad_SP;
986 }
987 case 1:
988 if (ptot < 0)
989 goto bad_SP;
990 ponln = ptot < 100 ? ptot : 100;
991 goto chk_SP;
992 case 2:
993 if (ptot < 0 || ponln < 0)
994 goto bad_SP;
995 chk_SP:
996 schdlrs_percentage = ptot;
997 schdlrs_onln_percentage = ponln;
998 break;
999 default:
1000 bad_SP:
1001 erts_fprintf(stderr,
1002 "bad schedulers percentage specifier %s\n",
1003 arg);
1004 erts_usage();
1005 break;
1006 }
1007
1008 VERBOSE(DEBUG_SYSTEM,
1009 ("using %d:%d scheduler percentages\n",
1010 schdlrs_percentage, schdlrs_onln_percentage));
1011 }
1012 else if (argv[i][2] == 'D') {
1013 char *arg;
1014 char *type = argv[i]+3;
1015 if (sys_strncmp(type, "Pcpu", 4) == 0) {
1016 int ptot, ponln;
1017 arg = get_arg(argv[i]+7, argv[i+1], &i);
1018 switch (sscanf(arg, "%d:%d", &ptot, &ponln)) {
1019 case 0:
1020 switch (sscanf(arg, ":%d", &ponln)) {
1021 case 1:
1022 if (ponln < 0)
1023 goto bad_SDPcpu;
1024 ptot = 100;
1025 goto chk_SDPcpu;
1026 default:
1027 goto bad_SDPcpu;
1028 }
1029 case 1:
1030 if (ptot < 0)
1031 goto bad_SDPcpu;
1032 ponln = ptot < 100 ? ptot : 100;
1033 goto chk_SDPcpu;
1034 case 2:
1035 if (ptot < 0 || ponln < 0)
1036 goto bad_SDPcpu;
1037 chk_SDPcpu:
1038 dirty_cpu_scheds_pctg = ptot;
1039 dirty_cpu_scheds_onln_pctg = ponln;
1040 break;
1041 default:
1042 bad_SDPcpu:
1043 erts_fprintf(stderr,
1044 "bad dirty CPU schedulers percentage specifier %s\n",
1045 arg);
1046 erts_usage();
1047 break;
1048 }
1049 VERBOSE(DEBUG_SYSTEM,
1050 ("using %d:%d dirty CPU scheduler percentages\n",
1051 dirty_cpu_scheds_pctg, dirty_cpu_scheds_onln_pctg));
1052 } else if (sys_strncmp(type, "cpu", 3) == 0) {
1053 int tot, onln;
1054 arg = get_arg(argv[i]+6, argv[i+1], &i);
1055 switch (sscanf(arg, "%d:%d", &tot, &onln)) {
1056 case 0:
1057 switch (sscanf(arg, ":%d", &onln)) {
1058 case 1:
1059 tot = no_schedulers;
1060 goto chk_SDcpu;
1061 default:
1062 goto bad_SDcpu;
1063 }
1064 case 1:
1065 onln = tot < dirty_cpu_scheds_online ?
1066 tot : dirty_cpu_scheds_online;
1067 case 2:
1068 chk_SDcpu:
1069 if (tot > 0)
1070 dirty_cpu_scheds = tot;
1071 else
1072 dirty_cpu_scheds = no_schedulers + tot;
1073 if (onln > 0)
1074 dirty_cpu_scheds_online = onln;
1075 else
1076 dirty_cpu_scheds_online = no_schedulers_online + onln;
1077 if (dirty_cpu_scheds < 1 ||
1078 ERTS_MAX_NO_OF_DIRTY_CPU_SCHEDULERS < dirty_cpu_scheds) {
1079 erts_fprintf(stderr,
1080 "bad amount of dirty CPU schedulers %d\n",
1081 tot);
1082 erts_usage();
1083 }
1084 if (dirty_cpu_scheds_online < 1 ||
1085 dirty_cpu_scheds < dirty_cpu_scheds_online) {
1086 erts_fprintf(stderr,
1087 "bad amount of dirty CPU schedulers online %d "
1088 "(total amount of dirty CPU schedulers %d)\n",
1089 dirty_cpu_scheds_online, dirty_cpu_scheds);
1090 erts_usage();
1091 }
1092 break;
1093 default:
1094 bad_SDcpu:
1095 erts_fprintf(stderr,
1096 "bad amount of dirty CPU schedulers %s\n",
1097 arg);
1098 erts_usage();
1099 break;
1100 }
1101 VERBOSE(DEBUG_SYSTEM,
1102 ("using %d:%d dirty CPU scheduler(s)\n", tot, onln));
1103 } else if (sys_strncmp(type, "io", 2) == 0) {
1104 arg = get_arg(argv[i]+5, argv[i+1], &i);
1105 dirty_io_scheds = atoi(arg);
1106 if (dirty_io_scheds < 1 ||
1107 dirty_io_scheds > ERTS_MAX_NO_OF_DIRTY_IO_SCHEDULERS) {
1108 erts_fprintf(stderr,
1109 "bad number of dirty I/O schedulers %s\n",
1110 arg);
1111 erts_usage();
1112 }
1113 VERBOSE(DEBUG_SYSTEM,
1114 ("using %d dirty I/O scheduler(s)\n", dirty_io_scheds));
1115 } else {
1116 erts_fprintf(stderr,
1117 "bad or missing dirty scheduler specifier: %s\n",
1118 argv[i]);
1119 erts_usage();
1120 break;
1121 }
1122 }
1123 else {
1124 int tot, onln;
1125 char *arg = get_arg(argv[i]+2, argv[i+1], &i);
1126 switch (sscanf(arg, "%d:%d", &tot, &onln)) {
1127 case 0:
1128 switch (sscanf(arg, ":%d", &onln)) {
1129 case 1:
1130 tot = no_schedulers;
1131 goto chk_S;
1132 default:
1133 goto bad_S;
1134 }
1135 case 1:
1136 onln = tot < schdlrs_onln ? tot : schdlrs_onln;
1137 case 2:
1138 chk_S:
1139 if (tot > 0)
1140 schdlrs = tot;
1141 else
1142 schdlrs = no_schedulers + tot;
1143 if (onln > 0)
1144 schdlrs_onln = onln;
1145 else
1146 schdlrs_onln = no_schedulers_online + onln;
1147 if (schdlrs < 1 || ERTS_MAX_NO_OF_SCHEDULERS < schdlrs) {
1148 erts_fprintf(stderr,
1149 "bad amount of schedulers %d\n",
1150 tot);
1151 erts_usage();
1152 }
1153 if (schdlrs_onln < 1 || schdlrs < schdlrs_onln) {
1154 erts_fprintf(stderr,
1155 "bad amount of schedulers online %d "
1156 "(total amount of schedulers %d)\n",
1157 schdlrs_onln, schdlrs);
1158 erts_usage();
1159 }
1160 break;
1161 default:
1162 bad_S:
1163 erts_fprintf(stderr,
1164 "bad amount of schedulers %s\n",
1165 arg);
1166 erts_usage();
1167 break;
1168 }
1169
1170 VERBOSE(DEBUG_SYSTEM,
1171 ("using %d:%d scheduler(s)\n", tot, onln));
1172 }
1173 break;
1174 default:
1175 break;
1176 }
1177 }
1178 i++;
1179 }
1180
1181 if (erts_async_max_threads < 1)
1182 erts_async_max_threads = 1;
1183
1184 /* apply any scheduler percentages */
1185 if (schdlrs_percentage != 100 || schdlrs_onln_percentage != 100) {
1186 schdlrs = schdlrs * schdlrs_percentage / 100;
1187 schdlrs_onln = schdlrs_onln * schdlrs_onln_percentage / 100;
1188 if (schdlrs < 1)
1189 schdlrs = 1;
1190 if (ERTS_MAX_NO_OF_SCHEDULERS < schdlrs) {
1191 erts_fprintf(stderr,
1192 "bad schedulers percentage %d "
1193 "(total amount of schedulers %d)\n",
1194 schdlrs_percentage, schdlrs);
1195 erts_usage();
1196 }
1197 if (schdlrs_onln < 1)
1198 schdlrs_onln = 1;
1199 if (schdlrs < schdlrs_onln) {
1200 erts_fprintf(stderr,
1201 "bad schedulers online percentage %d "
1202 "(total amount of schedulers %d, online %d)\n",
1203 schdlrs_onln_percentage, schdlrs, schdlrs_onln);
1204 erts_usage();
1205 }
1206 }
1207 /* apply any dirty scheduler precentages */
1208 if (dirty_cpu_scheds_pctg != 100 || dirty_cpu_scheds_onln_pctg != 100) {
1209 dirty_cpu_scheds = dirty_cpu_scheds * dirty_cpu_scheds_pctg / 100;
1210 dirty_cpu_scheds_online = dirty_cpu_scheds_online * dirty_cpu_scheds_onln_pctg / 100;
1211 }
1212 if (dirty_cpu_scheds > schdlrs)
1213 dirty_cpu_scheds = schdlrs;
1214 if (dirty_cpu_scheds < 1)
1215 dirty_cpu_scheds = 1;
1216 if (dirty_cpu_scheds_online > schdlrs_onln)
1217 dirty_cpu_scheds_online = schdlrs_onln;
1218 if (dirty_cpu_scheds_online < 1)
1219 dirty_cpu_scheds_online = 1;
1220 }
1221
1222
1223 no_schedulers = schdlrs;
1224 no_schedulers_online = schdlrs_onln;
1225
1226 erts_no_schedulers = (Uint) no_schedulers;
1227 erts_no_dirty_cpu_schedulers = no_dirty_cpu_schedulers = dirty_cpu_scheds;
1228 no_dirty_cpu_schedulers_online = dirty_cpu_scheds_online;
1229 erts_no_dirty_io_schedulers = no_dirty_io_schedulers = dirty_io_scheds;
1230 erts_early_init_scheduling(no_schedulers);
1231
1232 alloc_opts.ncpu = ncpu;
1233 erts_alloc_init(argc, argv, &alloc_opts); /* Handles (and removes)
1234 -M flags. */
1235 /* Require allocators */
1236
1237 erts_init_check_io(argc, argv);
1238
1239 /*
1240 * Thread progress management:
1241 *
1242 * * Managed threads:
1243 * ** Scheduler threads (see erl_process.c)
1244 * ** Aux thread (see erl_process.c)
1245 * ** Sys message dispatcher thread (see erl_trace.c)
1246 * ** IO Poll threads (see erl_check_io.c)
1247 *
1248 * * Unmanaged threads that need to register:
1249 * ** Async threads (see erl_async.c)
1250 * ** Dirty scheduler threads
1251 */
1252 erts_thr_progress_init(no_schedulers,
1253 no_schedulers+2+erts_no_poll_threads,
1254 erts_async_max_threads +
1255 erts_no_dirty_cpu_schedulers +
1256 erts_no_dirty_io_schedulers
1257 );
1258 erts_thr_q_init();
1259 erts_init_utils();
1260 erts_early_init_cpu_topology(no_schedulers,
1261 &max_main_threads,
1262 max_reader_groups,
1263 &reader_groups,
1264 max_decentralized_counter_groups,
1265 &decentralized_counter_groups);
1266 erts_flxctr_setup(decentralized_counter_groups);
1267 {
1268 erts_thr_late_init_data_t elid = ERTS_THR_LATE_INIT_DATA_DEF_INITER;
1269 elid.mem.std.alloc = ethr_std_alloc;
1270 elid.mem.std.realloc = ethr_std_realloc;
1271 elid.mem.std.free = ethr_std_free;
1272 elid.mem.sl.alloc = ethr_sl_alloc;
1273 elid.mem.sl.realloc = ethr_sl_realloc;
1274 elid.mem.sl.free = ethr_sl_free;
1275 elid.mem.ll.alloc = ethr_ll_alloc;
1276 elid.mem.ll.realloc = ethr_ll_realloc;
1277 elid.mem.ll.free = ethr_ll_free;
1278 elid.main_threads = max_main_threads;
1279 elid.reader_groups = reader_groups;
1280
1281 erts_thr_late_init(&elid);
1282 }
1283 erts_msacc_early_init();
1284
1285 #ifdef ERTS_ENABLE_LOCK_CHECK
1286 erts_lc_late_init();
1287 #endif
1288
1289 #ifdef ERTS_ENABLE_LOCK_COUNT
1290 erts_lcnt_late_init();
1291 #endif
1292
1293 erl_sys_args(argc, argv);
1294
1295 /* Creates threads on Windows that depend on the arguments, so has to be after erl_sys_args */
1296 erl_sys_init();
1297
1298 erts_ets_realloc_always_moves = 0;
1299 erts_ets_always_compress = 0;
1300 erts_dist_buf_busy_limit = ERTS_DE_BUSY_LIMIT;
1301
1302 return ncpu;
1303 }
1304
1305
1306 void
erl_start(int argc,char ** argv)1307 erl_start(int argc, char **argv)
1308 {
1309 int i = 1;
1310 char* arg=NULL;
1311 int have_break_handler = 1;
1312 char envbuf[21]; /* enough for any 64-bit integer */
1313 size_t envbufsz;
1314 int ncpu = early_init(&argc, argv);
1315 int proc_tab_sz = ERTS_DEFAULT_MAX_PROCESSES;
1316 int port_tab_sz = ERTS_DEFAULT_MAX_PORTS;
1317 int port_tab_sz_ignore_files = 0;
1318 int legacy_proc_tab = 0;
1319 int legacy_port_tab = 0;
1320 int time_correction;
1321 ErtsTimeWarpMode time_warp_mode;
1322 int node_tab_delete_delay = ERTS_NODE_TAB_DELAY_GC_DEFAULT;
1323 ErtsDbSpinCount db_spin_count = ERTS_DB_SPNCNT_NORMAL;
1324
1325 set_default_time_adj(&time_correction,
1326 &time_warp_mode);
1327
1328 envbufsz = sizeof(envbuf);
1329 if (erts_sys_explicit_8bit_getenv(ERL_MAX_ETS_TABLES_ENV, envbuf, &envbufsz) == 1)
1330 user_requested_db_max_tabs = atoi(envbuf);
1331 else
1332 user_requested_db_max_tabs = 0;
1333
1334 envbufsz = sizeof(envbuf);
1335 if (erts_sys_explicit_8bit_getenv("ERL_FULLSWEEP_AFTER", envbuf, &envbufsz) == 1) {
1336 Uint16 max_gen_gcs = atoi(envbuf);
1337 erts_atomic32_set_nob(&erts_max_gen_gcs,
1338 (erts_aint32_t) max_gen_gcs);
1339 }
1340
1341 envbufsz = sizeof(envbuf);
1342 if (erts_sys_explicit_8bit_getenv("ERL_MAX_PORTS", envbuf, &envbufsz) == 1) {
1343 port_tab_sz = atoi(envbuf);
1344 port_tab_sz_ignore_files = 1;
1345 }
1346
1347 /*
1348 * A default stack size suitable for pcre which might use quite
1349 * a lot of stack.
1350 */
1351 erts_sched_thread_suggested_stack_size = ERTS_DEFAULT_SCHED_STACK_SIZE;
1352 erts_dcpu_sched_thread_suggested_stack_size = ERTS_DEFAULT_DCPU_SCHED_STACK_SIZE;
1353 erts_dio_sched_thread_suggested_stack_size = ERTS_DEFAULT_DIO_SCHED_STACK_SIZE;
1354
1355 #ifdef DEBUG
1356 verbose = DEBUG_DEFAULT;
1357 #endif
1358
1359 erts_error_logger_warnings = am_warning;
1360
1361 while (i < argc) {
1362 if (argv[i][0] != '-') {
1363 erts_usage();
1364 }
1365 if (sys_strcmp(argv[i], "--") == 0) { /* end of emulator options */
1366 i++;
1367 break;
1368 }
1369 switch (argv[i][1]) {
1370
1371 /*
1372 * NOTE: -M flags are handled (and removed from argv) by
1373 * erts_alloc_init().
1374 */
1375
1376 case 'p':
1377 if (!sys_strncmp(argv[i],"-pc",3)) {
1378 int printable_chars = ERL_PRINTABLE_CHARACTERS_LATIN1;
1379 arg = get_arg(argv[i]+3, argv[i+1], &i);
1380 if (!sys_strcmp(arg,"unicode")) {
1381 printable_chars = ERL_PRINTABLE_CHARACTERS_UNICODE;
1382 } else if (sys_strcmp(arg,"latin1")) {
1383 erts_fprintf(stderr, "bad range of printable "
1384 "characters: %s\n", arg);
1385 erts_usage();
1386 }
1387 erts_set_printable_characters(printable_chars);
1388 break;
1389 } else {
1390 erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]);
1391 erts_usage();
1392 }
1393 case 'f':
1394 if (!sys_strncmp(argv[i],"-fn",3)) {
1395 int warning_type = ERL_FILENAME_WARNING_WARNING;
1396 arg = get_arg(argv[i]+3, argv[i+1], &i);
1397 switch (*arg) {
1398 case 'u':
1399 switch (*(arg+1)) {
1400 case 'w':
1401 case 0:
1402 break;
1403 case 'i':
1404 warning_type = ERL_FILENAME_WARNING_IGNORE;
1405 break;
1406 case 'e':
1407 warning_type = ERL_FILENAME_WARNING_ERROR;
1408 break;
1409 default:
1410 erts_fprintf(stderr, "bad type of warnings for "
1411 "wrongly coded filename: %s\n", arg+1);
1412 erts_usage();
1413 }
1414 erts_set_user_requested_filename_encoding
1415 (
1416 ERL_FILENAME_UTF8,
1417 warning_type
1418 );
1419 break;
1420 case 'l':
1421 erts_set_user_requested_filename_encoding
1422 (
1423 ERL_FILENAME_LATIN1,
1424 warning_type
1425 );
1426 break;
1427 case 'a':
1428 switch (*(arg+1)) {
1429 case 'w':
1430 case 0:
1431 break;
1432 case 'i':
1433 warning_type = ERL_FILENAME_WARNING_IGNORE;
1434 break;
1435 case 'e':
1436 warning_type = ERL_FILENAME_WARNING_ERROR;
1437 break;
1438 default:
1439 erts_fprintf(stderr, "bad type of warnings for "
1440 "wrongly coded filename: %s\n", arg+1);
1441 erts_usage();
1442 }
1443 erts_set_user_requested_filename_encoding
1444 (
1445 ERL_FILENAME_UNKNOWN,
1446 warning_type
1447 );
1448 break;
1449 default:
1450 erts_fprintf(stderr, "bad filename encoding %s, can be "
1451 "(l,u or a, optionally followed by w, "
1452 "i or e)\n", arg);
1453 erts_usage();
1454 }
1455 break;
1456 } else {
1457 erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]);
1458 erts_usage();
1459 }
1460 case 'L':
1461 erts_no_line_info = 1;
1462 break;
1463 case 'v':
1464 #ifdef DEBUG
1465 if (argv[i][2] == '\0') {
1466 verbose |= DEBUG_SYSTEM;
1467 } else {
1468 char *ch;
1469 for (ch = argv[i]+2; *ch != '\0'; ch++) {
1470 switch (*ch) {
1471 case 's': verbose |= DEBUG_SYSTEM; break;
1472 case 'g': verbose |= DEBUG_PRIVATE_GC; break;
1473 case 'M': verbose |= DEBUG_MEMORY; break;
1474 case 'a': verbose |= DEBUG_ALLOCATION; break;
1475 case 't': verbose |= DEBUG_THREADS; break;
1476 case 'p': verbose |= DEBUG_PROCESSES; break;
1477 case 'm': verbose |= DEBUG_MESSAGES; break;
1478 case 'c': verbose |= DEBUG_SHCOPY; break;
1479 default : erts_fprintf(stderr,"Unknown verbose option: %c\n",*ch);
1480 }
1481 }
1482 }
1483 erts_printf("Verbose level: ");
1484 if (verbose & DEBUG_SYSTEM) erts_printf("SYSTEM ");
1485 if (verbose & DEBUG_PRIVATE_GC) erts_printf("PRIVATE_GC ");
1486 if (verbose & DEBUG_MEMORY) erts_printf("PARANOID_MEMORY ");
1487 if (verbose & DEBUG_ALLOCATION) erts_printf("ALLOCATION ");
1488 if (verbose & DEBUG_THREADS) erts_printf("THREADS ");
1489 if (verbose & DEBUG_PROCESSES) erts_printf("PROCESSES ");
1490 if (verbose & DEBUG_MESSAGES) erts_printf("MESSAGES ");
1491 if (verbose & DEBUG_SHCOPY) erts_printf("SHCOPY ");
1492 erts_printf("\n");
1493 #else
1494 erts_fprintf(stderr, "warning: -v (only in debug compiled code)\n");
1495 #endif
1496 break;
1497 case 'V' :
1498 {
1499 char tmp[256];
1500
1501 tmp[0] = tmp[1] = '\0';
1502 #ifdef DEBUG
1503 strcat(tmp, ",DEBUG");
1504 #endif
1505 strcat(tmp, ",SMP");
1506 strcat(tmp, ",ASYNC_THREADS");
1507 erts_fprintf(stderr, "Erlang ");
1508 if (tmp[1]) {
1509 erts_fprintf(stderr, "(%s) ", tmp+1);
1510 }
1511 erts_fprintf(stderr, "(" EMULATOR ") emulator version "
1512 ERLANG_VERSION "\n");
1513 erts_exit(0, "");
1514 }
1515 break;
1516
1517 case 'H': /* undocumented */
1518 fprintf(stderr, "The undocumented +H option has been removed (R10B-6).\n\n");
1519 break;
1520
1521 case 'h': {
1522 char *sub_param = argv[i]+2;
1523 /* set default heap size
1524 *
1525 * h|ms - min_heap_size
1526 * h|mbs - min_bin_vheap_size
1527 * h|pds - erts_pd_initial_size
1528 * h|mqd - message_queue_data
1529 * h|max - max_heap_size
1530 * h|maxk - max_heap_kill
1531 * h|maxel - max_heap_error_logger
1532 *
1533 */
1534 if (has_prefix("mbs", sub_param)) {
1535 arg = get_arg(sub_param+3, argv[i+1], &i);
1536 if ((BIN_VH_MIN_SIZE = atoi(arg)) <= 0) {
1537 erts_fprintf(stderr, "bad heap size %s\n", arg);
1538 erts_usage();
1539 }
1540 VERBOSE(DEBUG_SYSTEM, ("using minimum binary virtual heap size %d\n", BIN_VH_MIN_SIZE));
1541
1542 } else if (has_prefix("ms", sub_param)) {
1543 arg = get_arg(sub_param+2, argv[i+1], &i);
1544 if ((H_MIN_SIZE = atoi(arg)) <= 0) {
1545 erts_fprintf(stderr, "bad heap size %s\n", arg);
1546 erts_usage();
1547 }
1548 VERBOSE(DEBUG_SYSTEM, ("using minimum heap size %d\n", H_MIN_SIZE));
1549 } else if (has_prefix("pds", sub_param)) {
1550 arg = get_arg(sub_param+3, argv[i+1], &i);
1551 if (!erts_pd_set_initial_size(atoi(arg))) {
1552 erts_fprintf(stderr, "bad initial process dictionary size %s\n", arg);
1553 erts_usage();
1554 }
1555 VERBOSE(DEBUG_SYSTEM, ("using initial process dictionary size %d\n",
1556 erts_pd_initial_size));
1557 } else if (has_prefix("mqd", sub_param)) {
1558 arg = get_arg(sub_param+3, argv[i+1], &i);
1559 if (sys_strcmp(arg, "on_heap") == 0) {
1560 erts_default_spo_flags &= ~SPO_OFF_HEAP_MSGQ;
1561 erts_default_spo_flags |= SPO_ON_HEAP_MSGQ;
1562 }
1563 else if (sys_strcmp(arg, "off_heap") == 0) {
1564 erts_default_spo_flags &= ~SPO_ON_HEAP_MSGQ;
1565 erts_default_spo_flags |= SPO_OFF_HEAP_MSGQ;
1566 }
1567 else {
1568 erts_fprintf(stderr,
1569 "Invalid message_queue_data flag: %s\n", arg);
1570 erts_usage();
1571 }
1572 } else if (has_prefix("maxk", sub_param)) {
1573 arg = get_arg(sub_param+4, argv[i+1], &i);
1574 if (sys_strcmp(arg,"true") == 0) {
1575 H_MAX_FLAGS |= MAX_HEAP_SIZE_KILL;
1576 } else if (sys_strcmp(arg,"false") == 0) {
1577 H_MAX_FLAGS &= ~MAX_HEAP_SIZE_KILL;
1578 } else {
1579 erts_fprintf(stderr, "bad max heap kill %s\n", arg);
1580 erts_usage();
1581 }
1582 VERBOSE(DEBUG_SYSTEM, ("using max heap kill %d\n", H_MAX_FLAGS));
1583 } else if (has_prefix("maxel", sub_param)) {
1584 arg = get_arg(sub_param+5, argv[i+1], &i);
1585 if (sys_strcmp(arg,"true") == 0) {
1586 H_MAX_FLAGS |= MAX_HEAP_SIZE_LOG;
1587 } else if (sys_strcmp(arg,"false") == 0) {
1588 H_MAX_FLAGS &= ~MAX_HEAP_SIZE_LOG;
1589 } else {
1590 erts_fprintf(stderr, "bad max heap error logger %s\n", arg);
1591 erts_usage();
1592 }
1593 VERBOSE(DEBUG_SYSTEM, ("using max heap log %d\n", H_MAX_FLAGS));
1594 } else if (has_prefix("max", sub_param)) {
1595 arg = get_arg(sub_param+3, argv[i+1], &i);
1596 if ((H_MAX_SIZE = atoi(arg)) < 0) {
1597 erts_fprintf(stderr, "bad max heap size %s\n", arg);
1598 erts_usage();
1599 }
1600 if (H_MAX_SIZE < H_MIN_SIZE && H_MAX_SIZE) {
1601 erts_fprintf(stderr, "max heap size (%s) is not allowed to be "
1602 "smaller than min heap size (%d)\n",
1603 arg, H_MIN_SIZE);
1604 erts_usage();
1605 }
1606 VERBOSE(DEBUG_SYSTEM, ("using max heap size %d\n", H_MAX_SIZE));
1607 } else {
1608 /* backward compatibility */
1609 arg = get_arg(argv[i]+2, argv[i+1], &i);
1610 if ((H_MIN_SIZE = atoi(arg)) <= 0) {
1611 erts_fprintf(stderr, "bad heap size %s\n", arg);
1612 erts_usage();
1613 }
1614 VERBOSE(DEBUG_SYSTEM, ("using minimum heap size %d\n", H_MIN_SIZE));
1615 }
1616 break;
1617 }
1618 case 'd':
1619 /*
1620 * Never produce crash dumps for internally detected
1621 * errors; only produce a core dump. (Generation of
1622 * crash dumps is destructive and makes it impossible
1623 * to inspect the contents of process heaps in the
1624 * core dump.)
1625 */
1626 erts_no_crash_dump = 1;
1627 break;
1628
1629 case 'e':
1630 if (sys_strcmp("c", argv[i]+2) == 0) {
1631 erts_ets_always_compress = 1;
1632 }
1633 else {
1634 /* set maximum number of ets tables */
1635 arg = get_arg(argv[i]+2, argv[i+1], &i);
1636 if (( user_requested_db_max_tabs = atoi(arg) ) < 0) {
1637 erts_fprintf(stderr, "bad maximum number of ets tables %s\n", arg);
1638 erts_usage();
1639 }
1640 VERBOSE(DEBUG_SYSTEM,
1641 ("using maximum number of ets tables %d\n",
1642 user_requested_db_max_tabs));
1643 }
1644 break;
1645
1646 case 'i':
1647 /* define name of module for initial function */
1648 init = get_arg(argv[i]+2, argv[i+1], &i);
1649 break;
1650
1651 case 'J':
1652 #ifdef BEAMASM
1653 {
1654 char *sub_param = argv[i]+2;
1655
1656 switch (sub_param[0])
1657 {
1658 case 'D':
1659 sub_param++;
1660 if (has_prefix("dump", sub_param)) {
1661 arg = get_arg(sub_param+4, argv[i + 1], &i);
1662 if (sys_strcmp(arg, "true") == 0) {
1663 erts_jit_asm_dump = 1;
1664 } else if (sys_strcmp(arg, "false") == 0) {
1665 erts_jit_asm_dump = 0;
1666 } else {
1667 erts_fprintf(stderr, "bad +JDdump flag %s\n", arg);
1668 erts_usage();
1669 }
1670 }
1671 break;
1672 case 'P':
1673 sub_param++;
1674
1675 if (has_prefix("perf", sub_param)) {
1676 arg = get_arg(sub_param+4, argv[i + 1], &i);
1677
1678 #ifdef HAVE_LINUX_PERF_SUPPORT
1679 if (sys_strcmp(arg, "true") == 0) {
1680 erts_jit_perf_support = BEAMASM_PERF_DUMP|BEAMASM_PERF_MAP;
1681 } else if (sys_strcmp(arg, "false") == 0) {
1682 erts_jit_perf_support = 0;
1683 } else if (sys_strcmp(arg, "dump") == 0) {
1684 erts_jit_perf_support = BEAMASM_PERF_DUMP;
1685 } else if (sys_strcmp(arg, "map") == 0) {
1686 erts_jit_perf_support = BEAMASM_PERF_MAP;
1687 } else {
1688 erts_fprintf(stderr, "bad +JPperf support flag %s\n", arg);
1689 erts_usage();
1690 }
1691 #else
1692 erts_fprintf(stderr, "+JPperf is not supported on this platform\n");
1693 erts_usage();
1694 #endif
1695 }
1696 break;
1697 default:
1698 erts_fprintf(stderr, "invalid JIT option %s\n", argv[i]);
1699 break;
1700 }
1701 }
1702 #else
1703 erts_fprintf(stderr,
1704 "JIT is not supported on this system (option %s)\n",
1705 argv[i]);
1706 erts_usage();
1707 #endif
1708 break;
1709
1710 case 'B':
1711 if (argv[i][2] == 'i') /* +Bi */
1712 ignore_break = 1;
1713 else if (argv[i][2] == 'c') /* +Bc */
1714 replace_intr = 1;
1715 else if (argv[i][2] == 'd') /* +Bd */
1716 have_break_handler = 0;
1717 else if (argv[i+1][0] == 'i') { /* +B i */
1718 get_arg(argv[i]+2, argv[i+1], &i);
1719 ignore_break = 1;
1720 }
1721 else if (argv[i+1][0] == 'c') { /* +B c */
1722 get_arg(argv[i]+2, argv[i+1], &i);
1723 replace_intr = 1;
1724 }
1725 else if (argv[i+1][0] == 'd') { /* +B d */
1726 get_arg(argv[i]+2, argv[i+1], &i);
1727 have_break_handler = 0;
1728 }
1729 else /* +B */
1730 have_break_handler = 0;
1731 break;
1732
1733 case 'n':
1734 arg = get_arg(argv[i]+2, argv[i+1], &i);
1735 switch (arg[0]) {
1736 case 's': /* synchronous */
1737 erts_port_synchronous_ops = 1;
1738 erts_port_schedule_all_ops = 0;
1739 break;
1740 case 'a': /* asynchronous */
1741 erts_port_synchronous_ops = 0;
1742 erts_port_schedule_all_ops = 1;
1743 break;
1744 case 'd': /* Default - schedule on conflict (asynchronous) */
1745 erts_port_synchronous_ops = 0;
1746 erts_port_schedule_all_ops = 0;
1747 break;
1748 default:
1749 bad_n_option:
1750 erts_fprintf(stderr, "bad -n option %s\n", arg);
1751 erts_usage();
1752 }
1753 if (arg[1] != '\0')
1754 goto bad_n_option;
1755 break;
1756
1757 case 'P': /* set maximum number of processes */
1758 arg = get_arg(argv[i]+2, argv[i+1], &i);
1759 if (sys_strcmp(arg, "legacy") == 0)
1760 legacy_proc_tab = 1;
1761 else {
1762 errno = 0;
1763 proc_tab_sz = strtol(arg, NULL, 10);
1764 if (errno != 0
1765 || proc_tab_sz < ERTS_MIN_PROCESSES
1766 || ERTS_MAX_PROCESSES < proc_tab_sz) {
1767 erts_fprintf(stderr, "bad number of processes %s\n", arg);
1768 erts_usage();
1769 }
1770 }
1771 break;
1772
1773 case 'Q': /* set maximum number of ports */
1774 arg = get_arg(argv[i]+2, argv[i+1], &i);
1775 if (sys_strcmp(arg, "legacy") == 0)
1776 legacy_port_tab = 1;
1777 else {
1778 errno = 0;
1779 port_tab_sz = strtol(arg, NULL, 10);
1780 if (errno != 0
1781 || port_tab_sz < ERTS_MIN_PROCESSES
1782 || ERTS_MAX_PROCESSES < port_tab_sz) {
1783 erts_fprintf(stderr, "bad number of ports %s\n", arg);
1784 erts_usage();
1785 }
1786 port_tab_sz_ignore_files = 1;
1787 }
1788 break;
1789
1790 case 'S' : /* Was handled in early_init() just read past it */
1791 if (argv[i][2] == 'D') {
1792 char* type = argv[i]+3;
1793 if (sys_strcmp(type, "Pcpu") == 0)
1794 (void) get_arg(argv[i]+7, argv[i+1], &i);
1795 if (sys_strcmp(type, "cpu") == 0)
1796 (void) get_arg(argv[i]+6, argv[i+1], &i);
1797 else if (sys_strcmp(type, "io") == 0)
1798 (void) get_arg(argv[i]+5, argv[i+1], &i);
1799 } else if (argv[i][2] == 'P')
1800 (void) get_arg(argv[i]+3, argv[i+1], &i);
1801 else
1802 (void) get_arg(argv[i]+2, argv[i+1], &i);
1803 break;
1804
1805 case 's' : {
1806 char *estr;
1807 int res;
1808 char *sub_param = argv[i]+2;
1809 if (has_prefix("bt", sub_param)) {
1810 arg = get_arg(sub_param+2, argv[i+1], &i);
1811 res = erts_init_scheduler_bind_type_string(arg);
1812 if (res != ERTS_INIT_SCHED_BIND_TYPE_SUCCESS) {
1813 switch (res) {
1814 case ERTS_INIT_SCHED_BIND_TYPE_NOT_SUPPORTED:
1815 estr = "not supported";
1816 break;
1817 case ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY:
1818 estr = "no cpu topology available";
1819 break;
1820 case ERTS_INIT_SCHED_BIND_TYPE_ERROR_BAD_TYPE:
1821 estr = "invalid type";
1822 break;
1823 default:
1824 estr = "undefined error";
1825 break;
1826 }
1827 erts_fprintf(stderr,
1828 "setting scheduler bind type '%s' failed: %s\n",
1829 arg,
1830 estr);
1831 erts_usage();
1832 }
1833 }
1834 else if (has_prefix("bwtdcpu", sub_param)) {
1835 arg = get_arg(sub_param + 7, argv[i+1], &i);
1836
1837 if (erts_sched_set_busy_wait_threshold(ERTS_SCHED_DIRTY_CPU, arg) != 0) {
1838 erts_fprintf(stderr, "bad dirty CPU scheduler busy wait threshold: %s\n",
1839 arg);
1840 erts_usage();
1841 }
1842
1843 VERBOSE(DEBUG_SYSTEM,
1844 ("dirty CPU scheduler wakeup threshold: %s\n", arg));
1845 }
1846 else if (has_prefix("bwtdio", sub_param)) {
1847 arg = get_arg(sub_param + 6, argv[i+1], &i);
1848
1849 if (erts_sched_set_busy_wait_threshold(ERTS_SCHED_DIRTY_IO, arg) != 0) {
1850 erts_fprintf(stderr, "bad dirty IO scheduler busy wait threshold: %s\n",
1851 arg);
1852 erts_usage();
1853 }
1854
1855 VERBOSE(DEBUG_SYSTEM,
1856 ("dirty IO scheduler wakeup threshold: %s\n", arg));
1857 }
1858 else if (has_prefix("bwt", sub_param)) {
1859 arg = get_arg(sub_param + 3, argv[i+1], &i);
1860
1861 if (erts_sched_set_busy_wait_threshold(ERTS_SCHED_NORMAL, arg) != 0) {
1862 erts_fprintf(stderr, "bad scheduler busy wait threshold: %s\n",
1863 arg);
1864 erts_usage();
1865 }
1866
1867 VERBOSE(DEBUG_SYSTEM,
1868 ("scheduler wakeup threshold: %s\n", arg));
1869 }
1870 else if (has_prefix("cl", sub_param)) {
1871 arg = get_arg(sub_param+2, argv[i+1], &i);
1872 if (sys_strcmp("true", arg) == 0) {
1873 erts_sched_compact_load = 1;
1874 erts_sched_balance_util = 0;
1875 }
1876 else if (sys_strcmp("false", arg) == 0)
1877 erts_sched_compact_load = 0;
1878 else {
1879 erts_fprintf(stderr,
1880 "bad scheduler compact load value '%s'\n",
1881 arg);
1882 erts_usage();
1883 }
1884 }
1885 else if (has_prefix("ct", sub_param)) {
1886 arg = get_arg(sub_param+2, argv[i+1], &i);
1887 res = erts_init_cpu_topology_string(arg);
1888 if (res != ERTS_INIT_CPU_TOPOLOGY_OK) {
1889 switch (res) {
1890 case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID:
1891 estr = "invalid identifier";
1892 break;
1893 case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE:
1894 estr = "invalid identifier range";
1895 break;
1896 case ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY:
1897 estr = "invalid hierarchy";
1898 break;
1899 case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_TYPE:
1900 estr = "invalid identifier type";
1901 break;
1902 case ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES:
1903 estr = "invalid nodes declaration";
1904 break;
1905 case ERTS_INIT_CPU_TOPOLOGY_MISSING_LID:
1906 estr = "missing logical identifier";
1907 break;
1908 case ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_LIDS:
1909 estr = "not unique logical identifiers";
1910 break;
1911 case ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_ENTITIES:
1912 estr = "not unique entities";
1913 break;
1914 case ERTS_INIT_CPU_TOPOLOGY_MISSING:
1915 estr = "missing cpu topology";
1916 break;
1917 default:
1918 estr = "undefined error";
1919 break;
1920 }
1921 erts_fprintf(stderr,
1922 "bad cpu topology '%s': %s\n",
1923 arg,
1924 estr);
1925 erts_usage();
1926 }
1927 }
1928 else if (has_prefix("ecio", sub_param)) {
1929 /* ignore argument, eager check io no longer used */
1930 arg = get_arg(sub_param+4, argv[i+1], &i);
1931 }
1932 else if (has_prefix("pp", sub_param)) {
1933 arg = get_arg(sub_param+2, argv[i+1], &i);
1934 if (sys_strcmp(arg, "true") == 0)
1935 erts_port_parallelism = 1;
1936 else if (sys_strcmp(arg, "false") == 0)
1937 erts_port_parallelism = 0;
1938 else {
1939 erts_fprintf(stderr,
1940 "bad port parallelism scheduling hint %s\n",
1941 arg);
1942 erts_usage();
1943 }
1944 }
1945 else if (has_prefix("tbt", sub_param)) {
1946 arg = get_arg(sub_param+3, argv[i+1], &i);
1947 res = erts_init_scheduler_bind_type_string(arg);
1948 if (res == ERTS_INIT_SCHED_BIND_TYPE_ERROR_BAD_TYPE) {
1949 erts_fprintf(stderr,
1950 "setting scheduler bind type '%s' failed: invalid type\n",
1951 arg);
1952 erts_usage();
1953 }
1954 }
1955 else if (has_prefix("ub", sub_param)) {
1956 arg = get_arg(sub_param+2, argv[i+1], &i);
1957 if (sys_strcmp("true", arg) == 0) {
1958 #if ERTS_HAVE_SCHED_UTIL_BALANCING_SUPPORT_OPT
1959 erts_sched_balance_util = 1;
1960 #else
1961 erts_fprintf(stderr,
1962 "scheduler utilization balancing not "
1963 "supported on this system\n");
1964 erts_usage();
1965 #endif
1966 }
1967 else if (sys_strcmp("false", arg) == 0)
1968 erts_sched_balance_util = 0;
1969 else {
1970 erts_fprintf(stderr, "bad scheduler utilization balancing "
1971 " value '%s'\n", arg);
1972 erts_usage();
1973 }
1974 }
1975 else if (has_prefix("wct", sub_param)) {
1976 arg = get_arg(sub_param+3, argv[i+1], &i);
1977 if (erts_sched_set_wake_cleanup_threshold(arg) != 0) {
1978 erts_fprintf(stderr, "scheduler wake cleanup threshold: %s\n",
1979 arg);
1980 erts_usage();
1981 }
1982 VERBOSE(DEBUG_SYSTEM,
1983 ("scheduler wake cleanup threshold: %s\n", arg));
1984 }
1985 else if (has_prefix("wtdcpu", sub_param)) {
1986 arg = get_arg(sub_param+6, argv[i+1], &i);
1987 if (erts_sched_set_wakeup_other_threshold(ERTS_SCHED_DIRTY_CPU, arg) != 0) {
1988 erts_fprintf(stderr, "dirty CPU scheduler wakeup threshold: %s\n",
1989 arg);
1990 erts_usage();
1991 }
1992 VERBOSE(DEBUG_SYSTEM,
1993 ("dirty CPU scheduler wakeup threshold: %s\n", arg));
1994 }
1995 else if (has_prefix("wtdio", sub_param)) {
1996 arg = get_arg(sub_param+5, argv[i+1], &i);
1997 if (erts_sched_set_wakeup_other_threshold(ERTS_SCHED_DIRTY_IO, arg) != 0) {
1998 erts_fprintf(stderr, "dirty IO scheduler wakeup threshold: %s\n",
1999 arg);
2000 erts_usage();
2001 }
2002 VERBOSE(DEBUG_SYSTEM,
2003 ("dirty IO scheduler wakeup threshold: %s\n", arg));
2004 }
2005 else if (has_prefix("wt", sub_param)) {
2006 arg = get_arg(sub_param+2, argv[i+1], &i);
2007 if (erts_sched_set_wakeup_other_threshold(ERTS_SCHED_NORMAL, arg) != 0) {
2008 erts_fprintf(stderr, "scheduler wakeup threshold: %s\n",
2009 arg);
2010 erts_usage();
2011 }
2012 VERBOSE(DEBUG_SYSTEM,
2013 ("scheduler wakeup threshold: %s\n", arg));
2014 }
2015 else if (has_prefix("ws", sub_param)) {
2016 arg = get_arg(sub_param+2, argv[i+1], &i);
2017 if (erts_sched_set_wakeup_other_type(ERTS_SCHED_NORMAL, arg) != 0) {
2018 erts_fprintf(stderr, "scheduler wakeup strategy: %s\n",
2019 arg);
2020 erts_usage();
2021 }
2022 VERBOSE(DEBUG_SYSTEM,
2023 ("scheduler wakeup threshold: %s\n", arg));
2024 }
2025 else if (has_prefix("ssdcpu", sub_param)) {
2026 /* suggested stack size (Kilo Words) for dirty CPU scheduler threads */
2027 arg = get_arg(sub_param+6, argv[i+1], &i);
2028 erts_dcpu_sched_thread_suggested_stack_size = atoi(arg);
2029
2030 if ((erts_dcpu_sched_thread_suggested_stack_size
2031 < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
2032 || (erts_dcpu_sched_thread_suggested_stack_size >
2033 ERTS_SCHED_THREAD_MAX_STACK_SIZE)) {
2034 erts_fprintf(stderr, "bad stack size for dirty CPU scheduler threads %s\n",
2035 arg);
2036 erts_usage();
2037 }
2038 VERBOSE(DEBUG_SYSTEM,
2039 ("suggested dirty CPU scheduler thread stack size %d kilo words\n",
2040 erts_dcpu_sched_thread_suggested_stack_size));
2041 }
2042 else if (has_prefix("ssdio", sub_param)) {
2043 /* suggested stack size (Kilo Words) for dirty IO scheduler threads */
2044 arg = get_arg(sub_param+5, argv[i+1], &i);
2045 erts_dio_sched_thread_suggested_stack_size = atoi(arg);
2046
2047 if ((erts_dio_sched_thread_suggested_stack_size
2048 < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
2049 || (erts_dio_sched_thread_suggested_stack_size >
2050 ERTS_SCHED_THREAD_MAX_STACK_SIZE)) {
2051 erts_fprintf(stderr, "bad stack size for dirty IO scheduler threads %s\n",
2052 arg);
2053 erts_usage();
2054 }
2055 VERBOSE(DEBUG_SYSTEM,
2056 ("suggested dirty IO scheduler thread stack size %d kilo words\n",
2057 erts_dio_sched_thread_suggested_stack_size));
2058 }
2059 else if (has_prefix("ss", sub_param)) {
2060 /* suggested stack size (Kilo Words) for scheduler threads */
2061 arg = get_arg(sub_param+2, argv[i+1], &i);
2062 erts_sched_thread_suggested_stack_size = atoi(arg);
2063 modified_sched_thread_suggested_stack_size = 1;
2064
2065 if ((erts_sched_thread_suggested_stack_size
2066 < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
2067 || (erts_sched_thread_suggested_stack_size >
2068 ERTS_SCHED_THREAD_MAX_STACK_SIZE)) {
2069 erts_fprintf(stderr, "bad stack size for scheduler threads %s\n",
2070 arg);
2071 erts_usage();
2072 }
2073 VERBOSE(DEBUG_SYSTEM,
2074 ("suggested scheduler thread stack size %d kilo words\n",
2075 erts_sched_thread_suggested_stack_size));
2076 }
2077 else if (has_prefix("fwi", sub_param)) {
2078 long val;
2079 arg = get_arg(sub_param+3, argv[i+1], &i);
2080 errno = 0;
2081 val = strtol(arg, NULL, 10);
2082 if (errno != 0 || val < 0) {
2083 erts_fprintf(stderr,
2084 "bad scheduler forced wakeup "
2085 "interval %s\n",
2086 arg);
2087 erts_usage();
2088 }
2089 erts_runq_supervision_interval = val;
2090 }
2091 else {
2092 erts_fprintf(stderr, "bad scheduling option %s\n", argv[i]);
2093 erts_usage();
2094 }
2095 break;
2096 }
2097 case 't':
2098 /* set atom table size */
2099 arg = get_arg(argv[i]+2, argv[i+1], &i);
2100 errno = 0;
2101 erts_atom_table_size = strtol(arg, NULL, 10);
2102 if (errno != 0 ||
2103 erts_atom_table_size < MIN_ATOM_TABLE_SIZE ||
2104 erts_atom_table_size > MAX_ATOM_TABLE_SIZE) {
2105 erts_fprintf(stderr, "bad atom table size %s\n", arg);
2106 erts_usage();
2107 }
2108 VERBOSE(DEBUG_SYSTEM,
2109 ("setting maximum number of atoms to %d\n",
2110 erts_atom_table_size));
2111 break;
2112
2113 case 'T' :
2114 arg = get_arg(argv[i]+2, argv[i+1], &i);
2115 errno = 0;
2116 erts_modified_timing_level = atoi(arg);
2117 if ((erts_modified_timing_level == 0 && errno != 0)
2118 || erts_modified_timing_level < 0
2119 || erts_modified_timing_level >= ERTS_MODIFIED_TIMING_LEVELS) {
2120 erts_fprintf(stderr, "bad modified timing level %s\n", arg);
2121 erts_usage();
2122 }
2123 else {
2124 VERBOSE(DEBUG_SYSTEM,
2125 ("using modified timing level %d\n",
2126 erts_modified_timing_level));
2127 }
2128
2129 break;
2130
2131 case 'R': {
2132 /* set compatibility release */
2133 int this_rel;
2134
2135 arg = get_arg(argv[i]+2, argv[i+1], &i);
2136 erts_compat_rel = atoi(arg);
2137
2138 this_rel = this_rel_num();
2139 if (erts_compat_rel < this_rel - 2 || this_rel < erts_compat_rel) {
2140 erts_fprintf(stderr, "bad compatibility release number %s\n", arg);
2141 erts_usage();
2142 }
2143
2144 switch (erts_compat_rel) {
2145 /* Currently no compat features... */
2146 default:
2147 break;
2148 }
2149
2150 break;
2151 }
2152
2153 case 'A': /* Was handled in early init just read past it */
2154 (void) get_arg(argv[i]+2, argv[i+1], &i);
2155 break;
2156
2157 case 'a':
2158 /* suggested stack size (Kilo Words) for threads in thread pool */
2159 arg = get_arg(argv[i]+2, argv[i+1], &i);
2160 erts_async_thread_suggested_stack_size = atoi(arg);
2161
2162 if ((erts_async_thread_suggested_stack_size
2163 < ERTS_ASYNC_THREAD_MIN_STACK_SIZE)
2164 || (erts_async_thread_suggested_stack_size >
2165 ERTS_ASYNC_THREAD_MAX_STACK_SIZE)) {
2166 erts_fprintf(stderr, "bad stack size for async threads %s\n",
2167 arg);
2168 erts_usage();
2169 }
2170
2171 VERBOSE(DEBUG_SYSTEM,
2172 ("suggested async-thread stack size %d kilo words\n",
2173 erts_async_thread_suggested_stack_size));
2174 break;
2175
2176 case 'r': {
2177 char *sub_param = argv[i]+2;
2178 if (has_prefix("g", sub_param)) {
2179 get_arg(sub_param+1, argv[i+1], &i);
2180 /* already handled */
2181 }
2182 else {
2183 erts_ets_realloc_always_moves = 1;
2184 }
2185 break;
2186 }
2187 case 'C':
2188 arg = get_arg(argv[i]+2, argv[i+1], &i);
2189 if (sys_strcmp(arg, "no_time_warp") == 0)
2190 time_warp_mode = ERTS_NO_TIME_WARP_MODE;
2191 else if (sys_strcmp(arg, "single_time_warp") == 0)
2192 time_warp_mode = ERTS_SINGLE_TIME_WARP_MODE;
2193 else if (sys_strcmp(arg, "multi_time_warp") == 0)
2194 time_warp_mode = ERTS_MULTI_TIME_WARP_MODE;
2195 else {
2196 erts_fprintf(stderr,
2197 "Invalid time warp mode: %s\n", arg);
2198 erts_usage();
2199 }
2200 break;
2201 case 'c':
2202 if (sys_strcmp(argv[i]+2, "false") == 0)
2203 goto time_correction_false;
2204 else if (sys_strcmp(argv[i]+2, "true") == 0)
2205 goto time_correction_true;
2206 else if (argv[i][2] == '\0') {
2207 if (i + 1 >= argc)
2208 goto time_correction_false;
2209 else {
2210 if (sys_strcmp(argv[i+1], "false") == 0) {
2211 (void) get_arg(argv[i]+2, argv[i+1], &i);
2212 goto time_correction_false;
2213 }
2214 else if (sys_strcmp(argv[i+1], "true") == 0) {
2215 (void) get_arg(argv[i]+2, argv[i+1], &i);
2216 time_correction_true:
2217 time_correction = 1;
2218 break;
2219 }
2220 else {
2221 time_correction_false:
2222 time_correction = 0;
2223 break;
2224 }
2225 }
2226 }
2227 else {
2228 arg = get_arg(argv[i]+2, argv[i+1], &i);
2229 erts_fprintf(stderr, "Invalid time correnction value: %s\n", arg);
2230 erts_usage();
2231 }
2232 break;
2233 case 'W':
2234 arg = get_arg(argv[i]+2, argv[i+1], &i);
2235 switch (arg[0]) {
2236 case 'i':
2237 erts_error_logger_warnings = am_info;
2238 break;
2239 case 'e':
2240 erts_error_logger_warnings = am_error;
2241 break;
2242 case 'w':
2243 erts_error_logger_warnings = am_warning;
2244 break;
2245 default:
2246 erts_fprintf(stderr, "unrecognized warning_map option %s\n", arg);
2247 erts_usage();
2248 }
2249 break;
2250
2251 case 'z': {
2252 char *sub_param = argv[i]+2;
2253
2254 if (has_prefix("dbbl", sub_param)) {
2255 int new_limit;
2256 arg = get_arg(sub_param+4, argv[i+1], &i);
2257 new_limit = atoi(arg);
2258 if (new_limit < 1 || INT_MAX/1024 < new_limit) {
2259 erts_fprintf(stderr, "Invalid dbbl limit: %d\n", new_limit);
2260 erts_usage();
2261 } else {
2262 erts_dist_buf_busy_limit = new_limit*1024;
2263 }
2264 }
2265 else if (has_prefix("dntgc", sub_param)) {
2266 long secs;
2267
2268 arg = get_arg(sub_param+5, argv[i+1], &i);
2269 if (sys_strcmp(arg, "infinity") == 0)
2270 secs = ERTS_NODE_TAB_DELAY_GC_INFINITY;
2271 else {
2272 char *endptr;
2273 errno = 0;
2274 secs = strtol(arg, &endptr, 10);
2275 if (errno != 0 || *arg == '\0' || *endptr != '\0'
2276 || secs < 0 || ERTS_NODE_TAB_DELAY_GC_MAX < secs) {
2277 erts_fprintf(stderr, "Invalid delayed node table gc: %s\n", arg);
2278 erts_usage();
2279 }
2280 }
2281 node_tab_delete_delay = (int) secs;
2282 }
2283 else if (has_prefix("ebwt", sub_param)) {
2284 arg = get_arg(sub_param+4, argv[i+1], &i);
2285 if (sys_strcmp(arg, "none") == 0)
2286 db_spin_count = ERTS_DB_SPNCNT_NONE;
2287 else if (sys_strcmp(arg, "very_short") == 0)
2288 db_spin_count = ERTS_DB_SPNCNT_VERY_LOW;
2289 else if (sys_strcmp(arg, "short") == 0)
2290 db_spin_count = ERTS_DB_SPNCNT_LOW;
2291 else if (sys_strcmp(arg, "medium") == 0)
2292 db_spin_count = ERTS_DB_SPNCNT_NORMAL;
2293 else if (sys_strcmp(arg, "long") == 0)
2294 db_spin_count = ERTS_DB_SPNCNT_HIGH;
2295 else if (sys_strcmp(arg, "very_long") == 0)
2296 db_spin_count = ERTS_DB_SPNCNT_VERY_HIGH;
2297 else if (sys_strcmp(arg, "extremely_long") == 0)
2298 db_spin_count = ERTS_DB_SPNCNT_EXTREMELY_HIGH;
2299 else {
2300 erts_fprintf(stderr,
2301 "Invalid ets busy wait threshold: %s\n", arg);
2302 erts_usage();
2303 }
2304 }
2305 else {
2306 erts_fprintf(stderr, "bad -z option %s\n", argv[i]);
2307 erts_usage();
2308 }
2309 break;
2310 }
2311
2312 default:
2313 erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]);
2314 erts_usage();
2315 }
2316 i++;
2317 }
2318
2319 if (!erts_check_time_adj_support(time_correction, time_warp_mode)) {
2320 char *time_correction_str = time_correction ? "Enabled" : "Disabled";
2321 char *time_warp_str = "undefined";
2322 switch (time_warp_mode) {
2323 case ERTS_NO_TIME_WARP_MODE:
2324 time_warp_str = "no";
2325 break;
2326 case ERTS_SINGLE_TIME_WARP_MODE:
2327 time_warp_str = "single";
2328 break;
2329 case ERTS_MULTI_TIME_WARP_MODE:
2330 time_warp_str = "multi";
2331 break;
2332 default:
2333 time_warp_str = "undefined";
2334 break;
2335 }
2336 erts_fprintf(stderr, "%s time correction with %s time warp mode "
2337 "is not supported on this platform\n",
2338 time_correction_str,
2339 time_warp_str);
2340 erts_usage();
2341 }
2342
2343 /* Output format on windows for sprintf defaults to three exponents.
2344 * We use two-exponent to mimic normal sprintf behaviour.
2345 */
2346
2347 #if defined(__WIN32__) && defined(_TWO_DIGIT_EXPONENT)
2348 _set_output_format(_TWO_DIGIT_EXPONENT);
2349 #endif
2350
2351 /* Restart will not reinstall the break handler */
2352 #ifdef __WIN32__
2353 if (ignore_break)
2354 erts_set_ignore_break();
2355 else if (replace_intr)
2356 erts_replace_intr();
2357 else
2358 init_break_handler();
2359 #else
2360 if (ignore_break)
2361 erts_set_ignore_break();
2362 else if (have_break_handler)
2363 init_break_handler();
2364 if (replace_intr)
2365 erts_replace_intr();
2366 #endif
2367
2368 boot_argc = argc - i; /* Number of arguments to init */
2369 boot_argv = &argv[i];
2370
2371 if (erts_sched_thread_suggested_stack_size < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
2372 erts_sched_thread_suggested_stack_size = ERTS_SCHED_THREAD_MIN_STACK_SIZE;
2373 if (erts_dcpu_sched_thread_suggested_stack_size < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
2374 erts_dcpu_sched_thread_suggested_stack_size = ERTS_SCHED_THREAD_MIN_STACK_SIZE;
2375 if (erts_dio_sched_thread_suggested_stack_size < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
2376 erts_dio_sched_thread_suggested_stack_size = ERTS_SCHED_THREAD_MIN_STACK_SIZE;
2377
2378 erl_init(ncpu,
2379 proc_tab_sz,
2380 legacy_proc_tab,
2381 port_tab_sz,
2382 port_tab_sz_ignore_files,
2383 legacy_port_tab,
2384 time_correction,
2385 time_warp_mode,
2386 node_tab_delete_delay,
2387 db_spin_count);
2388
2389 load_preloaded();
2390 erts_end_staging_code_ix();
2391 erts_commit_staging_code_ix();
2392
2393 erts_initialized = 1;
2394
2395 erts_init_process_id = erl_first_process_otp(init, boot_argc, boot_argv);
2396 ASSERT(erts_init_process_id != ERTS_INVALID_PID);
2397
2398 {
2399 /*
2400 * The erts_code_purger and the erts_literal_area_collector
2401 * system processes are *always* alive. If they terminate
2402 * they bring the whole VM down.
2403 */
2404 Eterm pid;
2405
2406 pid = erl_system_process_otp(erts_init_process_id,
2407 "erts_code_purger", !0,
2408 PRIORITY_NORMAL);
2409 erts_code_purger
2410 = (Process *) erts_ptab_pix2intptr_ddrb(&erts_proc,
2411 internal_pid_index(pid));
2412 ASSERT(erts_code_purger && erts_code_purger->common.id == pid);
2413 erts_proc_inc_refc(erts_code_purger);
2414
2415 pid = erl_system_process_otp(erts_init_process_id,
2416 "erts_literal_area_collector",
2417 !0, PRIORITY_NORMAL);
2418 erts_literal_area_collector
2419 = (Process *) erts_ptab_pix2intptr_ddrb(&erts_proc,
2420 internal_pid_index(pid));
2421 ASSERT(erts_literal_area_collector
2422 && erts_literal_area_collector->common.id == pid);
2423 erts_proc_inc_refc(erts_literal_area_collector);
2424
2425 pid = erl_system_process_otp(erts_init_process_id,
2426 "erts_dirty_process_signal_handler",
2427 !0, PRIORITY_NORMAL);
2428 erts_dirty_process_signal_handler
2429 = (Process *) erts_ptab_pix2intptr_ddrb(&erts_proc,
2430 internal_pid_index(pid));
2431 ASSERT(erts_dirty_process_signal_handler
2432 && erts_dirty_process_signal_handler->common.id == pid);
2433 erts_proc_inc_refc(erts_dirty_process_signal_handler);
2434
2435 pid = erl_system_process_otp(erts_init_process_id,
2436 "erts_dirty_process_signal_handler",
2437 !0, PRIORITY_HIGH);
2438 erts_dirty_process_signal_handler_high
2439 = (Process *) erts_ptab_pix2intptr_ddrb(&erts_proc,
2440 internal_pid_index(pid));
2441 ASSERT(erts_dirty_process_signal_handler_high
2442 && erts_dirty_process_signal_handler_high->common.id == pid);
2443 erts_proc_inc_refc(erts_dirty_process_signal_handler_high);
2444
2445 pid = erl_system_process_otp(erts_init_process_id,
2446 "erts_dirty_process_signal_handler",
2447 !0, PRIORITY_MAX);
2448 erts_dirty_process_signal_handler_max
2449 = (Process *) erts_ptab_pix2intptr_ddrb(&erts_proc,
2450 internal_pid_index(pid));
2451 ASSERT(erts_dirty_process_signal_handler_max
2452 && erts_dirty_process_signal_handler_max->common.id == pid);
2453 erts_proc_inc_refc(erts_dirty_process_signal_handler_max);
2454 }
2455
2456 erts_start_schedulers();
2457
2458 #ifdef ERTS_ENABLE_LOCK_COUNT
2459 erts_lcnt_post_startup();
2460 #endif
2461
2462 /* Let system specific code decide what to do with the main thread... */
2463 erts_sys_main_thread(); /* May or may not return! */
2464 }
2465
2466
2467
erts_thr_fatal_error(int err,const char * what)2468 __decl_noreturn void erts_thr_fatal_error(int err, const char *what)
2469 {
2470 const char *errstr = err ? strerror(err) : NULL;
2471 erts_fprintf(stderr,
2472 "Failed to %s: %s%s(%d)\n",
2473 what,
2474 errstr ? errstr : "",
2475 errstr ? " " : "",
2476 err);
2477 abort();
2478 }
2479
2480
2481 static void
system_cleanup(int flush_async)2482 system_cleanup(int flush_async)
2483 {
2484 /*
2485 * Make sure only one thread exits the runtime system.
2486 */
2487 if (erts_atomic_inc_read_nob(&exiting) != 1) {
2488 /*
2489 * Another thread is currently exiting the system;
2490 * wait for it to do its job.
2491 */
2492 if (erts_thr_progress_is_managed_thread()) {
2493 /*
2494 * The exiting thread might be waiting for
2495 * us to block; need to update status...
2496 */
2497 erts_thr_progress_active(erts_thr_prgr_data(NULL), 0);
2498 erts_thr_progress_prepare_wait(erts_thr_prgr_data(NULL));
2499 }
2500 /* Wait forever... */
2501 while (1)
2502 erts_milli_sleep(10000000);
2503 }
2504
2505 /* No cleanup wanted if ...
2506 * 1. we are about to do an abnormal exit
2507 * 2. we haven't finished initializing, or
2508 * 3. another thread than the main thread is performing the exit
2509 * (in threaded non smp case).
2510 */
2511
2512 if (!flush_async
2513 || !erts_initialized
2514 )
2515 return;
2516
2517 #ifdef ERTS_ENABLE_LOCK_CHECK
2518 erts_lc_check_exact(NULL, 0);
2519 #endif
2520
2521 erts_exit_flush_async();
2522 }
2523
2524 static int erts_exit_code;
2525
2526 static __decl_noreturn void __noreturn
erts_exit_vv(int n,int flush_async,const char * fmt,va_list args1,va_list args2)2527 erts_exit_vv(int n, int flush_async, const char *fmt, va_list args1, va_list args2)
2528 {
2529 system_cleanup(flush_async);
2530
2531 if (erts_mtrace_enabled)
2532 erts_mtrace_exit((Uint32) n);
2533
2534 if (fmt != NULL && *fmt != '\0')
2535 erl_error(fmt, args2); /* Print error message. */
2536
2537 erts_exit_code = n;
2538
2539 /* Produce an Erlang crash dump if error */
2540 if (((n == ERTS_ERROR_EXIT && erts_no_crash_dump == 0) || n == ERTS_DUMP_EXIT)
2541 && erts_initialized) {
2542 erl_crash_dump_v((char*) NULL, 0, fmt, args1);
2543 }
2544
2545 erts_exit_epilogue();
2546 }
2547
erts_exit_epilogue(void)2548 __decl_noreturn void __noreturn erts_exit_epilogue(void)
2549 {
2550 int n = erts_exit_code;
2551
2552 sys_tty_reset(n);
2553
2554 if (n == ERTS_INTR_EXIT)
2555 exit(0);
2556 else if (n == ERTS_DUMP_EXIT)
2557 ERTS_EXIT_AFTER_DUMP(1);
2558 else if (n == ERTS_ERROR_EXIT || n == ERTS_ABORT_EXIT)
2559 abort();
2560 exit(n);
2561 }
2562
2563 /* Exit without flushing async threads */
erts_exit(int n,const char * fmt,...)2564 __decl_noreturn void __noreturn erts_exit(int n, const char *fmt, ...)
2565 {
2566 va_list args1, args2;
2567 va_start(args1, fmt);
2568 va_start(args2, fmt);
2569 erts_exit_vv(n, 0, fmt, args1, args2);
2570 va_end(args2);
2571 va_end(args1);
2572 }
2573
2574 /* Exit after flushing async threads */
erts_flush_async_exit(int n,char * fmt,...)2575 __decl_noreturn void __noreturn erts_flush_async_exit(int n, char *fmt, ...)
2576 {
2577 va_list args1, args2;
2578 va_start(args1, fmt);
2579 va_start(args2, fmt);
2580 erts_exit_vv(n, 1, fmt, args1, args2);
2581 va_end(args2);
2582 va_end(args1);
2583 }
2584