static Eterm staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking, struct m* loaded, int nloaded) { #ifdef ERTS_SMP if (is_blocking || !commit) #endif { if (commit) { erts_end_staging_code_ix(); erts_commit_staging_code_ix(); if (loaded) { int i; for (i=0; i < nloaded; i++) { set_default_trace_pattern(loaded[i].module); } } } else { erts_abort_staging_code_ix(); } if (loaded) { erts_free(ERTS_ALC_T_LOADER_TMP, loaded); } if (is_blocking) { erts_smp_thr_progress_unblock(); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); } erts_release_code_write_permission(); return res; } #ifdef ERTS_SMP else { ErtsThrPrgrVal later; ASSERT(is_value(res)); if (loaded) { erts_free(ERTS_ALC_T_LOADER_TMP, loaded); } erts_end_staging_code_ix(); /* * Now we must wait for all schedulers to do a memory barrier before * we can activate and let them access the new staged code. This allows * schedulers to read active code_ix in a safe way while executing * without any memory barriers at all. */ later = erts_thr_progress_later(); erts_thr_progress_wakeup(c_p->scheduler_data, later); erts_notify_code_ix_activation(c_p, later); erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); /* * handle_code_ix_activation() will do the rest "later" * and resume this process to return 'res'. */ ERTS_BIF_YIELD_RETURN(c_p, res); } #endif }
BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) { #if !defined(HIPE) BIF_ERROR(BIF_P, EXC_NOTSUP); #else Module* modp; Eterm res, mod; if (!ERTS_TERM_IS_MAGIC_BINARY(BIF_ARG_1) || is_not_atom(mod = erts_module_for_prepared_code (((ProcBin*)binary_val(BIF_ARG_1))->val))) { BIF_ERROR(BIF_P, BADARG); } if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD3(bif_export[BIF_code_make_stub_module_3], BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); } erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); modp = erts_get_module(mod, erts_active_code_ix()); if (modp && modp->curr.num_breakpoints > 0) { ASSERT(modp->curr.code_hdr != NULL); erts_clear_module_break(modp); ASSERT(modp->curr.num_breakpoints == 0); } erts_start_staging_code_ix(1); res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); if (res == mod) { erts_end_staging_code_ix(); erts_commit_staging_code_ix(); if (!modp) modp = erts_get_module(mod, erts_active_code_ix()); hipe_redirect_to_module(modp); } else { erts_abort_staging_code_ix(); } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_release_code_write_permission(); return res; #endif }
BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) { Module* modp; Eterm res; if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD3(bif_export[BIF_code_make_stub_module_3], BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); } erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); if (modp && modp->curr.num_breakpoints > 0) { ASSERT(modp->curr.code_hdr != NULL); erts_clear_module_break(modp); ASSERT(modp->curr.num_breakpoints == 0); } erts_start_staging_code_ix(1); res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); if (res == BIF_ARG_1) { erts_end_staging_code_ix(); erts_commit_staging_code_ix(); } else { erts_abort_staging_code_ix(); } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_release_code_write_permission(); return res; }
void erl_start(int argc, char **argv) { int i = 1; char* arg=NULL; char* Parg = NULL; int have_break_handler = 1; char envbuf[21]; /* enough for any 64-bit integer */ size_t envbufsz; int ncpu = early_init(&argc, argv); envbufsz = sizeof(envbuf); if (erts_sys_getenv(ERL_MAX_ETS_TABLES_ENV, envbuf, &envbufsz) == 0) user_requested_db_max_tabs = atoi(envbuf); else user_requested_db_max_tabs = 0; envbufsz = sizeof(envbuf); if (erts_sys_getenv("ERL_FULLSWEEP_AFTER", envbuf, &envbufsz) == 0) { Uint16 max_gen_gcs = atoi(envbuf); erts_smp_atomic32_set_nob(&erts_max_gen_gcs, (erts_aint32_t) max_gen_gcs); } #if (defined(__APPLE__) && defined(__MACH__)) || defined(__DARWIN__) /* * The default stack size on MacOS X is too small for pcre. */ erts_sched_thread_suggested_stack_size = 256; #endif #ifdef DEBUG verbose = DEBUG_DEFAULT; #endif erts_error_logger_warnings = am_error; while (i < argc) { if (argv[i][0] != '-') { erts_usage(); } if (strcmp(argv[i], "--") == 0) { /* end of emulator options */ i++; break; } switch (argv[i][1]) { /* * NOTE: -M flags are handled (and removed from argv) by * erts_alloc_init(). * * The -d, -m, -S, -t, and -T flags was removed in * Erlang 5.3/OTP R9C. * * -S, and -T has been reused in Erlang 5.5/OTP R11B. * * -d has been reused in a patch R12B-4. */ case '#' : arg = get_arg(argv[i]+2, argv[i+1], &i); if ((display_items = atoi(arg)) == 0) { erts_fprintf(stderr, "bad display items%s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("using display items %d\n",display_items)); break; case 'f': if (!strncmp(argv[i],"-fn",3)) { arg = get_arg(argv[i]+3, argv[i+1], &i); switch (*arg) { case 'u': erts_set_user_requested_filename_encoding(ERL_FILENAME_UTF8); break; case 'l': erts_set_user_requested_filename_encoding(ERL_FILENAME_LATIN1); break; case 'a': erts_set_user_requested_filename_encoding(ERL_FILENAME_UNKNOWN); default: erts_fprintf(stderr, "bad filename encoding %s, can be (l,u or a)\n", arg); erts_usage(); } break; } else { erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]); erts_usage(); } case 'L': erts_no_line_info = 1; break; case 'v': #ifdef DEBUG if (argv[i][2] == '\0') { verbose |= DEBUG_SYSTEM; } else { char *ch; for (ch = argv[i]+2; *ch != '\0'; ch++) { switch (*ch) { case 's': verbose |= DEBUG_SYSTEM; break; case 'g': verbose |= DEBUG_PRIVATE_GC; break; case 'M': verbose |= DEBUG_MEMORY; break; case 'a': verbose |= DEBUG_ALLOCATION; break; case 't': verbose |= DEBUG_THREADS; break; case 'p': verbose |= DEBUG_PROCESSES; break; case 'm': verbose |= DEBUG_MESSAGES; break; default : erts_fprintf(stderr,"Unknown verbose option: %c\n",*ch); } } } erts_printf("Verbose level: "); if (verbose & DEBUG_SYSTEM) erts_printf("SYSTEM "); if (verbose & DEBUG_PRIVATE_GC) erts_printf("PRIVATE_GC "); if (verbose & DEBUG_MEMORY) erts_printf("PARANOID_MEMORY "); if (verbose & DEBUG_ALLOCATION) erts_printf("ALLOCATION "); if (verbose & DEBUG_THREADS) erts_printf("THREADS "); if (verbose & DEBUG_PROCESSES) erts_printf("PROCESSES "); if (verbose & DEBUG_MESSAGES) erts_printf("MESSAGES "); erts_printf("\n"); #else erts_fprintf(stderr, "warning: -v (only in debug compiled code)\n"); #endif break; case 'V' : { char tmp[256]; tmp[0] = tmp[1] = '\0'; #ifdef DEBUG strcat(tmp, ",DEBUG"); #endif #ifdef ERTS_SMP strcat(tmp, ",SMP"); #endif #ifdef USE_THREADS strcat(tmp, ",ASYNC_THREADS"); #endif #ifdef HIPE strcat(tmp, ",HIPE"); #endif erts_fprintf(stderr, "Erlang "); if (tmp[1]) { erts_fprintf(stderr, "(%s) ", tmp+1); } erts_fprintf(stderr, "(" EMULATOR ") emulator version " ERLANG_VERSION "\n"); erl_exit(0, ""); } break; case 'H': /* undocumented */ fprintf(stderr, "The undocumented +H option has been removed (R10B-6).\n\n"); break; case 'h': { char *sub_param = argv[i]+2; /* set default heap size * * h|ms - min_heap_size * h|mbs - min_bin_vheap_size * */ if (has_prefix("mbs", sub_param)) { arg = get_arg(sub_param+3, argv[i+1], &i); if ((BIN_VH_MIN_SIZE = atoi(arg)) <= 0) { erts_fprintf(stderr, "bad heap size %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("using minimum binary virtual heap size %d\n", BIN_VH_MIN_SIZE)); } else if (has_prefix("ms", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); if ((H_MIN_SIZE = atoi(arg)) <= 0) { erts_fprintf(stderr, "bad heap size %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("using minimum heap size %d\n", H_MIN_SIZE)); } else { /* backward compatibility */ arg = get_arg(argv[i]+2, argv[i+1], &i); if ((H_MIN_SIZE = atoi(arg)) <= 0) { erts_fprintf(stderr, "bad heap size %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("using minimum heap size %d\n", H_MIN_SIZE)); } break; } case 'd': /* * Never produce crash dumps for internally detected * errors; only produce a core dump. (Generation of * crash dumps is destructive and makes it impossible * to inspect the contents of process heaps in the * core dump.) */ erts_no_crash_dump = 1; break; case 'e': if (sys_strcmp("c", argv[i]+2) == 0) { erts_ets_always_compress = 1; } else { /* set maximum number of ets tables */ arg = get_arg(argv[i]+2, argv[i+1], &i); if (( user_requested_db_max_tabs = atoi(arg) ) < 0) { erts_fprintf(stderr, "bad maximum number of ets tables %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("using maximum number of ets tables %d\n", user_requested_db_max_tabs)); } break; case 'i': /* define name of module for initial function */ init = get_arg(argv[i]+2, argv[i+1], &i); break; case 'b': /* define name of initial function */ boot = get_arg(argv[i]+2, argv[i+1], &i); break; case 'B': if (argv[i][2] == 'i') /* +Bi */ ignore_break = 1; else if (argv[i][2] == 'c') /* +Bc */ replace_intr = 1; else if (argv[i][2] == 'd') /* +Bd */ have_break_handler = 0; else if (argv[i+1][0] == 'i') { /* +B i */ get_arg(argv[i]+2, argv[i+1], &i); ignore_break = 1; } else if (argv[i+1][0] == 'c') { /* +B c */ get_arg(argv[i]+2, argv[i+1], &i); replace_intr = 1; } else if (argv[i+1][0] == 'd') { /* +B d */ get_arg(argv[i]+2, argv[i+1], &i); have_break_handler = 0; } else /* +B */ have_break_handler = 0; break; case 'K': /* If kernel poll support is present, erl_sys_args() will remove the K parameter and value */ get_arg(argv[i]+2, argv[i+1], &i); erts_fprintf(stderr, "kernel-poll not supported; \"K\" parameter ignored\n", arg); break; case 'P': /* set maximum number of processes */ Parg = get_arg(argv[i]+2, argv[i+1], &i); erts_proc.max = atoi(Parg); /* Check of result is delayed until later. This is because +R may be given after +P. */ break; case 'S' : /* Was handled in early_init() just read past it */ (void) get_arg(argv[i]+2, argv[i+1], &i); break; case 's' : { char *estr; int res; char *sub_param = argv[i]+2; if (has_prefix("bt", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); res = erts_init_scheduler_bind_type_string(arg); if (res != ERTS_INIT_SCHED_BIND_TYPE_SUCCESS) { switch (res) { case ERTS_INIT_SCHED_BIND_TYPE_NOT_SUPPORTED: estr = "not supported"; break; case ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY: estr = "no cpu topology available"; break; case ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_BAD_TYPE: estr = "invalid type"; break; default: estr = "undefined error"; break; } erts_fprintf(stderr, "setting scheduler bind type '%s' failed: %s\n", arg, estr); erts_usage(); } } else if (has_prefix("bwt", sub_param)) { arg = get_arg(sub_param+3, argv[i+1], &i); if (erts_sched_set_busy_wait_threshold(arg) != 0) { erts_fprintf(stderr, "bad scheduler busy wait threshold: %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("scheduler wakup threshold: %s\n", arg)); } else if (has_prefix("cl", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); if (sys_strcmp("true", arg) == 0) erts_sched_compact_load = 1; else if (sys_strcmp("false", arg) == 0) erts_sched_compact_load = 0; else { erts_fprintf(stderr, "bad scheduler compact load value '%s'\n", arg); erts_usage(); } } else if (has_prefix("ct", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); res = erts_init_cpu_topology_string(arg); if (res != ERTS_INIT_CPU_TOPOLOGY_OK) { switch (res) { case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID: estr = "invalid identifier"; break; case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE: estr = "invalid identifier range"; break; case ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY: estr = "invalid hierarchy"; break; case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_TYPE: estr = "invalid identifier type"; break; case ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES: estr = "invalid nodes declaration"; break; case ERTS_INIT_CPU_TOPOLOGY_MISSING_LID: estr = "missing logical identifier"; break; case ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_LIDS: estr = "not unique logical identifiers"; break; case ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_ENTITIES: estr = "not unique entities"; break; case ERTS_INIT_CPU_TOPOLOGY_MISSING: estr = "missing cpu topology"; break; default: estr = "undefined error"; break; } erts_fprintf(stderr, "bad cpu topology '%s': %s\n", arg, estr); erts_usage(); } } else if (sys_strcmp("nsp", sub_param) == 0) erts_use_sender_punish = 0; else if (sys_strcmp("wt", sub_param) == 0) { arg = get_arg(sub_param+2, argv[i+1], &i); if (erts_sched_set_wakeup_other_thresold(arg) != 0) { erts_fprintf(stderr, "scheduler wakeup threshold: %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("scheduler wakeup threshold: %s\n", arg)); } else if (sys_strcmp("ws", sub_param) == 0) { arg = get_arg(sub_param+2, argv[i+1], &i); if (erts_sched_set_wakeup_other_type(arg) != 0) { erts_fprintf(stderr, "scheduler wakeup strategy: %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("scheduler wakeup threshold: %s\n", arg)); } else if (has_prefix("ss", sub_param)) { /* suggested stack size (Kilo Words) for scheduler threads */ arg = get_arg(sub_param+2, argv[i+1], &i); erts_sched_thread_suggested_stack_size = atoi(arg); if ((erts_sched_thread_suggested_stack_size < ERTS_SCHED_THREAD_MIN_STACK_SIZE) || (erts_sched_thread_suggested_stack_size > ERTS_SCHED_THREAD_MAX_STACK_SIZE)) { erts_fprintf(stderr, "bad stack size for scheduler threads %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("suggested scheduler thread stack size %d kilo words\n", erts_sched_thread_suggested_stack_size)); } else { erts_fprintf(stderr, "bad scheduling option %s\n", argv[i]); erts_usage(); } break; } case 't': /* set atom table size */ arg = get_arg(argv[i]+2, argv[i+1], &i); errno = 0; erts_atom_table_size = strtol(arg, NULL, 10); if (errno != 0 || erts_atom_table_size < MIN_ATOM_TABLE_SIZE || erts_atom_table_size > MAX_ATOM_TABLE_SIZE) { erts_fprintf(stderr, "bad atom table size %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("setting maximum number of atoms to %d\n", erts_atom_table_size)); break; case 'T' : arg = get_arg(argv[i]+2, argv[i+1], &i); errno = 0; erts_modified_timing_level = atoi(arg); if ((erts_modified_timing_level == 0 && errno != 0) || erts_modified_timing_level < 0 || erts_modified_timing_level >= ERTS_MODIFIED_TIMING_LEVELS) { erts_fprintf(stderr, "bad modified timing level %s\n", arg); erts_usage(); } else { VERBOSE(DEBUG_SYSTEM, ("using modified timing level %d\n", erts_modified_timing_level)); } break; case 'R': { /* set compatibility release */ arg = get_arg(argv[i]+2, argv[i+1], &i); erts_compat_rel = atoi(arg); if (erts_compat_rel < ERTS_MIN_COMPAT_REL || erts_compat_rel > this_rel_num()) { erts_fprintf(stderr, "bad compatibility release number %s\n", arg); erts_usage(); } ASSERT(ERTS_MIN_COMPAT_REL >= 7); switch (erts_compat_rel) { case 7: case 8: case 9: erts_use_r9_pids_ports = 1; default: break; } break; } case 'A': /* Was handled in early init just read past it */ (void) get_arg(argv[i]+2, argv[i+1], &i); break; case 'a': /* suggested stack size (Kilo Words) for threads in thread pool */ arg = get_arg(argv[i]+2, argv[i+1], &i); erts_async_thread_suggested_stack_size = atoi(arg); if ((erts_async_thread_suggested_stack_size < ERTS_ASYNC_THREAD_MIN_STACK_SIZE) || (erts_async_thread_suggested_stack_size > ERTS_ASYNC_THREAD_MAX_STACK_SIZE)) { erts_fprintf(stderr, "bad stack size for async threads %s\n", arg); erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("suggested async-thread stack size %d kilo words\n", erts_async_thread_suggested_stack_size)); break; case 'r': { char *sub_param = argv[i]+2; if (has_prefix("g", sub_param)) { get_arg(sub_param+1, argv[i+1], &i); /* already handled */ } else { erts_ets_realloc_always_moves = 1; } break; } case 'n': /* XXX obsolete */ break; case 'c': if (argv[i][2] == 0) { /* -c: documented option */ erts_disable_tolerant_timeofday = 1; } #ifdef ERTS_OPCODE_COUNTER_SUPPORT else if (argv[i][2] == 'i') { /* -ci: undcoumented option*/ count_instructions = 1; } #endif break; case 'W': arg = get_arg(argv[i]+2, argv[i+1], &i); switch (arg[0]) { case 'i': erts_error_logger_warnings = am_info; break; case 'w': erts_error_logger_warnings = am_warning; break; case 'e': /* The default */ erts_error_logger_warnings = am_error; default: erts_fprintf(stderr, "unrecognized warning_map option %s\n", arg); erts_usage(); } break; case 'z': { char *sub_param = argv[i]+2; int new_limit; if (has_prefix("dbbl", sub_param)) { arg = get_arg(sub_param+4, argv[i+1], &i); new_limit = atoi(arg); if (new_limit < 1 || INT_MAX/1024 < new_limit) { erts_fprintf(stderr, "Invalid dbbl limit: %d\n", new_limit); erts_usage(); } else { erts_dist_buf_busy_limit = new_limit*1024; } } else { erts_fprintf(stderr, "bad -z option %s\n", argv[i]); erts_usage(); } break; } default: erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]); erts_usage(); } i++; } /* Delayed check of +P flag */ if (erts_proc.max < ERTS_MIN_PROCESSES || erts_proc.max > ERTS_MAX_PROCESSES || (erts_use_r9_pids_ports && erts_proc.max > ERTS_MAX_R9_PROCESSES)) { erts_fprintf(stderr, "bad number of processes %s\n", Parg); erts_usage(); } /* Restart will not reinstall the break handler */ #ifdef __WIN32__ if (ignore_break) erts_set_ignore_break(); else if (replace_intr) erts_replace_intr(); else init_break_handler(); #else if (ignore_break) erts_set_ignore_break(); else if (have_break_handler) init_break_handler(); if (replace_intr) erts_replace_intr(); #endif boot_argc = argc - i; /* Number of arguments to init */ boot_argv = &argv[i]; erl_init(ncpu); load_preloaded(); erts_end_staging_code_ix(); erts_commit_staging_code_ix(); erts_initialized = 1; erl_first_process_otp("otp_ring0", NULL, 0, boot_argc, boot_argv); #ifdef ERTS_SMP erts_start_schedulers(); /* Let system specific code decide what to do with the main thread... */ erts_sys_main_thread(); /* May or may not return! */ #else erts_thr_set_main_status(1, 1); #if ERTS_USE_ASYNC_READY_Q erts_get_scheduler_data()->aux_work_data.async_ready.queue = erts_get_async_ready_queue(1); #endif set_main_stack_size(); process_main(); #endif }
static Eterm staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking, struct m* mods, int nmods, int free_mods) { #ifdef ERTS_SMP if (is_blocking || !commit) #endif { if (commit) { int i; erts_end_staging_code_ix(); erts_commit_staging_code_ix(); for (i=0; i < nmods; i++) { if (mods[i].modp->curr.code_hdr) { set_default_trace_pattern(mods[i].module); } #ifdef HIPE hipe_redirect_to_module(mods[i].modp); #endif } } else { erts_abort_staging_code_ix(); } if (free_mods) { erts_free(ERTS_ALC_T_LOADER_TMP, mods); } if (is_blocking) { erts_smp_thr_progress_unblock(); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); } erts_release_code_write_permission(); return res; } #ifdef ERTS_SMP else { ASSERT(is_value(res)); if (free_mods) { erts_free(ERTS_ALC_T_LOADER_TMP, mods); } erts_end_staging_code_ix(); /* * Now we must wait for all schedulers to do a memory barrier before * we can commit and let them access the new staged code. This allows * schedulers to read active code_ix in a safe way while executing * without any memory barriers at all. */ ASSERT(committer_state.stager == NULL); committer_state.stager = c_p; erts_schedule_thr_prgr_later_op(smp_code_ix_commiter, NULL, &committer_state.lop); erts_proc_inc_refc(c_p); erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); /* * smp_code_ix_commiter() will do the rest "later" * and resume this process to return 'res'. */ ERTS_BIF_YIELD_RETURN(c_p, res); } #endif }