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