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