void erts_thr_progress_fatal_error_wait(SWord timeout) { erts_aint32_t bc; SWord time_left = timeout; ErtsMonotonicTime timeout_time; ErtsSchedulerData *esdp = erts_get_scheduler_data(); /* * Counting poll intervals may give us a too long timeout * if cpu is busy. We use timeout time to try to prevent * this. In case we havn't got time correction this may * however fail too... */ timeout_time = erts_get_monotonic_time(esdp); timeout_time += ERTS_MSEC_TO_MONOTONIC((ErtsMonotonicTime) timeout); while (1) { if (erts_milli_sleep(ERTS_THR_PRGR_FTL_ERR_BLCK_POLL_INTERVAL) == 0) time_left -= ERTS_THR_PRGR_FTL_ERR_BLCK_POLL_INTERVAL; bc = erts_atomic32_read_acqb(&intrnl->misc.data.block_count); if (bc == 0) break; /* Succefully blocked all managed threads */ if (time_left <= 0) break; /* Timeout */ if (timeout_time <= erts_get_monotonic_time(esdp)) break; /* Timeout */ } }
void erts_deep_process_dump(fmtfn_t to, void *to_arg) { int i, max = erts_ptab_max(&erts_proc); all_binaries = NULL; init_literal_areas(); erts_init_persistent_dumping(); for (i = 0; i < max; i++) { Process *p = erts_pix2proc(i); if (p && p->i != ENULL) { erts_aint32_t state = erts_atomic32_read_acqb(&p->state); if (state & ERTS_PSFLG_EXITING) continue; if (state & ERTS_PSFLG_GC) { ErtsSchedulerData *sdp = erts_get_scheduler_data(); if (!sdp || p != sdp->current_process) continue; /* We want to dump the garbing process that caused the dump */ } dump_process_info(to, to_arg, p); } } dump_persistent_terms(to, to_arg); dump_literals(to, to_arg); dump_binaries(to, to_arg, all_binaries); }
void erts_debug_unuse_tmp_heap(int size, Process *p) { ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p)); sd->num_tmp_heap_used -= size; ASSERT(sd->num_tmp_heap_used >= 0); }
Eterm *erts_debug_allocate_tmp_heap(int size, Process *p) { ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p)); int offset = sd->num_tmp_heap_used; ASSERT(offset+size <= TMP_HEAP_SIZE); return (sd->tmp_heap)+offset; }
static ERTS_INLINE void make_ref_in_array(Uint32 ref[ERTS_MAX_REF_NUMBERS]) { ErtsSchedulerData *esdp = erts_get_scheduler_data(); if (esdp) erts_sched_make_ref_in_array(esdp, ref); else global_make_ref_in_array(0, ref); }
void erts_raw_get_unique_integer(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]) { ErtsSchedulerData *esdp = erts_get_scheduler_data(); if (esdp) { val[0] = (Uint64) esdp->thr_id; val[1] = esdp->unique++; } else { val[0] = (Uint64) 0; val[1] = (Uint64) erts_atomic64_inc_read_nob(&unique_data.w.val1); } }
static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) { ErtsSchedulerData *esdp = erts_get_scheduler_data(); Process *rp = msaccrp->proc; ErtsMessage *msgp = NULL; Eterm **hpp, *hp; Eterm ref_copy = NIL, msg; Uint sz, *szp; ErlOffHeap *ohp = NULL; ErtsProcLocks rp_locks = (esdp && msaccrp->req_sched == esdp->no ? ERTS_PROC_LOCK_MAIN : 0); sz = 0; hpp = NULL; szp = &sz; if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx); while (1) { if (hpp) ref_copy = STORE_NC(hpp, ohp, msaccrp->ref); else *szp += REF_THING_SIZE; if (msaccrp->action != ERTS_MSACC_GATHER) msg = ref_copy; else { msg = erts_msacc_gather_stats(msacc, hpp, szp); msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg); } if (hpp) break; msgp = erts_alloc_message_heap(rp, &rp_locks, sz, &hp, &ohp); hpp = &hp; szp = NULL; } if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx); erts_queue_message(rp, rp_locks, msgp, msg, am_system); if (esdp && msaccrp->req_sched == esdp->no) rp_locks &= ~ERTS_PROC_LOCK_MAIN; if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); }
static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) { ErtsSchedulerData *esdp = erts_get_scheduler_data(); Process *rp = msaccrp->proc; ErtsMessage *msgp = NULL; Eterm *hp; Eterm ref_copy = NIL, msg; ErtsProcLocks rp_locks = (esdp && msaccrp->req_sched == esdp->no ? ERTS_PROC_LOCK_MAIN : 0); ErtsHeapFactory factory; if (msaccrp->action == ERTS_MSACC_GATHER) { msgp = erts_factory_message_create(&factory, rp, &rp_locks, DEFAULT_MSACC_MSG_SIZE); if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx); hp = erts_produce_heap(&factory, REF_THING_SIZE + 3 /* tuple */, 0); ref_copy = STORE_NC(&hp, &msgp->hfrag.off_heap, msaccrp->ref); msg = erts_msacc_gather_stats(msacc, &factory); msg = TUPLE2(hp, ref_copy, msg); if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx); erts_factory_close(&factory); } else { ErlOffHeap *ohp = NULL; msgp = erts_alloc_message_heap(rp, &rp_locks, REF_THING_SIZE, &hp, &ohp); msg = STORE_NC(&hp, &msgp->hfrag.off_heap, msaccrp->ref); } erts_queue_message(rp, rp_locks, msgp, msg, am_system); if (esdp && msaccrp->req_sched == esdp->no) rp_locks &= ~ERTS_PROC_LOCK_MAIN; if (rp_locks) erts_smp_proc_unlock(rp, rp_locks); }
int erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) { int port_was_enqueued = 0; Port *pp; ErtsPortTaskQueue *ptqp; ErtsPortTask *ptp; int res = 0; int reds = ERTS_PORT_REDS_EXECUTE; erts_aint_t io_tasks_executed = 0; int fpe_was_unmasked; ErtsPortTaskExeBlockData blk_data = {runq, NULL}; ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); ERTS_PT_CHK_PORTQ(runq); pp = pop_port(runq); if (!pp) { res = 0; goto done; } ERTS_PORT_NOT_IN_RUNQ(pp); *curr_port_pp = pp; ASSERT(pp->sched.taskq); ASSERT(pp->sched.taskq->first); ptqp = pp->sched.taskq; pp->sched.taskq = NULL; ASSERT(!pp->sched.exe_taskq); pp->sched.exe_taskq = ptqp; if (erts_smp_port_trylock(pp) == EBUSY) { erts_smp_runq_unlock(runq); erts_smp_port_lock(pp); erts_smp_runq_lock(runq); } if (erts_sched_stat.enabled) { ErtsSchedulerData *esdp = erts_get_scheduler_data(); Uint old = ERTS_PORT_SCHED_ID(pp, esdp->no); int migrated = old && old != esdp->no; erts_smp_spin_lock(&erts_sched_stat.lock); erts_sched_stat.prio[ERTS_PORT_PRIO_LEVEL].total_executed++; erts_sched_stat.prio[ERTS_PORT_PRIO_LEVEL].executed++; if (migrated) { erts_sched_stat.prio[ERTS_PORT_PRIO_LEVEL].total_migrated++; erts_sched_stat.prio[ERTS_PORT_PRIO_LEVEL].migrated++; } erts_smp_spin_unlock(&erts_sched_stat.lock); } /* trace port scheduling, in */ if (IS_TRACED_FL(pp, F_TRACE_SCHED_PORTS)) { trace_sched_ports(pp, am_in); } ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp)); ERTS_PT_CHK_PRES_PORTQ(runq, pp); ptp = pop_task(ptqp); fpe_was_unmasked = erts_block_fpe(); while (ptp) { ASSERT(pp->sched.taskq != pp->sched.exe_taskq); reset_handle(ptp); erts_smp_runq_unlock(runq); ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp)); ERTS_SMP_CHK_NO_PROC_LOCKS; ASSERT(pp->drv_ptr); switch (ptp->type) { case ERTS_PORT_TASK_FREE: /* May be pushed in q at any time */ reds += ERTS_PORT_REDS_FREE; erts_smp_runq_lock(runq); erts_unblock_fpe(fpe_was_unmasked); ASSERT(pp->status & ERTS_PORT_SFLG_FREE_SCHEDULED); if (ptqp->first || (pp->sched.taskq && pp->sched.taskq->first)) handle_remaining_tasks(runq, pp); ASSERT(!ptqp->first && (!pp->sched.taskq || !pp->sched.taskq->first)); #ifdef ERTS_SMP erts_smp_atomic_dec_nob(&pp->refc); /* Not alive */ ERTS_SMP_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 0); /* Lock */ #else erts_port_status_bor_set(pp, ERTS_PORT_SFLG_FREE); #endif port_task_free(ptp); if (pp->sched.taskq) port_taskq_free(pp->sched.taskq); pp->sched.taskq = NULL; goto tasks_done; case ERTS_PORT_TASK_TIMEOUT: reds += ERTS_PORT_REDS_TIMEOUT; if (!(pp->status & ERTS_PORT_SFLGS_DEAD)) (*pp->drv_ptr->timeout)((ErlDrvData) pp->drv_data); break; case ERTS_PORT_TASK_INPUT: reds += ERTS_PORT_REDS_INPUT; ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0); /* NOTE some windows drivers use ->ready_input for input and output */ (*pp->drv_ptr->ready_input)((ErlDrvData) pp->drv_data, ptp->event); io_tasks_executed++; break; case ERTS_PORT_TASK_OUTPUT: reds += ERTS_PORT_REDS_OUTPUT; ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0); (*pp->drv_ptr->ready_output)((ErlDrvData) pp->drv_data, ptp->event); io_tasks_executed++; break; case ERTS_PORT_TASK_EVENT: reds += ERTS_PORT_REDS_EVENT; ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0); (*pp->drv_ptr->event)((ErlDrvData) pp->drv_data, ptp->event, ptp->event_data); io_tasks_executed++; break; case ERTS_PORT_TASK_DIST_CMD: reds += erts_dist_command(pp, CONTEXT_REDS-reds); break; default: erl_exit(ERTS_ABORT_EXIT, "Invalid port task type: %d\n", (int) ptp->type); break; } if ((pp->status & ERTS_PORT_SFLG_CLOSING) && erts_is_port_ioq_empty(pp)) { reds += ERTS_PORT_REDS_TERMINATE; erts_terminate_port(pp); } ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp)); #ifdef ERTS_SMP if (pp->xports) erts_smp_xports_unlock(pp); ASSERT(!pp->xports); #endif ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp)); port_task_free(ptp); erts_smp_runq_lock(runq); ptp = pop_task(ptqp); } tasks_done: erts_unblock_fpe(fpe_was_unmasked); if (io_tasks_executed) { ASSERT(erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks) >= io_tasks_executed); erts_smp_atomic_add_relb(&erts_port_task_outstanding_io_tasks, -1*io_tasks_executed); } *curr_port_pp = NULL; #ifdef ERTS_SMP ASSERT(runq == (ErtsRunQueue *) erts_smp_atomic_read_nob(&pp->run_queue)); #endif if (!pp->sched.taskq) { ASSERT(pp->sched.exe_taskq); pp->sched.exe_taskq = NULL; } else { #ifdef ERTS_SMP ErtsRunQueue *xrunq; #endif ASSERT(!(pp->status & ERTS_PORT_SFLGS_DEAD)); ASSERT(pp->sched.taskq->first); #ifdef ERTS_SMP xrunq = erts_check_emigration_need(runq, ERTS_PORT_PRIO_LEVEL); if (!xrunq) { #endif enqueue_port(runq, pp); ASSERT(pp->sched.exe_taskq); pp->sched.exe_taskq = NULL; /* No need to notify ourselves about inc in runq. */ #ifdef ERTS_SMP } else { /* Port emigrated ... */ erts_smp_atomic_set_nob(&pp->run_queue, (erts_aint_t) xrunq); enqueue_port(xrunq, pp); ASSERT(pp->sched.exe_taskq); pp->sched.exe_taskq = NULL; erts_smp_runq_unlock(xrunq); erts_smp_notify_inc_runq(xrunq); } #endif port_was_enqueued = 1; } res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks) != (erts_aint_t) 0); ERTS_PT_CHK_PRES_PORTQ(runq, pp); port_taskq_free(ptqp); if (erts_system_profile_flags.runnable_ports && (port_was_enqueued != 1)) { profile_runnable_port(pp, am_inactive); } /* trace port scheduling, out */ if (IS_TRACED_FL(pp, F_TRACE_SCHED_PORTS)) { trace_sched_ports(pp, am_out); } #ifndef ERTS_SMP erts_port_release(pp); #else { erts_aint_t refc; erts_smp_mtx_unlock(pp->lock); refc = erts_smp_atomic_dec_read_nob(&pp->refc); ASSERT(refc >= 0); if (refc == 0) { erts_smp_runq_unlock(runq); erts_port_cleanup(pp); /* Might aquire runq lock */ erts_smp_runq_lock(runq); res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks) != (erts_aint_t) 0); } } #endif done: blk_data.resp = &res; ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); ERTS_PORT_REDUCTIONS_EXECUTED(runq, reds); 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 }
NifExport * erts_nif_export_schedule(Process *c_p, Process *dirty_shadow_proc, ErtsCodeMFA *mfa, BeamInstr *pc, BeamInstr instr, void *dfunc, void *ifunc, Eterm mod, Eterm func, int argc, const Eterm *argv) { Process *used_proc; ErtsSchedulerData *esdp; Eterm* reg; NifExport* nep; int i; ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) & ERTS_PROC_LOCK_MAIN); if (dirty_shadow_proc) { esdp = erts_get_scheduler_data(); ASSERT(esdp && ERTS_SCHEDULER_IS_DIRTY(esdp)); used_proc = dirty_shadow_proc; } else { esdp = erts_proc_sched_data(c_p); ASSERT(esdp && !ERTS_SCHEDULER_IS_DIRTY(esdp)); used_proc = c_p; ERTS_VBUMP_ALL_REDS(c_p); } reg = esdp->x_reg_array; if (mfa) nep = erts_get_proc_nif_export(c_p, (int) mfa->arity); else { /* If no mfa, this is not the first schedule... */ nep = ERTS_PROC_GET_NIF_TRAP_EXPORT(c_p); ASSERT(nep && nep->argc >= 0); } if (nep->argc < 0) { /* * First schedule; save things that might * need to be restored... */ for (i = 0; i < (int) mfa->arity; i++) nep->argv[i] = reg[i]; nep->pc = pc; nep->cp = c_p->cp; nep->mfa = mfa; nep->current = c_p->current; ASSERT(argc >= 0); nep->argc = (int) mfa->arity; nep->m = NULL; ASSERT(!erts_check_nif_export_in_area(c_p, (char *) nep, (sizeof(NifExport) + (sizeof(Eterm) *(nep->argc-1))))); } /* Copy new arguments into register array if necessary... */ if (reg != argv) { for (i = 0; i < argc; i++) reg[i] = argv[i]; } ASSERT(is_atom(mod) && is_atom(func)); nep->exp.info.mfa.module = mod; nep->exp.info.mfa.function = func; nep->exp.info.mfa.arity = (Uint) argc; nep->exp.beam[0] = (BeamInstr) instr; /* call_nif || apply_bif */ nep->exp.beam[1] = (BeamInstr) dfunc; nep->func = ifunc; used_proc->arity = argc; used_proc->freason = TRAP; used_proc->i = (BeamInstr*) nep->exp.addressv[0]; return nep; }
/* XXX THIS SHOULD BE IN SYSTEM !!!! */ void erl_crash_dump_v(char *file, int line, char* fmt, va_list args) { #ifdef ERTS_SMP ErtsThrPrgrData tpd_buf; /* in case we aren't a managed thread... */ #endif int fd; size_t envsz; time_t now; char env[21]; /* enough to hold any 64-bit integer */ size_t dumpnamebufsize = MAXPATHLEN; char dumpnamebuf[MAXPATHLEN]; char* dumpname; int secs; int env_erl_crash_dump_seconds_set = 1; int i; if (ERTS_SOMEONE_IS_CRASH_DUMPING) return; #ifdef ERTS_SMP /* Order all managed threads to block, this has to be done first to guarantee that this is the only thread to generate crash dump. */ erts_thr_progress_fatal_error_block(&tpd_buf); #ifdef ERTS_THR_HAVE_SIG_FUNCS /* * We suspend all scheduler threads so that we can dump some * data about the currently running processes and scheduler data. * We have to be very very careful when doing this as the schedulers * could be anywhere. */ for (i = 0; i < erts_no_schedulers; i++) { erts_tid_t tid = ERTS_SCHEDULER_IX(i)->tid; if (!erts_equal_tids(tid,erts_thr_self())) sys_thr_suspend(tid); } #endif /* Allow us to pass certain places without locking... */ erts_smp_atomic32_set_mb(&erts_writing_erl_crash_dump, 1); erts_smp_tsd_set(erts_is_crash_dumping_key, (void *) 1); #else /* !ERTS_SMP */ erts_writing_erl_crash_dump = 1; #endif /* ERTS_SMP */ envsz = sizeof(env); /* ERL_CRASH_DUMP_SECONDS not set * if we have a heart port, break immediately * otherwise dump crash indefinitely (until crash is complete) * same as ERL_CRASH_DUMP_SECONDS = 0 * - do not write dump * - do not set an alarm * - break immediately * * ERL_CRASH_DUMP_SECONDS = 0 * - do not write dump * - do not set an alarm * - break immediately * * ERL_CRASH_DUMP_SECONDS < 0 * - do not set alarm * - write dump until done * * ERL_CRASH_DUMP_SECONDS = S (and S positive) * - Don't dump file forever * - set alarm (set in sys) * - write dump until alarm or file is written completely */ if (erts_sys_getenv__("ERL_CRASH_DUMP_SECONDS", env, &envsz) != 0) { env_erl_crash_dump_seconds_set = 0; secs = -1; } else { env_erl_crash_dump_seconds_set = 1; secs = atoi(env); } if (secs == 0) { return; } /* erts_sys_prepare_crash_dump returns 1 if heart port is found, otherwise 0 * If we don't find heart (0) and we don't have ERL_CRASH_DUMP_SECONDS set * we should continue writing a dump * * beware: secs -1 means no alarm */ if (erts_sys_prepare_crash_dump(secs) && !env_erl_crash_dump_seconds_set ) { return; } if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0) dumpname = "erl_crash.dump"; else dumpname = &dumpnamebuf[0]; erts_fprintf(stderr,"\nCrash dump is being written to: %s...", dumpname); fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640); if (fd < 0) return; /* Can't create the crash dump, skip it */ time(&now); erts_fdprintf(fd, "=erl_crash_dump:0.3\n%s", ctime(&now)); if (file != NULL) erts_fdprintf(fd, "The error occurred in file %s, line %d\n", file, line); if (fmt != NULL && *fmt != '\0') { erts_fdprintf(fd, "Slogan: "); erts_vfdprintf(fd, fmt, args); } erts_fdprintf(fd, "System version: "); erts_print_system_version(fd, NULL, NULL); erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE); erts_fdprintf(fd, "Taints: "); erts_print_nif_taints(fd, NULL); erts_fdprintf(fd, "Atoms: %d\n", atom_table_size()); #ifdef USE_THREADS /* We want to note which thread it was that called erl_exit */ if (erts_get_scheduler_data()) { erts_fdprintf(fd, "Calling Thread: scheduler:%d\n", erts_get_scheduler_data()->no); } else { if (!erts_thr_getname(erts_thr_self(), dumpnamebuf, MAXPATHLEN)) erts_fdprintf(fd, "Calling Thread: %s\n", dumpnamebuf); else erts_fdprintf(fd, "Calling Thread: %p\n", erts_thr_self()); } #else erts_fdprintf(fd, "Calling Thread: scheduler:1\n"); #endif #if defined(ERTS_HAVE_TRY_CATCH) /* * erts_print_scheduler_info is not guaranteed to be safe to call * here for all schedulers as we may have suspended a scheduler * in the middle of updating the STACK_TOP and STACK_START * variables and thus when scanning the stack we could get * segmentation faults. We protect against this very unlikely * scenario by using the ERTS_SYS_TRY_CATCH. */ for (i = 0; i < erts_no_schedulers; i++) { ERTS_SYS_TRY_CATCH( erts_print_scheduler_info(fd, NULL, ERTS_SCHEDULER_IX(i)), erts_fdprintf(fd, "** crashed **\n")); } #endif #ifdef ERTS_SMP #if defined(ERTS_THR_HAVE_SIG_FUNCS) /* We resume all schedulers so that we are in a known safe state when we write the rest of the crash dump */ for (i = 0; i < erts_no_schedulers; i++) { erts_tid_t tid = ERTS_SCHEDULER_IX(i)->tid; if (!erts_equal_tids(tid,erts_thr_self())) sys_thr_resume(tid); } #endif /* * Wait for all managed threads to block. If all threads haven't blocked * after a minute, we go anyway and hope for the best... * * We do not release system again. We expect an exit() or abort() after * dump has been written. */ erts_thr_progress_fatal_error_wait(60000); /* Either worked or not... */ #endif #ifndef ERTS_HAVE_TRY_CATCH /* This is safe to call here, as all schedulers are blocked */ for (i = 0; i < erts_no_schedulers; i++) { erts_print_scheduler_info(fd, NULL, ERTS_SCHEDULER_IX(i)); } #endif info(fd, NULL); /* General system info */ if (erts_ptab_initialized(&erts_proc)) process_info(fd, NULL); /* Info about each process and port */ db_info(fd, NULL, 0); erts_print_bif_timer_info(fd, NULL); distribution_info(fd, NULL); erts_fdprintf(fd, "=loaded_modules\n"); loaded(fd, NULL); erts_dump_fun_entries(fd, NULL); erts_deep_process_dump(fd, NULL); erts_fdprintf(fd, "=atoms\n"); dump_atoms(fd, NULL); /* Keep the instrumentation data at the end of the dump */ if (erts_instr_memory_map || erts_instr_stat) { erts_fdprintf(fd, "=instr_data\n"); if (erts_instr_stat) { erts_fdprintf(fd, "=memory_status\n"); erts_instr_dump_stat_to_fd(fd, 0); } if (erts_instr_memory_map) { erts_fdprintf(fd, "=memory_map\n"); erts_instr_dump_memory_map_to_fd(fd); } } erts_fdprintf(fd, "=end\n"); close(fd); erts_fprintf(stderr,"done\n"); }
/* Add messages last in message queue */ static void queue_messages(Process* receiver, ErtsProcLocks receiver_locks, ErtsMessage* first, ErtsMessage** last, Uint len) { int locked_msgq = 0; erts_aint32_t state; #ifdef DEBUG { ErtsMessage* fmsg = ERTS_SIG_IS_MSG(first) ? first : first->next; ASSERT(fmsg); ASSERT(is_value(ERL_MESSAGE_TERM(fmsg))); ASSERT(is_value(ERL_MESSAGE_FROM(fmsg))); ASSERT(ERL_MESSAGE_TOKEN(fmsg) == am_undefined || ERL_MESSAGE_TOKEN(fmsg) == NIL || is_tuple(ERL_MESSAGE_TOKEN(fmsg))); } #endif ERTS_LC_ASSERT((erts_proc_lc_my_proc_locks(receiver) & ERTS_PROC_LOCK_MSGQ) == (receiver_locks & ERTS_PROC_LOCK_MSGQ)); if (!(receiver_locks & ERTS_PROC_LOCK_MSGQ)) { erts_proc_lock(receiver, ERTS_PROC_LOCK_MSGQ); locked_msgq = 1; } state = erts_atomic32_read_nob(&receiver->state); if (state & ERTS_PSFLG_EXITING) { /* Drop message if receiver is exiting or has a pending exit... */ if (locked_msgq) erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ); if (ERTS_SIG_IS_NON_MSG(first)) { ErtsSchedulerData* esdp = erts_get_scheduler_data(); ASSERT(esdp); ASSERT(!esdp->pending_signal.sig); esdp->pending_signal.sig = (ErtsSignal*) first; esdp->pending_signal.to = receiver->common.id; first = first->next; } erts_cleanup_messages(first); return; } if (last == &first->next) { ASSERT(len == 1); LINK_MESSAGE(receiver, first); } else { erts_enqueue_signals(receiver, first, last, NULL, len, state); } if (receiver_locks & ERTS_PROC_LOCK_MAIN) erts_proc_sig_fetch(receiver); if (locked_msgq) { erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ); } if (last == &first->next) erts_proc_notify_new_message(receiver, receiver_locks); else erts_proc_notify_new_sig(receiver, state, ERTS_PSFLG_ACTIVE); }