diff options
Diffstat (limited to 'erts')
47 files changed, 1107 insertions, 516 deletions
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index 99f0421080..5089d4e0ce 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -572,7 +572,7 @@ <tag><marker id="async_thread_pool_size"/><c><![CDATA[+A size]]></c></tag> <item> <p>Sets the number of threads in async thread pool. Valid range - is 0-1024. Defaults to 10 if thread support is available.</p> + is 0-1024. Defaults to 1.</p> </item> <tag><c><![CDATA[+B [c | d | i]]]></c></tag> <item> @@ -1155,6 +1155,26 @@ without prior notice.</p> </note> </item> + <tag><marker id="+sbwtdcpu"/> + <c>+sbwtdcpu none|very_short|short|medium|long|very_long</c></tag> + <item> + <p>As <seealso marker="+sbwt"><c>+sbwt</c></seealso> but affects + dirty CPU schedulers. Defaults to <c>short</c>.</p> + <note> + <p>This flag can be removed or changed at any time + without prior notice.</p> + </note> + </item> + <tag><marker id="+sbwtdio"/> + <c>+sbwtdio none|very_short|short|medium|long|very_long</c></tag> + <item> + <p>As <seealso marker="+sbwt"><c>+sbwt</c></seealso> but affects + dirty IO schedulers. Defaults to <c>short</c>.</p> + <note> + <p>This flag can be removed or changed at any time + without prior notice.</p> + </note> + </item> <tag><marker id="+scl"/><c>+scl true|false</c></tag> <item> <p>Enables or disables scheduler compaction of load. By default @@ -1420,6 +1440,26 @@ notice.</p> </note> </item> + <tag><marker id="+swtdcpu"/> + <c>+swtdcpu very_low|low|medium|high|very_high</c></tag> + <item> + <p>As <seealso marker="+swt"><c>+swt</c></seealso> but + affects dirty CPU schedulers. Defaults to <c>medium</c>.</p> + <note> + <p>This flag can be removed or changed at any time + without prior notice.</p> + </note> + </item> + <tag><marker id="+swtdio"/> + <c>+swtdio very_low|low|medium|high|very_high</c></tag> + <item> + <p>As <seealso marker="+swt"><c>+swt</c></seealso> but affects + dirty IO schedulers. Defaults to <c>medium</c>.</p> + <note> + <p>This flag can be removed or changed at any time + without prior notice.</p> + </note> + </item> </taglist> </item> <tag><marker id="+t"/><c><![CDATA[+t size]]></c></tag> diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 27b0945c10..cabc07d020 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -2185,6 +2185,20 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> + <name><ret>int</ret> + <nametext>enif_make_map_from_arrays(ErlNifEnv* env, ERL_NIF_TERM keys[], + ERL_NIF_TERM values[], size_t cnt, ERL_NIF_TERM *map_out)</nametext></name> + <fsummary>Make map term from the given keys and values.</fsummary> + <desc> + <p>Makes a map term from the given keys and values.</p> + <p>If successful, this function sets <c>*map_out</c> to the new map and + returns <c>true</c>. Returns <c>false</c> there are any duplicate + keys.</p> + <p>All keys and values must belong to <c>env</c>.</p> + </desc> + </func> + + <func> <name><ret>unsigned char *</ret><nametext>enif_make_new_binary(ErlNifEnv* env, size_t size, ERL_NIF_TERM* termp)</nametext></name> <fsummary>Allocate and create a new binary term.</fsummary> diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 7963386e1d..cceca66850 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -673,3 +673,4 @@ atom xor atom x86 atom yes atom yield +atom nifs diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 0184c567f1..e61199a8fd 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -554,6 +554,7 @@ static Eterm get_module_info(Process* p, ErtsCodeIndex code_ix, static Eterm exported_from_module(Process* p, ErtsCodeIndex code_ix, Eterm mod); static Eterm functions_in_module(Process* p, BeamCodeHeader*); +static Eterm nifs_in_module(Process* p, Eterm module); static Eterm attributes_for_module(Process* p, BeamCodeHeader*); static Eterm compilation_info_for_module(Process* p, BeamCodeHeader*); static Eterm md5_of_module(Process* p, BeamCodeHeader*); @@ -4521,6 +4522,19 @@ is_empty_map(LoaderState* stp, GenOpArg Lit) } /* + * Predicate to test whether the given literal is an export. + */ +static int +literal_is_export(LoaderState* stp, GenOpArg Lit) +{ + Eterm term; + + ASSERT(Lit.type == TAG_q); + term = stp->literals[Lit.val].term; + return is_export(term); +} + +/* * Pseudo predicate map_key_sort that will sort the Rest operand for * map instructions as a side effect. */ @@ -5954,6 +5968,8 @@ get_module_info(Process* p, ErtsCodeIndex code_ix, BeamCodeHeader* code_hdr, return exported_from_module(p, code_ix, module); } else if (what == am_functions) { return functions_in_module(p, code_hdr); + } else if (what == am_nifs) { + return nifs_in_module(p, module); } else if (what == am_attributes) { return attributes_for_module(p, code_hdr); } else if (what == am_compile) { @@ -6007,6 +6023,46 @@ functions_in_module(Process* p, /* Process whose heap to use. */ } /* + * Builds a list of all NIFs in the given module: + * [{Name, Arity},...] + */ +Eterm +nifs_in_module(Process* p, Eterm module) +{ + Eterm nif_list, *hp; + Module *mod; + + mod = erts_get_module(module, erts_active_code_ix()); + nif_list = NIL; + + if (mod->curr.nif != NULL) { + int func_count, func_ix; + ErlNifFunc *funcs; + + func_count = erts_nif_get_funcs(mod->curr.nif, &funcs); + hp = HAlloc(p, func_count * 5); + + for (func_ix = func_count - 1; func_ix >= 0; func_ix--) { + Eterm name, arity, pair; + ErlNifFunc *func; + + func = &funcs[func_ix]; + + name = am_atom_put(func->name, sys_strlen(func->name)); + arity = make_small(func->arity); + + pair = TUPLE2(hp, name, arity); + hp += 3; + + nif_list = CONS(hp, pair, nif_list); + hp += 2; + } + } + + return nif_list; +} + +/* * Returns 'true' if mod has any native compiled functions, otherwise 'false' */ diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index adea7d007e..232597c5b6 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -52,7 +52,6 @@ Export *erts_await_result; static Export await_exit_trap; static Export* flush_monitor_messages_trap = NULL; static Export* set_cpu_topology_trap = NULL; -static Export* await_proc_exit_trap = NULL; static Export* await_port_send_result_trap = NULL; Export* erts_format_cpu_topology_trap = NULL; static Export dsend_continue_trap_export; @@ -4654,42 +4653,6 @@ static BIF_RETTYPE bif_return_trap(BIF_ALIST_2) BIF_RET(res); } -void -erts_bif_prep_await_proc_exit_data_trap(Process *c_p, Eterm pid, Eterm ret) -{ - ERTS_BIF_PREP_TRAP3_NO_RET(await_proc_exit_trap, c_p, pid, am_data, ret); -} - -void -erts_bif_prep_await_proc_exit_reason_trap(Process *c_p, Eterm pid) -{ - ERTS_BIF_PREP_TRAP3_NO_RET(await_proc_exit_trap, c_p, - pid, am_reason, am_undefined); -} - -void -erts_bif_prep_await_proc_exit_apply_trap(Process *c_p, - Eterm pid, - Eterm module, - Eterm function, - Eterm args[], - int nargs) -{ - Eterm term; - Eterm *hp; - int i; - ASSERT(is_atom(module) && is_atom(function)); - - hp = HAlloc(c_p, 4+2*nargs); - term = NIL; - for (i = nargs-1; i >= 0; i--) { - term = CONS(hp, args[i], term); - hp += 2; - } - term = TUPLE3(hp, module, function, term); - ERTS_BIF_PREP_TRAP3_NO_RET(await_proc_exit_trap, c_p, pid, am_apply, term); -} - Export bif_return_trap_export; void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a, @@ -4742,7 +4705,6 @@ void erts_init_bif(void) erts_format_cpu_topology_trap = erts_export_put(am_erlang, am_format_cpu_topology, 1); - await_proc_exit_trap = erts_export_put(am_erlang,am_await_proc_exit,3); await_port_send_result_trap = erts_export_put(am_erts_internal, am_await_port_send_result, 3); system_flag_scheduler_wall_time_trap diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h index dca53686f4..a33421d762 100644 --- a/erts/emulator/beam/bif.h +++ b/erts/emulator/beam/bif.h @@ -437,67 +437,6 @@ do { \ ERTS_BIF_EXITED((PROC)); \ } while (0) -/* - * The ERTS_BIF_*_AWAIT_X_*_TRAP makros either exits the caller, or - * sets up a trap to erlang:await_proc_exit/3. - * - * The caller is acquired to hold the 'main' lock on C_P. No other locks - * are allowed to be held. - */ - -#define ERTS_BIF_PREP_AWAIT_X_DATA_TRAP(RET, C_P, PID, DATA) \ -do { \ - erts_bif_prep_await_proc_exit_data_trap((C_P), (PID), (DATA)); \ - (RET) = THE_NON_VALUE; \ -} while (0) - -#define ERTS_BIF_PREP_AWAIT_X_REASON_TRAP(RET, C_P, PID) \ -do { \ - erts_bif_prep_await_proc_exit_reason_trap((C_P), (PID)); \ - (RET) = THE_NON_VALUE; \ -} while (0) - -#define ERTS_BIF_PREP_AWAIT_X_APPLY_TRAP(RET, C_P, PID, M, F, A, AN) \ -do { \ - erts_bif_prep_await_proc_exit_apply_trap((C_P), (PID), \ - (M), (F), (A), (AN)); \ - (RET) = THE_NON_VALUE; \ -} while (0) - -#define ERTS_BIF_AWAIT_X_DATA_TRAP(C_P, PID, DATA) \ -do { \ - erts_bif_prep_await_proc_exit_data_trap((C_P), (PID), (DATA)); \ - return THE_NON_VALUE; \ -} while (0) - -#define ERTS_BIF_AWAIT_X_REASON_TRAP(C_P, PID) \ -do { \ - erts_bif_prep_await_proc_exit_reason_trap((C_P), (PID)); \ - return THE_NON_VALUE; \ -} while (0) - -#define ERTS_BIF_AWAIT_X_APPLY_TRAP(C_P, PID, M, F, A, AN) \ -do { \ - erts_bif_prep_await_proc_exit_apply_trap((C_P), (PID), \ - (M), (F), (A), (AN)); \ - return THE_NON_VALUE; \ -} while (0) - -void -erts_bif_prep_await_proc_exit_data_trap(Process *c_p, - Eterm pid, - Eterm data); -void -erts_bif_prep_await_proc_exit_reason_trap(Process *c_p, - Eterm pid); -void -erts_bif_prep_await_proc_exit_apply_trap(Process *c_p, - Eterm pid, - Eterm module, - Eterm function, - Eterm args[], - int nargs); - int erts_call_dirty_bif(ErtsSchedulerData *esdp, Process *c_p, BeamInstr *I, Eterm *reg); diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 93613ac2eb..687fd39d58 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -266,6 +266,7 @@ bif erlang:demonitor/1 bif erlang:demonitor/2 bif erlang:is_process_alive/1 +bif erts_internal:is_process_alive/2 bif erlang:error/1 error_1 bif erlang:error/2 error_2 diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index fdf307da1b..f203d85ca9 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -937,6 +937,24 @@ erts_dsig_send_demonitor(ErtsDSigData *dsdp, Eterm watcher, return res; } +static int can_send_seqtrace_token(ErtsSendContext* ctx, Eterm token) { + Eterm label; + + if (ctx->dep->flags & DFLAG_BIG_SEQTRACE_LABELS) { + /* The other end is capable of handling arbitrary seq_trace labels. */ + return 1; + } + + /* The other end only tolerates smalls, but since we could potentially be + * talking to an old 32-bit emulator from a 64-bit one, we have to check + * whether the label is small on any emulator. */ + label = SEQ_TRACE_T_LABEL(token); + + return is_small(label) && + signed_val(label) <= (ERTS_SINT32_MAX >> _TAG_IMMED1_SIZE) && + signed_val(label) >= (ERTS_SINT32_MIN >> _TAG_IMMED1_SIZE); +} + int erts_dsig_send_msg(Eterm remote, Eterm message, ErtsSendContext* ctx) { @@ -970,37 +988,38 @@ erts_dsig_send_msg(Eterm remote, Eterm message, ErtsSendContext* ctx) "%T", remote); msize = size_object(message); if (have_seqtrace(token)) { - tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_label = SEQ_TRACE_T_DTRACE_LABEL(token); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); } } #endif - if (token != NIL) { - Eterm el1, el2; - if (ctx->dep->flags & DFLAG_SEND_SENDER) { - el1 = make_small(DOP_SEND_SENDER_TT); - el2 = sender->common.id; - } - else { - el1 = make_small(DOP_SEND_TT); - el2 = am_Empty; - } - ctl = TUPLE4(&ctx->ctl_heap[0], el1, el2, remote, token); - } - else { - Eterm el1, el2; + { + Eterm dist_op, sender_id; + int send_token; + + send_token = (token != NIL && can_send_seqtrace_token(ctx, token)); + if (ctx->dep->flags & DFLAG_SEND_SENDER) { - el1 = make_small(DOP_SEND_SENDER); - el2 = sender->common.id; + dist_op = make_small(send_token ? + DOP_SEND_SENDER_TT : + DOP_SEND_SENDER); + sender_id = sender->common.id; + } else { + dist_op = make_small(send_token ? + DOP_SEND_TT : + DOP_SEND); + sender_id = am_Empty; } - else { - el1 = make_small(DOP_SEND); - el2 = am_Empty; + + if (send_token) { + ctl = TUPLE4(&ctx->ctl_heap[0], dist_op, sender_id, remote, token); + } else { + ctl = TUPLE3(&ctx->ctl_heap[0], dist_op, sender_id, remote); } - ctl = TUPLE3(&ctx->ctl_heap[0], el1, el2, remote); } + DTRACE6(message_send, sender_name, receiver_name, msize, tok_label, tok_lastcnt, tok_serial); DTRACE7(message_send_remote, sender_name, node_name, receiver_name, @@ -1046,19 +1065,20 @@ erts_dsig_send_reg_msg(Eterm remote_name, Eterm message, "{%T,%s}", remote_name, node_name); msize = size_object(message); if (have_seqtrace(token)) { - tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_label = SEQ_TRACE_T_DTRACE_LABEL(token); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); } } #endif - if (token != NIL) + if (token != NIL && can_send_seqtrace_token(ctx, token)) ctl = TUPLE5(&ctx->ctl_heap[0], make_small(DOP_REG_SEND_TT), sender->common.id, am_Empty, remote_name, token); else ctl = TUPLE4(&ctx->ctl_heap[0], make_small(DOP_REG_SEND), sender->common.id, am_Empty, remote_name); + DTRACE6(message_send, sender_name, receiver_name, msize, tok_label, tok_lastcnt, tok_serial); DTRACE7(message_send_remote, sender_name, node_name, receiver_name, @@ -1110,7 +1130,7 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, erts_snprintf(reason_str, sizeof(DTRACE_CHARBUF_NAME(reason_str)), "%T", reason); if (have_seqtrace(token)) { - tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_label = SEQ_TRACE_T_DTRACE_LABEL(token); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); } diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h index c608fef816..dda2029a4c 100644 --- a/erts/emulator/beam/dist.h +++ b/erts/emulator/beam/dist.h @@ -45,7 +45,8 @@ #define DFLAG_MAP_TAG 0x20000 #define DFLAG_BIG_CREATION 0x40000 #define DFLAG_SEND_SENDER 0x80000 -#define DFLAG_NO_MAGIC 0x100000 /* internal for pending connection */ +#define DFLAG_BIG_SEQTRACE_LABELS 0x100000 +#define DFLAG_NO_MAGIC 0x200000 /* internal for pending connection */ /* Mandatory flags for distribution */ #define DFLAG_DIST_MANDATORY (DFLAG_EXTENDED_REFERENCES \ @@ -73,7 +74,8 @@ | DFLAG_UTF8_ATOMS \ | DFLAG_MAP_TAG \ | DFLAG_BIG_CREATION \ - | DFLAG_SEND_SENDER) + | DFLAG_SEND_SENDER \ + | DFLAG_BIG_SEQTRACE_LABELS) /* Flags addable by local distr implementations */ #define DFLAG_DIST_ADDABLE DFLAG_DIST_DEFAULT diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index 579e9b12f4..294bce115f 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1505,6 +1505,7 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name) res = ERL_DE_LOAD_ERROR_BAD_NAME; goto error; } + erts_atomic_init_nob(&(dh->refc), (erts_aint_t) 0); erts_atomic32_init_nob(&dh->port_count, 0); dh->full_path = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sys_strlen(path) + 1); @@ -1512,7 +1513,7 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name) dh->flags = 0; dh->status = ERL_DE_OK; - if (erts_add_driver_entry(dp, dh, 1) != 0 /* io.c */) { + if (erts_add_driver_entry(dp, dh, 1, 1) != 0 /* io.c */) { /* * The init in the driver struct did not return 0 */ diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 6106cfdcfd..bdca93428e 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -73,6 +73,9 @@ static Export *gather_msacc_res_trap; static Export *gather_gc_info_res_trap; static Export *gather_system_check_res_trap; +static Export *is_process_alive_trap; + + #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1) static char otp_version[] = ERLANG_OTP_VERSION; @@ -3501,34 +3504,53 @@ fun_info_mfa_1(BIF_ALIST_1) BIF_ERROR(p, BADARG); } +BIF_RETTYPE erts_internal_is_process_alive_2(BIF_ALIST_2) +{ + if (!is_internal_pid(BIF_ARG_1) || !is_internal_ordinary_ref(BIF_ARG_2)) + BIF_ERROR(BIF_P, BADARG); + erts_proc_sig_send_is_alive_request(BIF_P, BIF_ARG_1, BIF_ARG_2); + BIF_RET(am_ok); +} + BIF_RETTYPE is_process_alive_1(BIF_ALIST_1) { - if(is_internal_pid(BIF_ARG_1)) { - Process *rp; - - if (BIF_ARG_1 == BIF_P->common.id) - BIF_RET(am_true); - - rp = erts_proc_lookup_raw(BIF_ARG_1); - if (!rp) { - BIF_RET(am_false); - } - else { - if (erts_atomic32_read_acqb(&rp->state) & ERTS_PSFLG_EXITING) - ERTS_BIF_AWAIT_X_DATA_TRAP(BIF_P, BIF_ARG_1, am_false); - else - BIF_RET(am_true); - } - } - else if(is_external_pid(BIF_ARG_1)) { - if(external_pid_dist_entry(BIF_ARG_1) == erts_this_dist_entry) + if (is_internal_pid(BIF_ARG_1)) { + erts_aint32_t state; + Process *rp; + + if (BIF_ARG_1 == BIF_P->common.id) + BIF_RET(am_true); + + rp = erts_proc_lookup_raw(BIF_ARG_1); + if (!rp) + BIF_RET(am_false); + + state = erts_atomic32_read_acqb(&rp->state); + if (state & (ERTS_PSFLG_EXITING + | ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_SIG_IN_Q)) { + /* + * If in exiting state, trap out and send 'is alive' + * request and wait for it to complete termination. + * + * If process has signals enqueued, we need to + * send it an 'is alive' request via its signal + * queue in order to ensure that signal order is + * preserved (we may earlier have sent it an + * exit signal that has not been processed yet). + */ + BIF_TRAP1(is_process_alive_trap, BIF_P, BIF_ARG_1); + } + + BIF_RET(am_true); + } + + if (is_external_pid(BIF_ARG_1)) { + if (external_pid_dist_entry(BIF_ARG_1) == erts_this_dist_entry) BIF_RET(am_false); /* A pid from an old incarnation of this node */ - else - BIF_ERROR(BIF_P, BADARG); - } - else { - BIF_ERROR(BIF_P, BADARG); } + + BIF_ERROR(BIF_P, BADARG); } BIF_RETTYPE process_display_2(BIF_ALIST_2) @@ -5007,6 +5029,10 @@ erts_bif_info_init(void) = erts_export_put(am_erts_internal, am_gather_microstate_accounting_result, 2); gather_system_check_res_trap = erts_export_put(am_erts_internal, am_gather_system_check_result, 1); + + is_process_alive_trap = erts_export_put(am_erts_internal, am_is_process_alive, 1); + + process_info_init(); os_info_init(); } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index a076f0bf54..1953f79d79 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -1807,9 +1807,6 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2, return old_value; } else if (arg1 == am_label) { - if (! is_small(arg2)) { - return THE_NON_VALUE; - } new_seq_trace_token(p); if (build_result) { old_value = SEQ_TRACE_TOKEN_LABEL(p); diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 1e8e9e5e94..3836f28aa4 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -2508,25 +2508,20 @@ restart: if (have_no_seqtrace(SEQ_TRACE_TOKEN(c_p))) *esp++ = NIL; else { - Eterm sender = SEQ_TRACE_TOKEN_SENDER(c_p); - Uint sender_sz = is_immed(sender) ? 0 : size_object(sender); - ehp = HAllocX(build_proc, 6 + sender_sz, HEAP_XTRA); - if (sender_sz) { - sender = copy_struct(sender, sender_sz, &ehp, &MSO(build_proc)); - } - *esp++ = make_tuple(ehp); - ehp[0] = make_arityval(5); - ehp[1] = SEQ_TRACE_TOKEN_FLAGS(c_p); - ehp[2] = SEQ_TRACE_TOKEN_LABEL(c_p); - ehp[3] = SEQ_TRACE_TOKEN_SERIAL(c_p); - ehp[4] = sender; - ehp[5] = SEQ_TRACE_TOKEN_LASTCNT(c_p); - ASSERT(SEQ_TRACE_TOKEN_ARITY(c_p) == 5); - ASSERT(is_immed(ehp[1])); - ASSERT(is_immed(ehp[2])); - ASSERT(is_immed(ehp[3])); - ASSERT(is_immed(ehp[5])); - } + Eterm token; + Uint token_sz; + + ASSERT(SEQ_TRACE_TOKEN_ARITY(c_p) == 5); + ASSERT(is_immed(SEQ_TRACE_TOKEN_FLAGS(c_p))); + ASSERT(is_immed(SEQ_TRACE_TOKEN_SERIAL(c_p))); + ASSERT(is_immed(SEQ_TRACE_TOKEN_LASTCNT(c_p))); + + token = SEQ_TRACE_TOKEN(c_p); + token_sz = size_object(token); + + ehp = HAllocX(build_proc, token_sz, HEAP_XTRA); + *esp++ = copy_struct(token, token_sz, &ehp, &MSO(build_proc)); + } break; case matchEnableTrace: ASSERT(c_p == self); diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 83ed2e4cd6..179822cc0b 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -62,7 +62,7 @@ # include <sys/resource.h> #endif -#define ERTS_DEFAULT_NO_ASYNC_THREADS 10 +#define ERTS_DEFAULT_NO_ASYNC_THREADS 1 #define ERTS_DEFAULT_SCHED_STACK_SIZE 128 #define ERTS_DEFAULT_DCPU_SCHED_STACK_SIZE 40 @@ -605,6 +605,10 @@ void erts_usage(void) erts_fprintf(stderr, "-stbt type u|ns|ts|ps|s|nnts|nnps|tnnps|db\n"); erts_fprintf(stderr, "-sbwt val set scheduler busy wait threshold, valid values are:\n"); erts_fprintf(stderr, " none|very_short|short|medium|long|very_long.\n"); + erts_fprintf(stderr, "-sbwtdcpu val set dirty CPU scheduler busy wait threshold, valid values are:\n"); + erts_fprintf(stderr, " none|very_short|short|medium|long|very_long.\n"); + erts_fprintf(stderr, "-sbwtdio val set dirty IO scheduler busy wait threshold, valid values are:\n"); + erts_fprintf(stderr, " none|very_short|short|medium|long|very_long.\n"); erts_fprintf(stderr, "-scl bool enable/disable compaction of scheduler load,\n"); erts_fprintf(stderr, " see the erl(1) documentation for more info.\n"); erts_fprintf(stderr, "-sct cput set cpu topology,\n"); @@ -623,6 +627,10 @@ void erts_usage(void) erts_fprintf(stderr, " very_lazy|lazy|medium|eager|very_eager.\n"); erts_fprintf(stderr, "-swt val set scheduler wakeup threshold, valid values are:\n"); erts_fprintf(stderr, " very_low|low|medium|high|very_high.\n"); + erts_fprintf(stderr, "-swtdcpu val set dirty CPU scheduler wakeup threshold, valid values are:\n"); + erts_fprintf(stderr, " very_low|low|medium|high|very_high.\n"); + erts_fprintf(stderr, "-swtdio val set dirty IO scheduler wakeup threshold, valid values are:\n"); + erts_fprintf(stderr, " very_low|low|medium|high|very_high.\n"); erts_fprintf(stderr, "-sss size suggested stack size in kilo words for scheduler threads,\n"); erts_fprintf(stderr, " valid range is [%d-%d] (default %d)\n", ERTS_SCHED_THREAD_MIN_STACK_SIZE, @@ -1687,15 +1695,41 @@ erl_start(int argc, char **argv) erts_usage(); } } + else if (has_prefix("bwtdcpu", sub_param)) { + arg = get_arg(sub_param + 7, argv[i+1], &i); + + if (erts_sched_set_busy_wait_threshold(ERTS_SCHED_DIRTY_CPU, arg) != 0) { + erts_fprintf(stderr, "bad dirty CPU scheduler busy wait threshold: %s\n", + arg); + erts_usage(); + } + + VERBOSE(DEBUG_SYSTEM, + ("dirty CPU scheduler wakeup threshold: %s\n", arg)); + } + else if (has_prefix("bwtdio", sub_param)) { + arg = get_arg(sub_param + 6, argv[i+1], &i); + + if (erts_sched_set_busy_wait_threshold(ERTS_SCHED_DIRTY_IO, arg) != 0) { + erts_fprintf(stderr, "bad dirty IO scheduler busy wait threshold: %s\n", + arg); + erts_usage(); + } + + VERBOSE(DEBUG_SYSTEM, + ("dirty IO scheduler wakeup threshold: %s\n", arg)); + } 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) { + arg = get_arg(sub_param + 3, argv[i+1], &i); + + if (erts_sched_set_busy_wait_threshold(ERTS_SCHED_NORMAL, arg) != 0) { erts_fprintf(stderr, "bad scheduler busy wait threshold: %s\n", arg); erts_usage(); } + VERBOSE(DEBUG_SYSTEM, - ("scheduler wakup threshold: %s\n", arg)); + ("scheduler wakeup threshold: %s\n", arg)); } else if (has_prefix("cl", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); @@ -1812,9 +1846,29 @@ erl_start(int argc, char **argv) VERBOSE(DEBUG_SYSTEM, ("scheduler wake cleanup threshold: %s\n", arg)); } + else if (has_prefix("wtdcpu", sub_param)) { + arg = get_arg(sub_param+6, argv[i+1], &i); + if (erts_sched_set_wakeup_other_threshold(ERTS_SCHED_DIRTY_CPU, arg) != 0) { + erts_fprintf(stderr, "dirty CPU scheduler wakeup threshold: %s\n", + arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, + ("dirty CPU scheduler wakeup threshold: %s\n", arg)); + } + else if (has_prefix("wtdio", sub_param)) { + arg = get_arg(sub_param+5, argv[i+1], &i); + if (erts_sched_set_wakeup_other_threshold(ERTS_SCHED_DIRTY_IO, arg) != 0) { + erts_fprintf(stderr, "dirty IO scheduler wakeup threshold: %s\n", + arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, + ("dirty IO scheduler wakeup threshold: %s\n", arg)); + } else if (has_prefix("wt", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); - if (erts_sched_set_wakeup_other_thresold(arg) != 0) { + if (erts_sched_set_wakeup_other_threshold(ERTS_SCHED_NORMAL, arg) != 0) { erts_fprintf(stderr, "scheduler wakeup threshold: %s\n", arg); erts_usage(); @@ -1824,7 +1878,7 @@ erl_start(int argc, char **argv) } else if (has_prefix("ws", sub_param)) { arg = get_arg(sub_param+2, argv[i+1], &i); - if (erts_sched_set_wakeup_other_type(arg) != 0) { + if (erts_sched_set_wakeup_other_type(ERTS_SCHED_NORMAL, arg) != 0) { erts_fprintf(stderr, "scheduler wakeup strategy: %s\n", arg); erts_usage(); diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index 8047a9567f..4ec6960997 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -490,7 +490,9 @@ Eterm erts_map_from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks0, Eterm *vs0, sys_memcpy(ks, ks0, n * sizeof(Eterm)); sys_memcpy(vs, vs0, n * sizeof(Eterm)); - erts_validate_and_sort_flatmap(mp); + if (!erts_validate_and_sort_flatmap(mp)) { + return THE_NON_VALUE; + } return make_flatmap(mp); } else { diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index ed7a9d37c2..51b7865c0b 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -315,7 +315,7 @@ erts_queue_dist_message(Process *rcvr, dtrace_proc_str(rcvr, receiver_name); if (have_seqtrace(token)) { - tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_label = SEQ_TRACE_T_DTRACE_LABEL(token); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); } @@ -323,7 +323,7 @@ erts_queue_dist_message(Process *rcvr, * TODO: We don't know the real size of the external message here. * -1 will appear to a D script as 4294967295. */ - DTRACE6(message_queued, receiver_name, -1, rcvr->msg.len + 1, + DTRACE6(message_queued, receiver_name, -1, rcvr->sig_qs.len + 1, tok_label, tok_lastcnt, tok_serial); } #endif @@ -640,7 +640,8 @@ erts_send_message(Process* sender, seq_trace_update_send(sender); seq_trace_output(stoken, message, SEQ_TRACE_SEND, receiver->common.id, sender); - seq_trace_size = 6; /* TUPLE5 */ + + seq_trace_size = size_object(stoken); } #ifdef USE_VM_PROBES if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) { @@ -689,7 +690,7 @@ erts_send_message(Process* sender, } if (DTRACE_ENABLED(message_send)) { if (have_seqtrace(stoken)) { - tok_label = signed_val(SEQ_TRACE_T_LABEL(stoken)); + tok_label = SEQ_TRACE_T_DTRACE_LABEL(stoken); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(stoken)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(stoken)); } diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 1d337d9792..0e0013e8a4 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -2934,6 +2934,44 @@ ERL_NIF_TERM enif_make_new_map(ErlNifEnv* env) return make_flatmap(mp); } +int enif_make_map_from_arrays(ErlNifEnv *env, + ERL_NIF_TERM keys[], + ERL_NIF_TERM values[], + size_t cnt, + ERL_NIF_TERM *map_out) +{ + ErtsHeapFactory factory; + int succeeded; + +#ifdef ERTS_NIF_ASSERT_IN_ENV + size_t index = 0; + + while (index < cnt) { + ASSERT_IN_ENV(env, keys[index], index, "key"); + ASSERT_IN_ENV(env, values[index], index, "value"); + index++; + } +#endif + + flush_env(env); + + erts_factory_proc_prealloc_init(&factory, env->proc, + cnt * 2 + MAP_HEADER_FLATMAP_SZ + 1); + + (*map_out) = erts_map_from_ks_and_vs(&factory, keys, values, cnt); + succeeded = (*map_out) != THE_NON_VALUE; + + if (!succeeded) { + erts_factory_undo(&factory); + } + + erts_factory_close(&factory); + + cache_env(env); + + return succeeded; +} + int enif_make_map_put(ErlNifEnv* env, Eterm map_in, Eterm key, @@ -3730,16 +3768,26 @@ static Eterm mkatom(const char *str) return am_atom_put(str, sys_strlen(str)); } -static struct tainted_module_t +struct tainted_module_t { struct tainted_module_t* next; Eterm module_atom; -}*first_tainted_module = NULL; +}; + +erts_atomic_t first_taint; /* struct tainted_module_t* */ -static void add_taint(Eterm mod_atom) +void erts_add_taint(Eterm mod_atom) { - struct tainted_module_t* t; - for (t=first_tainted_module ; t!=NULL; t=t->next) { +#ifdef ERTS_ENABLE_LOCK_CHECK + extern erts_rwmtx_t erts_driver_list_lock; /* Mutex for driver list */ +#endif + struct tainted_module_t *first, *t; + + ERTS_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_driver_list_lock) + || erts_thr_progress_is_blocking()); + + first = (struct tainted_module_t*) erts_atomic_read_nob(&first_taint); + for (t=first ; t; t=t->next) { if (t->module_atom == mod_atom) { return; } @@ -3747,22 +3795,24 @@ static void add_taint(Eterm mod_atom) t = erts_alloc_fnf(ERTS_ALC_T_TAINT, sizeof(*t)); if (t != NULL) { t->module_atom = mod_atom; - t->next = first_tainted_module; - first_tainted_module = t; + t->next = first; + erts_atomic_set_nob(&first_taint, (erts_aint_t)t); } } Eterm erts_nif_taints(Process* p) { - struct tainted_module_t* t; + struct tainted_module_t *first, *t; unsigned cnt = 0; Eterm list = NIL; Eterm* hp; - for (t=first_tainted_module ; t!=NULL; t=t->next) { + + first = (struct tainted_module_t*) erts_atomic_read_nob(&first_taint); + for (t=first ; t!=NULL; t=t->next) { cnt++; } hp = HAlloc(p,cnt*2); - for (t=first_tainted_module ; t!=NULL; t=t->next) { + for (t=first ; t!=NULL; t=t->next) { list = CONS(hp, t->module_atom, list); hp += 2; } @@ -3771,9 +3821,11 @@ Eterm erts_nif_taints(Process* p) void erts_print_nif_taints(fmtfn_t to, void* to_arg) { - struct tainted_module_t* t; + struct tainted_module_t *t; const char* delim = ""; - for (t=first_tainted_module ; t!=NULL; t=t->next) { + + t = (struct tainted_module_t*) erts_atomic_read_nob(&first_taint); + for ( ; t; t = t->next) { const Atom* atom = atom_tab(atom_val(t->module_atom)); erts_cbprintf(to,to_arg,"%s%.*s", delim, atom->len, atom->name); delim = ","; @@ -3887,6 +3939,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT; Eterm ret = am_ok; int veto; + int taint = 1; struct erl_module_nif* lib = NULL; struct erl_module_instance* this_mi; struct erl_module_instance* prev_mi; @@ -3933,10 +3986,15 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ASSERT(module_p != NULL); mod_atomp = atom_tab(atom_val(mod_atom)); - init_func = erts_static_nif_get_nif_init((char*)mod_atomp->name, mod_atomp->len); - if (init_func != NULL) - handle = init_func; - + { + ErtsStaticNifEntry* sne; + sne = erts_static_nif_get_nif_init((char*)mod_atomp->name, mod_atomp->len); + if (sne != NULL) { + init_func = sne->nif_init; + handle = init_func; + taint = sne->taint; + } + } this_mi = &module_p->curr; prev_mi = &module_p->old; if (in_area(caller, module_p->old.code_hdr, module_p->old.code_length)) { @@ -3973,7 +4031,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) " function: '%s'", errdesc.str); } - else if ((add_taint(mod_atom), + else if ((taint ? erts_add_taint(mod_atom) : 0, (entry = erts_sys_ddll_call_nif_init(init_func)) == NULL)) { ret = load_nif_error(BIF_P, bad_lib, "Library init-call unsuccessful"); } diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index e051ecb26e..1906da732b 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -53,7 +53,7 @@ ** 2.12: 20.0 add enif_select, enif_open_resource_type_x ** 2.13: 20.1 add enif_ioq ** 2.14: 21.0 add enif_ioq_peek_head, enif_(mutex|cond|rwlock|thread)_name -** enif_vfprintf, enif_vsnprintf +** enif_vfprintf, enif_vsnprintf, enif_make_map_from_arrays */ #define ERL_NIF_MAJOR_VERSION 2 #define ERL_NIF_MINOR_VERSION 14 diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index 744f7c9f69..61f8fcf6ed 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -208,6 +208,8 @@ ERL_NIF_API_FUNC_DECL(char*,enif_thread_name,(ErlNifTid)); ERL_NIF_API_FUNC_DECL(int,enif_vfprintf,(FILE*, const char *fmt, va_list)); ERL_NIF_API_FUNC_DECL(int,enif_vsnprintf,(char*, size_t, const char *fmt, va_list)); +ERL_NIF_API_FUNC_DECL(int,enif_make_map_from_arrays,(ErlNifEnv *env, ERL_NIF_TERM keys[], ERL_NIF_TERM values[], size_t cnt, ERL_NIF_TERM *map_out)); + /* ** ADD NEW ENTRIES HERE (before this comment) !!! */ @@ -389,6 +391,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_vsnprintf,(char*, size_t, const char *fmt, va_lis # define enif_thread_name ERL_NIF_API_FUNC_MACRO(enif_thread_name) # define enif_vfprintf ERL_NIF_API_FUNC_MACRO(enif_vfprintf) # define enif_vsnprintf ERL_NIF_API_FUNC_MACRO(enif_vsnprintf) +# define enif_make_map_from_arrays ERL_NIF_API_FUNC_MACRO(enif_make_map_from_arrays) /* ** ADD NEW ENTRIES HERE (before this comment) diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index ca83e70046..1f147011a8 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -1051,14 +1051,16 @@ static void erts_lcnt_enable_dist_lock_count(void *dep_raw, void *enable) { if(enable) { erts_lcnt_install_new_lock_info(&dep->rwmtx.lcnt, "dist_entry", dep->sysname, ERTS_LOCK_TYPE_RWMUTEX | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION); - erts_lcnt_install_new_lock_info(&dep->lnk_mtx.lcnt, "dist_entry_links", dep->sysname, - ERTS_LOCK_TYPE_MUTEX | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION); erts_lcnt_install_new_lock_info(&dep->qlock.lcnt, "dist_entry_out_queue", dep->sysname, ERTS_LOCK_TYPE_MUTEX | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION); + if (dep->mld) + erts_lcnt_install_new_lock_info(&dep->mld->mtx.lcnt, "dist_entry_links", dep->sysname, + ERTS_LOCK_TYPE_MUTEX | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION); } else { erts_lcnt_uninstall(&dep->rwmtx.lcnt); - erts_lcnt_uninstall(&dep->lnk_mtx.lcnt); erts_lcnt_uninstall(&dep->qlock.lcnt); + if (dep->mld) + erts_lcnt_uninstall(&dep->mld->mtx.lcnt); } } diff --git a/erts/emulator/beam/erl_posix_str.c b/erts/emulator/beam/erl_posix_str.c index deb7e3e173..7b3e640d3f 100644 --- a/erts/emulator/beam/erl_posix_str.c +++ b/erts/emulator/beam/erl_posix_str.c @@ -156,6 +156,9 @@ erl_errno_id(error) #ifdef EFAULT case EFAULT: return "efault"; #endif +#ifdef EFTYPE + case EFTYPE: return "eftype"; +#endif #ifdef EFBIG case EFBIG: return "efbig"; #endif @@ -351,6 +354,9 @@ erl_errno_id(error) #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP)) case EOPNOTSUPP: return "eopnotsupp"; #endif +#ifdef EOVERFLOW + case EOVERFLOW: return "eoverflow"; +#endif #ifdef EPERM case EPERM: return "eperm"; #endif diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index e6f8460164..910f241a3a 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -532,14 +532,13 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) { Atom* module = atom_tab(atom_val(ep->info.mfa.module)); Atom* name = atom_tab(atom_val(ep->info.mfa.function)); - PRINT_STRING(res, fn, arg, "#Fun<"); + PRINT_STRING(res, fn, arg, "fun "); PRINT_BUF(res, fn, arg, module->name, module->len); - PRINT_CHAR(res, fn, arg, '.'); + PRINT_CHAR(res, fn, arg, ':'); PRINT_BUF(res, fn, arg, name->name, name->len); - PRINT_CHAR(res, fn, arg, '.'); + PRINT_CHAR(res, fn, arg, '/'); PRINT_SWORD(res, fn, arg, 'd', 0, 1, (ErlPfSWord) ep->info.mfa.arity); - PRINT_CHAR(res, fn, arg, '>'); } break; case FUN_DEF: diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c index 1b5cbb1919..1ba0b789ec 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.c +++ b/erts/emulator/beam/erl_proc_sig_queue.c @@ -40,6 +40,7 @@ #include "erl_gc.h" #include "bif.h" #include "erl_proc_sig_queue.h" +#include "dtrace-wrapper.h" #define ERTS_SIG_REDS_CNT_FACTOR 4 #define ERTS_PROC_SIG_TRACE_COUNT_LIMIT 200 @@ -48,7 +49,7 @@ * Note that not all signal are handled using this functionality! */ -#define ERTS_SIG_Q_OP_MAX 9 +#define ERTS_SIG_Q_OP_MAX 10 #define ERTS_SIG_Q_OP_EXIT 0 #define ERTS_SIG_Q_OP_EXIT_LINKED 1 @@ -59,7 +60,8 @@ #define ERTS_SIG_Q_OP_UNLINK 6 #define ERTS_SIG_Q_OP_GROUP_LEADER 7 #define ERTS_SIG_Q_OP_TRACE_CHANGE_STATE 8 -#define ERTS_SIG_Q_OP_PERSISTENT_MON_MSG ERTS_SIG_Q_OP_MAX +#define ERTS_SIG_Q_OP_PERSISTENT_MON_MSG 9 +#define ERTS_SIG_Q_OP_IS_ALIVE ERTS_SIG_Q_OP_MAX #define ERTS_SIG_Q_TYPE_MAX (ERTS_MON_LNK_TYPE_MAX + 5) @@ -184,6 +186,11 @@ typedef struct { Eterm heap[1]; } ErtsSigGroupLeader; +typedef struct { + Eterm message; + Eterm requester; +} ErtsIsAliveRequest; + static int handle_msg_tracing(Process *c_p, ErtsSigRecvTracing *tracing, ErtsMessage ***next_nm_sig); @@ -359,20 +366,47 @@ sig_enqueue_trace(Process *c_p, ErtsMessage *sig, int op, #ifdef USE_VM_PROBES case ERTS_SIG_Q_OP_EXIT: - case ERTS_SIG_Q_OP_EXIT_LINKED: { - ErtsExitSignalData *xsigd = get_exit_signal_data(sig); - if(DTRACE_ENABLED(process_exit_signal) && is_pid(xsigd->from)) { - DTRACE_CHARBUF(sender_str, DTRACE_TERM_BUF_SIZE); - DTRACE_CHARBUF(receiver_str, DTRACE_TERM_BUF_SIZE); - DTRACE_CHARBUF(reason_buf, DTRACE_TERM_BUF_SIZE); + case ERTS_SIG_Q_OP_EXIT_LINKED: + + if (DTRACE_ENABLED(process_exit_signal)) { + Uint16 type = ERTS_PROC_SIG_TYPE(((ErtsSignal *) sig)->common.tag); + Eterm reason, from; + + if (type == ERTS_SIG_Q_TYPE_GEN_EXIT) { + ErtsExitSignalData *xsigd = get_exit_signal_data(sig); + reason = xsigd->reason; + from = xsigd->from; + } + else { + ErtsLink *lnk = (ErtsLink *) sig, *olnk; + + ASSERT(type == ERTS_LNK_TYPE_PROC + || type == ERTS_LNK_TYPE_PORT + || type == ERTS_LNK_TYPE_DIST_PROC); + + olnk = erts_link_to_other(lnk, NULL); + reason = lnk->other.item; + from = olnk->other.item; + } + + if (is_pid(from)) { - dtrace_pid_str(from, sender_str); - dtrace_proc_str(rp, receiver_str); - erts_snprintf(reason_buf, sizeof(DTRACE_CHARBUF_NAME(reason_buf)) - 1, "%T", reason); - DTRACE3(process_exit_signal, sender_str, receiver_str, reason_buf); + DTRACE_CHARBUF(sender_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(receiver_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(reason_buf, DTRACE_TERM_BUF_SIZE); + + if (reason == am_kill) { + reason = am_killed; + } + + dtrace_pid_str(from, sender_str); + dtrace_proc_str(rp, receiver_str); + erts_snprintf(reason_buf, sizeof(DTRACE_CHARBUF_NAME(reason_buf)) - 1, "%T", reason); + DTRACE3(process_exit_signal, sender_str, receiver_str, reason_buf); + } } break; - } + #endif default: @@ -548,6 +582,43 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) return res; } +static int +maybe_elevate_sig_handling_prio(Process *c_p, Eterm other) +{ + /* + * returns: + * > 0 -> elevated prio; process alive or exiting + * < 0 -> no elevation needed; process alive or exiting + * 0 -> process terminated (free) + */ + int res; + Process *rp; + erts_aint32_t state, my_prio, other_prio; + + rp = erts_proc_lookup_raw(other); + if (!rp) + res = 0; + else { + res = -1; + state = erts_atomic32_read_nob(&c_p->state); + my_prio = ERTS_PSFLGS_GET_USR_PRIO(state); + + state = erts_atomic32_read_nob(&rp->state); + other_prio = ERTS_PSFLGS_GET_USR_PRIO(state); + + if (other_prio > my_prio) { + /* Others prio is lower than mine; elevate it... */ + res = !!erts_sig_prio(other, my_prio); + if (res) { + /* ensure handled if dirty executing... */ + state = erts_atomic32_read_nob(&rp->state); + ensure_dirty_proc_handled(other, state, my_prio); + } + } + } + return res; +} + void erts_proc_sig_fetch(Process *proc) { @@ -681,13 +752,14 @@ send_gen_exit_signal(Process *c_p, Eterm from_tag, seq_trace_update_send(c_p); #ifdef USE_VM_PROBES + utag_sz = 0; + utag = NIL; if (c_p && token != NIL && (DT_UTAG_FLAGS(c_p) & DT_UTAG_SPREADING)) { utag_sz = size_object(DT_UTAG(c_p)); utag = DT_UTAG(c_p); } else if (token == am_have_dt_utag) { - utag_sz = 0; - utag = token = NIL; + token = NIL; } hsz += utag_sz; #endif @@ -765,7 +837,7 @@ send_gen_exit_signal(Process *c_p, Eterm from_tag, s_utag = (is_immed(utag) ? utag : copy_struct(utag, utag_sz, &hp, ohp)); - ERL_MESSAGE_DT_UTAG(mp) = utag; + ERL_MESSAGE_DT_UTAG(mp) = s_utag; #endif ERL_MESSAGE_TERM(mp) = ERTS_PROC_SIG_MAKE_TAG(op, @@ -1215,33 +1287,10 @@ erts_proc_sig_send_group_leader(Process *c_p, Eterm to, Eterm gl, Eterm ref) if (!res) destroy_sig_group_leader(sgl); else if (c_p) { - int prio_res = !0; erts_aint_t flags, rm_flags = ERTS_SIG_GL_FLG_SENDER; - Process *rp; - erts_aint32_t state, my_prio, other_prio; - - state = erts_atomic32_read_nob(&c_p->state); - my_prio = ERTS_PSFLGS_GET_USR_PRIO(state); - - rp = erts_proc_lookup_raw(to); - if (!rp) - prio_res = 0; - else { - state = erts_atomic32_read_nob(&rp->state); - other_prio = ERTS_PSFLGS_GET_USR_PRIO(state); - - if (other_prio > my_prio) { - /* Others prio is lower than mine; elevate it... */ - prio_res = erts_sig_prio(to, my_prio); - if (prio_res) { - state = erts_atomic32_read_nob(&rp->state); - ensure_dirty_proc_handled(to, state, my_prio); - } - } - } + int prio_res = maybe_elevate_sig_handling_prio(c_p, to); if (!prio_res) rm_flags |= ERTS_SIG_GL_FLG_ACTIVE; - flags = erts_atomic_read_band_nob(&sgl->flags, ~rm_flags); if (!prio_res && (flags & ERTS_SIG_GL_FLG_ACTIVE)) res = 0; /* We deactivated signal... */ @@ -1253,6 +1302,99 @@ erts_proc_sig_send_group_leader(Process *c_p, Eterm to, Eterm gl, Eterm ref) group_leader_reply(c_p, c_p->common.id, ref, 0); } +void +erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to, Eterm ref) +{ + ErlHeapFragment *hfrag; + Uint hsz; + Eterm *hp, *start_hp, ref_cpy, msg; + ErlOffHeap *ohp; + ErtsMessage *mp; + ErtsIsAliveRequest *alive_req; + + ASSERT(is_internal_ordinary_ref(ref)); + + hsz = ERTS_REF_THING_SIZE + 3 + sizeof(ErtsIsAliveRequest)/sizeof(Eterm); + + mp = erts_alloc_message(hsz, &hp); + hfrag = &mp->hfrag; + mp->next = NULL; + ohp = &hfrag->off_heap; + start_hp = hp; + + ref_cpy = STORE_NC(&hp, ohp, ref); + msg = TUPLE2(hp, ref_cpy, am_false); /* default res 'false' */ + hp += 3; + + hfrag->used_size = hp - start_hp; + + alive_req = (ErtsIsAliveRequest *) (char *) hp; + alive_req->message = msg; + alive_req->requester = c_p->common.id; + + ERL_MESSAGE_TERM(mp) = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_IS_ALIVE, + ERTS_SIG_Q_TYPE_UNDEFINED, + 0); + ERL_MESSAGE_TOKEN(mp) = NIL; + ERL_MESSAGE_FROM(mp) = am_system; +#ifdef USE_VM_PROBES + ERL_MESSAGE_DT_UTAG(mp) = NIL; +#endif + + if (proc_queue_signal(c_p, to, (ErtsSignal *) mp, ERTS_SIG_Q_OP_IS_ALIVE)) + (void) maybe_elevate_sig_handling_prio(c_p, to); + else { + /* It wasn't alive; reply to ourselves... */ + mp->next = NULL; + mp->data.attached = ERTS_MSG_COMBINED_HFRAG; + erts_queue_message(c_p, ERTS_PROC_LOCK_MAIN, + mp, msg, am_system); + } +} + +static void +is_alive_response(Process *c_p, ErtsMessage *mp, int is_alive) +{ + /* + * Sender prepared the message for us. Just patch + * the result if necessary. The default prepared + * result is 'false'. + */ + Process *rp; + ErtsIsAliveRequest *alive_req; + + alive_req = (ErtsIsAliveRequest *) (char *) (&mp->hfrag.mem[0] + + mp->hfrag.used_size); + + + ASSERT(ERTS_SIG_IS_NON_MSG(mp)); + ASSERT(ERTS_PROC_SIG_OP(((ErtsSignal *) mp)->common.tag) + == ERTS_SIG_Q_OP_IS_ALIVE); + ASSERT(mp->hfrag.alloc_size > mp->hfrag.used_size); + ASSERT((mp->hfrag.alloc_size - mp->hfrag.used_size)*sizeof(UWord) + >= sizeof(ErtsIsAliveRequest)); + ASSERT(is_internal_pid(alive_req->requester)); + ASSERT(alive_req->requester != c_p->common.id); + ASSERT(is_tuple_arity(alive_req->message, 2)); + ASSERT(is_internal_ordinary_ref(tuple_val(alive_req->message)[1])); + ASSERT(tuple_val(alive_req->message)[2] == am_false); + + ERL_MESSAGE_TERM(mp) = alive_req->message; + mp->data.attached = ERTS_MSG_COMBINED_HFRAG; + mp->next = NULL; + + rp = erts_proc_lookup(alive_req->requester); + if (!rp) + erts_cleanup_messages(mp); + else { + if (is_alive) { /* patch result... */ + Eterm *tp = tuple_val(alive_req->message); + tp[2] = am_true; + } + erts_queue_message(rp, 0, mp, alive_req->message, am_system); + } +} + static ERTS_INLINE void adjust_tracing_state(Process *c_p, ErtsSigRecvTracing *tracing, int setup) { @@ -1447,8 +1589,8 @@ handle_exit_signal(Process *c_p, ErtsSigRecvTracing *tracing, { ErtsMessage *conv_msg = NULL; ErtsExitSignalData *xsigd = NULL; - ErtsLinkData *ldp; - ErtsLink *dlnk; + ErtsLinkData *ldp = NULL; /* Avoid erroneous warning... */ + ErtsLink *dlnk = NULL; /* Avoid erroneous warning... */ Eterm tag = ((ErtsSignal *) sig)->common.tag; Uint16 type = ERTS_PROC_SIG_TYPE(tag); int op = ERTS_PROC_SIG_OP(tag); @@ -1472,8 +1614,6 @@ handle_exit_signal(Process *c_p, ErtsSigRecvTracing *tracing, /* Link no longer active; ignore... */ ignore = !0; destroy = !0; - ldp = NULL; /* Avoid erroneous warning... */ - dlnk = NULL; /* Avoid erroneous warning... */ } else { ignore = 0; @@ -2355,6 +2495,13 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, break; } + case ERTS_SIG_Q_OP_IS_ALIVE: + ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + remove_nm_sig(c_p, sig, next_nm_sig); + is_alive_response(c_p, sig, !0); + ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + break; + case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: { Uint16 type = ERTS_PROC_SIG_TYPE(tag); @@ -2667,6 +2814,12 @@ erts_proc_sig_handle_exit(Process *c_p, int *redsp) break; } + case ERTS_SIG_Q_OP_IS_ALIVE: + ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + is_alive_response(c_p, sig, 0); + ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + break; + case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: destroy_trace_info((ErtsSigTraceInfo *) sig); break; @@ -2803,6 +2956,7 @@ erts_proc_sig_signal_size(ErtsSignal *sig) break; case ERTS_SIG_Q_OP_PERSISTENT_MON_MSG: + case ERTS_SIG_Q_OP_IS_ALIVE: size = ((ErtsMessage *) sig)->hfrag.alloc_size; size *= sizeof(Eterm); size += sizeof(ErtsMessage) - sizeof(Eterm); @@ -3069,7 +3223,7 @@ handle_message_enqueued_tracing(Process *c_p, Eterm seq_trace_token = ERL_MESSAGE_TOKEN(msg); if (seq_trace_token != NIL && is_tuple(seq_trace_token)) { - tok_label = signed_val(SEQ_TRACE_T_LABEL(seq_trace_token)); + tok_label = SEQ_TRACE_T_DTRACE_LABEL(seq_trace_token); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(seq_trace_token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(seq_trace_token)); } @@ -3514,6 +3668,7 @@ erts_proc_sig_debug_foreach_sig(Process *c_p, break; } + case ERTS_SIG_Q_OP_IS_ALIVE: case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: break; diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h index 433e30ce4a..56fe3e683e 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.h +++ b/erts/emulator/beam/erl_proc_sig_queue.h @@ -31,6 +31,7 @@ * - Link * - Unlink * - Group leader + * - Is process alive * - Trace change * * The signal queue consists of three parts: @@ -426,6 +427,30 @@ void erts_proc_sig_send_group_leader(Process *c_p, Eterm to, Eterm gl, Eterm ref); +/** + * + * @brief Send an 'is process alive' signal to a process. + * + * A response message '{Ref, Result}' is sent to the + * sender when performed where Ref is the reference passed + * as 'ref' argument, and Result is either 'true' or 'false'. + * + * @param[in] c_p Pointer to process struct of + * currently executing process. + * NULL if signal arrived via + * distribution. + * + * @param[in] to Identifier of receiver. + * + * @param[in] ref Reference to use in response + * message to the sending + * process (i.e., c_p). + * + */ +void +erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to, + Eterm ref); + /* * End of send operations of currently supported process signals. */ diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 7969025f57..be1306cd79 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -172,11 +172,19 @@ int erts_dio_sched_thread_suggested_stack_size = -1; ErtsLcPSDLocks erts_psd_required_locks[ERTS_PSD_SIZE]; #endif -static struct ErtsSchedBusyWait_ { +typedef struct { int aux_work; int tse; int sys_schedule; -} sched_busy_wait; +} ErtsBusyWaitParams; + +static ErtsBusyWaitParams sched_busy_wait_params[ERTS_SCHED_TYPE_LAST + 1]; + +static ERTS_INLINE ErtsBusyWaitParams * +sched_get_busy_wait_params(ErtsSchedulerData *esdp) +{ + return &sched_busy_wait_params[esdp->type]; +} int erts_disable_proc_not_running_opt; @@ -3262,7 +3270,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) erts_runq_unlock(rq); - spincount = sched_busy_wait.tse; + spincount = sched_get_busy_wait_params(esdp)->tse; if (ERTS_SCHEDULER_IS_DIRTY(esdp)) dirty_sched_wall_time_change(esdp, working = 0); @@ -3364,7 +3372,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) } flgs = sched_prep_cont_spin_wait(ssi); - spincount = sched_busy_wait.aux_work; + spincount = sched_get_busy_wait_params(esdp)->aux_work; if (!(flgs & ERTS_SSI_FLG_WAITING)) { ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING)); @@ -5250,24 +5258,35 @@ typedef enum { #define ERTS_WAKEUP_OTHER_FIXED_INC_LEGACY (CONTEXT_REDS/10) -static struct { +typedef struct { ErtsSchedWakeupOtherThreshold threshold; ErtsSchedWakeupOtherType type; int limit; int dec_shift; int dec_mask; void (*check)(ErtsRunQueue *rq, Uint32 flags); -} wakeup_other; +} ErtsWakeupOtherParams; + +static ErtsWakeupOtherParams sched_wakeup_other_params[ERTS_SCHED_TYPE_LAST + 1]; + +static ERTS_INLINE ErtsWakeupOtherParams * +runq_get_wakeup_other_params(ErtsRunQueue *rq) +{ + ErtsSchedulerData *esdp = rq->scheduler; + return &sched_wakeup_other_params[esdp->type]; +} static void wakeup_other_check(ErtsRunQueue *rq, Uint32 flags) { + ErtsWakeupOtherParams *wo_params = runq_get_wakeup_other_params(rq); int wo_reds = rq->wakeup_other_reds; + if (wo_reds) { int left_len = erts_atomic32_read_dirty(&rq->len) - 1; if (left_len < 1) { - int wo_reduce = wo_reds << wakeup_other.dec_shift; - wo_reduce &= wakeup_other.dec_mask; + int wo_reduce = wo_reds << wo_params->dec_shift; + wo_reduce &= wo_params->dec_mask; rq->wakeup_other -= wo_reduce; if (rq->wakeup_other < 0) rq->wakeup_other = 0; @@ -5275,7 +5294,7 @@ wakeup_other_check(ErtsRunQueue *rq, Uint32 flags) else { rq->wakeup_other += (left_len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC); - if (rq->wakeup_other > wakeup_other.limit) { + if (rq->wakeup_other > wo_params->limit) { if (ERTS_RUNQ_IX_IS_DIRTY(rq->ix)) { if (rq->waiting) { wake_dirty_scheduler(rq); @@ -5297,42 +5316,44 @@ wakeup_other_check(ErtsRunQueue *rq, Uint32 flags) } static void -wakeup_other_set_limit(void) +wakeup_other_set_limit(ErtsWakeupOtherParams *params) { - switch (wakeup_other.threshold) { + switch (params->threshold) { case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_HIGH: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH; - wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_VERY_HIGH; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH; + params->dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_VERY_HIGH; break; case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_HIGH: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH; - wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_HIGH; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH; + params->dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_HIGH; break; case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM; - wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_MEDIUM; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM; + params->dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_MEDIUM; break; case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_LOW: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_LOW; - wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_LOW; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_LOW; + params->dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_LOW; break; case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_LOW: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW; - wakeup_other.dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_VERY_LOW; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW; + params->dec_shift = ERTS_WAKEUP_OTHER_DEC_SHIFT_VERY_LOW; break; } - if (wakeup_other.dec_shift < 0) - wakeup_other.dec_mask = (1 << (sizeof(wakeup_other.dec_mask)*8 - + wakeup_other.dec_shift)) - 1; + + if (params->dec_shift < 0) + params->dec_mask = (1 << (sizeof(params->dec_mask)*8 + + params->dec_shift)) - 1; else { - wakeup_other.dec_mask = 0; - wakeup_other.dec_mask = ~wakeup_other.dec_mask; + params->dec_mask = 0; + params->dec_mask = ~params->dec_mask; } } static void wakeup_other_check_legacy(ErtsRunQueue *rq, Uint32 flags) { + ErtsWakeupOtherParams *wo_params = runq_get_wakeup_other_params(rq); int wo_reds = rq->wakeup_other_reds; if (wo_reds) { erts_aint32_t len = erts_atomic32_read_dirty(&rq->len); @@ -5341,7 +5362,7 @@ wakeup_other_check_legacy(ErtsRunQueue *rq, Uint32 flags) if (rq->wakeup_other < 0) rq->wakeup_other = 0; } - else if (rq->wakeup_other < wakeup_other.limit) + else if (rq->wakeup_other < wo_params->limit) rq->wakeup_other += len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC_LEGACY; else { if (flags & ERTS_RUNQ_FLG_PROTECTED) @@ -5357,23 +5378,23 @@ wakeup_other_check_legacy(ErtsRunQueue *rq, Uint32 flags) } static void -wakeup_other_set_limit_legacy(void) +wakeup_other_set_limit_legacy(ErtsWakeupOtherParams *params) { - switch (wakeup_other.threshold) { + switch (params->threshold) { case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_HIGH: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH_LEGACY; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH_LEGACY; break; case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_HIGH: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH_LEGACY; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH_LEGACY; break; case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM_LEGACY; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM_LEGACY; break; case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_LOW: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_LOW_LEGACY; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_LOW_LEGACY; break; case ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_LOW: - wakeup_other.limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW_LEGACY; + params->limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW_LEGACY; break; } } @@ -5381,15 +5402,21 @@ wakeup_other_set_limit_legacy(void) static void set_wakeup_other_data(void) { - switch (wakeup_other.type) { - case ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT: - wakeup_other.check = wakeup_other_check; - wakeup_other_set_limit(); - break; - case ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY: - wakeup_other.check = wakeup_other_check_legacy; - wakeup_other_set_limit_legacy(); - break; + ErtsSchedType type; + + for (type = ERTS_SCHED_TYPE_FIRST; type <= ERTS_SCHED_TYPE_LAST; type++) { + ErtsWakeupOtherParams *params = &sched_wakeup_other_params[type]; + + switch (params->type) { + case ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT: + params->check = wakeup_other_check; + wakeup_other_set_limit(params); + break; + case ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY: + params->check = wakeup_other_check_legacy; + wakeup_other_set_limit_legacy(params); + break; + } } } @@ -5444,56 +5471,64 @@ runq_supervisor(void *unused) void erts_early_init_scheduling(int no_schedulers) { + ErtsSchedType type; + aux_work_timeout_early_init(no_schedulers); - wakeup_other.threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM; - wakeup_other.type = ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT; - sched_busy_wait.sys_schedule = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM; - sched_busy_wait.tse = (ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM - * ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT); - sched_busy_wait.aux_work = (ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM - * ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_MEDIUM); + + for (type = ERTS_SCHED_TYPE_FIRST; type <= ERTS_SCHED_TYPE_LAST; type++) { + erts_sched_set_wakeup_other_threshold(type, "medium"); + erts_sched_set_wakeup_other_type(type, "default"); + + erts_sched_set_busy_wait_threshold(type, "medium"); + } + + erts_sched_set_busy_wait_threshold(ERTS_SCHED_DIRTY_CPU, "short"); + erts_sched_set_busy_wait_threshold(ERTS_SCHED_DIRTY_IO, "short"); } int -erts_sched_set_wakeup_other_thresold(char *str) -{ - ErtsSchedWakeupOtherThreshold threshold; - if (sys_strcmp(str, "very_high") == 0) - threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_HIGH; - else if (sys_strcmp(str, "high") == 0) - threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_HIGH; - else if (sys_strcmp(str, "medium") == 0) - threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM; - else if (sys_strcmp(str, "low") == 0) - threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_LOW; - else if (sys_strcmp(str, "very_low") == 0) - threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_LOW; - else - return EINVAL; - wakeup_other.threshold = threshold; - set_wakeup_other_data(); +erts_sched_set_wakeup_other_threshold(ErtsSchedType sched_type, char *str) +{ + ErtsWakeupOtherParams *params = &sched_wakeup_other_params[sched_type]; + + if (sys_strcmp(str, "very_high") == 0) { + params->threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_HIGH; + } else if (sys_strcmp(str, "high") == 0) { + params->threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_HIGH; + } else if (sys_strcmp(str, "medium") == 0) { + params->threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM; + } else if (sys_strcmp(str, "low") == 0) { + params->threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_LOW; + } else if (sys_strcmp(str, "very_low") == 0) { + params->threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_VERY_LOW; + } else { + return EINVAL; + } + return 0; } int -erts_sched_set_wakeup_other_type(char *str) +erts_sched_set_wakeup_other_type(ErtsSchedType sched_type, char *str) { - ErtsSchedWakeupOtherType type; - if (sys_strcmp(str, "default") == 0) - type = ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT; - else if (sys_strcmp(str, "legacy") == 0) - type = ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY; - else - return EINVAL; - wakeup_other.type = type; + ErtsWakeupOtherParams *params = &sched_wakeup_other_params[sched_type]; + + if (sys_strcmp(str, "default") == 0) { + params->type = ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT; + } else if (sys_strcmp(str, "legacy") == 0) { + params->type = ERTS_SCHED_WAKEUP_OTHER_TYPE_LEGACY; + } else { + return EINVAL; + } + return 0; } int -erts_sched_set_busy_wait_threshold(char *str) +erts_sched_set_busy_wait_threshold(ErtsSchedType sched_type, char *str) { - int sys_sched; - int aux_work_fact; + ErtsBusyWaitParams *params = &sched_busy_wait_params[sched_type]; + int aux_work_fact, sys_sched; if (sys_strcmp(str, "very_long") == 0) { sys_sched = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_VERY_LONG; @@ -5523,9 +5558,9 @@ erts_sched_set_busy_wait_threshold(char *str) return EINVAL; } - sched_busy_wait.sys_schedule = sys_sched; - sched_busy_wait.tse = sys_sched*ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT; - sched_busy_wait.aux_work = sys_sched*aux_work_fact; + params->sys_schedule = sys_sched; + params->tse = sys_sched * ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT; + params->aux_work = sys_sched * aux_work_fact; return 0; } @@ -9894,7 +9929,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) if (flags & ERTS_RUNQ_FLG_MISC_OP) exec_misc_ops(rq); - wakeup_other.check(rq, flags); + runq_get_wakeup_other_params(rq)->check(rq, flags); /* * Find a new port to run. @@ -10501,6 +10536,8 @@ done: return st; } + +static void exit_permanent_prio_elevation(Process *c_p, erts_aint32_t state); static void save_gc_task(Process *c_p, ErtsProcSysTask *st, int prio); static void save_dirty_task(Process *c_p, ErtsProcSysTask *st); @@ -10633,8 +10670,10 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds) reds, local_only); reds -= sig_reds; - if (state & ERTS_PSFLG_EXITING) - goto perm_elevate_prio; + if (state & ERTS_PSFLG_EXITING) { + exit_permanent_prio_elevation(c_p, state); + break; + } if (sig_res) break; @@ -10648,37 +10687,8 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds) st = NULL; } else { - erts_aint32_t a; - state = erts_atomic32_read_nob(&c_p->state); - - perm_elevate_prio: - - /* - * we are about to terminate; permanently elevate - * prio in order to ensure high prio signal - * handling... - */ - - a = state; - while (1) { - erts_aint32_t aprio, uprio, n, e; - ASSERT(!(a & ERTS_PSFLG_FREE)); - aprio = ERTS_PSFLGS_GET_ACT_PRIO(a); - uprio = ERTS_PSFLGS_GET_USR_PRIO(a); - if (aprio >= uprio) - break; /* user prio >= actual prio */ - /* - * actual prio is higher than user prio; raise - * user prio to actual prio... - */ - n = e = a; - n &= ~ERTS_PSFLGS_USR_PRIO_MASK; - n |= aprio << ERTS_PSFLGS_USR_PRIO_OFFSET; - a = erts_atomic32_cmpxchg_mb(&c_p->state, n, e); - if (a == e) - break; - } + exit_permanent_prio_elevation(c_p, state); } break; } @@ -10730,12 +10740,15 @@ cleanup_sys_tasks(Process *c_p, erts_aint32_t in_state, int in_reds) } switch (st->type) { + case ERTS_PSTT_PRIO_SIG: + state = erts_atomic32_read_nob(&c_p->state); + exit_permanent_prio_elevation(c_p, state); + /* fall through... */ case ERTS_PSTT_GC_MAJOR: case ERTS_PSTT_GC_MINOR: case ERTS_PSTT_CPC: case ERTS_PSTT_COHMQ: case ERTS_PSTT_ETS_FREE_FIXATION: - case ERTS_PSTT_PRIO_SIG: st_res = am_false; break; case ERTS_PSTT_CLA: @@ -10759,6 +10772,36 @@ cleanup_sys_tasks(Process *c_p, erts_aint32_t in_state, int in_reds) return reds; } +static void +exit_permanent_prio_elevation(Process *c_p, erts_aint32_t state) +{ + erts_aint32_t a; + /* + * we are about to terminate; permanently elevate + * prio in order to ensure high prio signal + * handling... + */ + a = state; + while (1) { + erts_aint32_t aprio, uprio, n, e; + ASSERT(a & ERTS_PSFLG_EXITING); + ASSERT(!(a & ERTS_PSFLG_FREE)); + aprio = ERTS_PSFLGS_GET_ACT_PRIO(a); + uprio = ERTS_PSFLGS_GET_USR_PRIO(a); + if (aprio >= uprio) + break; /* user prio >= actual prio */ + /* + * actual prio is higher than user prio; raise + * user prio to actual prio... + */ + n = e = a; + n &= ~ERTS_PSFLGS_USR_PRIO_MASK; + n |= aprio << ERTS_PSFLGS_USR_PRIO_OFFSET; + a = erts_atomic32_cmpxchg_mb(&c_p->state, n, e); + if (a == e) + break; + } +} void erts_execute_dirty_system_task(Process *c_p) @@ -12752,16 +12795,13 @@ erts_continue_exit_process(Process *p) erts_set_gc_state(p, 1); state = erts_atomic32_read_acqb(&p->state); - if ((state & ERTS_PSFLG_SYS_TASKS) - || p->dirty_sys_tasks - ) { + if ((state & ERTS_PSFLG_SYS_TASKS) || p->dirty_sys_tasks) { if (cleanup_sys_tasks(p, state, CONTEXT_REDS) >= CONTEXT_REDS/2) goto yield; } #ifdef DEBUG erts_proc_lock(p, ERTS_PROC_LOCK_STATUS); - ASSERT(p->sys_task_qs == NULL); ASSERT(ERTS_PROC_GET_DELAYED_GC_TASK_QS(p) == NULL); ASSERT(p->dirty_sys_tasks == NULL); erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS); @@ -12873,7 +12913,30 @@ erts_continue_exit_process(Process *p) ? ERTS_PROC_SET_DIST_ENTRY(p, NULL) : NULL); - erts_proc_unlock(p, ERTS_PROC_LOCKS_ALL); + + /* + * It might show up signal prio elevation tasks until we + * have entered free state. Cleanup such tasks now. + */ + state = erts_atomic32_read_acqb(&p->state); + if (!(state & ERTS_PSFLG_SYS_TASKS)) + erts_proc_unlock(p, ERTS_PROC_LOCKS_ALL); + else { + erts_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR); + + do { + (void) cleanup_sys_tasks(p, state, CONTEXT_REDS); + state = erts_atomic32_read_acqb(&p->state); + } while (state & ERTS_PSFLG_SYS_TASKS); + + erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN); + } + +#ifdef DEBUG + erts_proc_lock(p, ERTS_PROC_LOCK_STATUS); + ASSERT(p->sys_task_qs == NULL); + erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS); +#endif if (dep) { erts_do_net_exits(dep, (reason == am_kill) ? am_killed : reason); diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 0550fb05b5..f7c6c3435b 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -400,9 +400,12 @@ typedef struct { } ErtsRunPrioQueue; typedef enum { - ERTS_SCHED_NORMAL, - ERTS_SCHED_DIRTY_CPU, - ERTS_SCHED_DIRTY_IO + ERTS_SCHED_NORMAL = 0, + ERTS_SCHED_DIRTY_CPU = 1, + ERTS_SCHED_DIRTY_IO = 2, + + ERTS_SCHED_TYPE_FIRST = ERTS_SCHED_NORMAL, + ERTS_SCHED_TYPE_LAST = ERTS_SCHED_DIRTY_IO } ErtsSchedType; typedef struct ErtsSchedulerData_ ErtsSchedulerData; @@ -1250,7 +1253,24 @@ void erts_check_for_holes(Process* p); #define SEQ_TRACE_T_SENDER(token) (*(tuple_val(token) + 4)) #define SEQ_TRACE_T_LASTCNT(token) (*(tuple_val(token) + 5)) +#ifdef USE_VM_PROBES +/* The dtrace probe for seq_trace only supports 'int' labels, so we represent + * all values that won't fit into a 32-bit signed integer as ERTS_SINT32_MIN + * (bigints, tuples, etc). */ + +#define SEQ_TRACE_T_DTRACE_LABEL(token) \ + DTRACE_SEQ_TRACE_LABEL__(SEQ_TRACE_T_LABEL(token)) + +#define DTRACE_SEQ_TRACE_LABEL__(label_term) \ + (is_small((label_term)) ? \ + ((signed_val((label_term)) <= ERTS_SINT32_MAX && \ + signed_val((label_term)) >= ERTS_SINT32_MIN) ? \ + signed_val((label_term)) : ERTS_SINT32_MIN) \ + : ERTS_SINT32_MIN) +#endif + /* + * Possible flags for the flags field in ErlSpawnOpts below. */ @@ -1712,9 +1732,9 @@ ERTS_GLB_INLINE int erts_proclist_is_last(ErtsProcList *list, #endif -int erts_sched_set_wakeup_other_thresold(char *str); -int erts_sched_set_wakeup_other_type(char *str); -int erts_sched_set_busy_wait_threshold(char *str); +int erts_sched_set_wakeup_other_threshold(ErtsSchedType sched_type, char *str); +int erts_sched_set_wakeup_other_type(ErtsSchedType sched_type, char *str); +int erts_sched_set_busy_wait_threshold(ErtsSchedType sched_type, char *str); int erts_sched_set_wake_cleanup_threshold(char *); void erts_schedule_thr_prgr_later_op(void (*)(void *), diff --git a/erts/emulator/beam/erlang_dtrace.d b/erts/emulator/beam/erlang_dtrace.d index d0b10e0306..c47a37eb62 100644 --- a/erts/emulator/beam/erlang_dtrace.d +++ b/erts/emulator/beam/erlang_dtrace.d @@ -55,7 +55,8 @@ provider erlang { * @param sender the PID (string form) of the sender * @param receiver the PID (string form) of the receiver * @param size the size of the message being delivered (words) - * @param token_label for the sender's sequential trace token + * @param token_label for the sender's sequential trace token. This will be + * INT_MIN if the label does not fit into a 32-bit integer. * @param token_previous count for the sender's sequential trace token * @param token_current count for the sender's sequential trace token */ @@ -73,7 +74,8 @@ provider erlang { * @param node_name the Erlang node name (string form) of the receiver * @param receiver the PID/name (string form) of the receiver * @param size the size of the message being delivered (words) - * @param token_label for the sender's sequential trace token + * @param token_label for the sender's sequential trace token. This will be + * INT_MIN if the label does not fit into a 32-bit integer. * @param token_previous count for the sender's sequential trace token * @param token_current count for the sender's sequential trace token */ @@ -98,7 +100,8 @@ provider erlang { * @param receiver the PID (string form) of the receiver * @param size the size of the message being delivered (words) * @param queue_len length of the queue of the receiving process - * @param token_label for the sender's sequential trace token + * @param token_label for the sender's sequential trace token. This will be + * INT_MIN if the label does not fit into a 32-bit integer. * @param token_previous count for the sender's sequential trace token * @param token_current count for the sender's sequential trace token */ @@ -122,7 +125,8 @@ provider erlang { * @param receiver the PID (string form) of the receiver * @param size the size of the message being delivered (words) * @param queue_len length of the queue of the receiving process - * @param token_label for the sender's sequential trace token + * @param token_label for the sender's sequential trace token. This will be + * INT_MIN if the label does not fit into a 32-bit integer. * @param token_previous count for the sender's sequential trace token * @param token_current count for the sender's sequential trace token */ @@ -273,7 +277,8 @@ provider erlang { * @param node_name the Erlang node name (string form) of the receiver * @param receiver the PID (string form) of the process receiving EXIT signal * @param reason the reason for the exit (may be truncated) - * @param token_label for the sender's sequential trace token + * @param token_label for the sender's sequential trace token. This will be + * INT_MIN if the label does not fit into a 32-bit integer. * @param token_previous count for the sender's sequential trace token * @param token_current count for the sender's sequential trace token */ diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index d853b2e352..7724231cd5 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -116,6 +116,7 @@ extern void erts_post_nif(struct enif_environment_t* env); extern void erts_resource_stop(ErtsResource*, ErlNifEvent, int is_direct_call); void erts_fire_nif_monitor(ErtsMonitor *tmon); void erts_nif_demonitored(ErtsResource* resource); +extern void erts_add_taint(Eterm mod_atom); extern Eterm erts_nif_taints(Process* p); extern void erts_print_nif_taints(fmtfn_t to, void* to_arg); void erts_unload_nif(struct erl_module_nif* nif); @@ -1150,7 +1151,7 @@ typedef struct { #define ERTS_SPAWN_DRIVER 1 #define ERTS_SPAWN_EXECUTABLE 2 #define ERTS_SPAWN_ANY (ERTS_SPAWN_DRIVER | ERTS_SPAWN_EXECUTABLE) -int erts_add_driver_entry(ErlDrvEntry *drv, DE_Handle *handle, int driver_list_locked); +int erts_add_driver_entry(ErlDrvEntry *drv, DE_Handle *handle, int driver_list_locked, int taint); void erts_destroy_driver(erts_driver_t *drv); int erts_save_suspend_process_on_port(Port*, Process*); Port *erts_open_driver(erts_driver_t*, Eterm, char*, SysDriverOpts*, int *, int *); @@ -1175,8 +1176,17 @@ void erts_lcnt_update_port_locks(int enable); #endif /* driver_tab.c */ +typedef struct { + ErlDrvEntry* de; + int taint; +} ErtsStaticDriver; typedef void *(*ErtsStaticNifInitFPtr)(void); -ErtsStaticNifInitFPtr erts_static_nif_get_nif_init(const char *name, int len); +typedef struct ErtsStaticNifEntry_ { + const char *nif_name; + ErtsStaticNifInitFPtr nif_init; + int taint; +} ErtsStaticNifEntry; +ErtsStaticNifEntry* erts_static_nif_get_nif_init(const char *name, int len); int erts_is_static_nif(void *handle); void erts_init_static_drivers(void); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index b2afdc6bf2..66b8005975 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -61,7 +61,7 @@ extern ErlDrvEntry spawn_driver_entry; #ifndef __WIN32__ extern ErlDrvEntry forker_driver_entry; #endif -extern ErlDrvEntry *driver_tab[]; /* table of static drivers, only used during initialization */ +extern ErtsStaticDriver driver_tab[]; /* table of static drivers, only used during initialization */ erts_driver_t *driver_list; /* List of all drivers, static and dynamic. */ erts_rwmtx_t erts_driver_list_lock; /* Mutex for driver list */ @@ -2361,6 +2361,21 @@ set_port_connected(int bang_op, trace_port(prt, am_getting_linked, connect); } +#ifdef USE_VM_PROBES + if (DTRACE_ENABLED(port_connect)) { + Eterm old_connected = ERTS_PORT_GET_CONNECTED(prt); + DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(newprocess_str, DTRACE_TERM_BUF_SIZE); + + dtrace_pid_str(old_connected, process_str); + erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), + "%T", prt->common.id); + dtrace_pid_str(connect, newprocess_str); + DTRACE4(port_connect, process_str, port_str, prt->name, newprocess_str); + } +#endif + ERTS_PORT_SET_CONNECTED(prt, connect); if (IS_TRACED_FL(prt, F_TRACE_RECEIVE)) @@ -2370,18 +2385,6 @@ set_port_connected(int bang_op, trace_port_send(prt, from, TUPLE2(hp, prt->common.id, am_connected), 1); } -#ifdef USE_VM_PROBES - if (DTRACE_ENABLED(port_connect)) { - DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); - DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); - DTRACE_CHARBUF(newprocess_str, DTRACE_TERM_BUF_SIZE); - - dtrace_pid_str(connect, process_str); - erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), "%T", prt->common.id); - dtrace_proc_str(rp, newprocess_str); - DTRACE4(port_connect, process_str, port_str, prt->name, newprocess_str); - } -#endif } return ERTS_PORT_OP_DONE; @@ -2832,7 +2835,7 @@ void erts_init_io(int port_tab_size, int port_tab_size_ignore_files, int legacy_port_tab) { - ErlDrvEntry** dp; + ErtsStaticDriver* dp; UWord common_element_size; erts_rwmtx_opt_t drv_list_rwmtx_opts = ERTS_RWMTX_OPT_DEFAULT_INITER; drv_list_rwmtx_opts.type = ERTS_RWMTX_TYPE_EXTREMELY_FREQUENT_READ; @@ -2891,8 +2894,8 @@ void erts_init_io(int port_tab_size, init_driver(&forker_driver, &forker_driver_entry, NULL); #endif erts_init_static_drivers(); - for (dp = driver_tab; *dp != NULL; dp++) - erts_add_driver_entry(*dp, NULL, 1); + for (dp = driver_tab; dp->de != NULL; dp++) + erts_add_driver_entry(dp->de, NULL, 1, dp->taint); erts_tsd_set(driver_list_lock_status_key, NULL); erts_rwmtx_rwunlock(&erts_driver_list_lock); @@ -7348,7 +7351,8 @@ no_stop_select_callback(ErlDrvEvent event, void* private) } #define IS_DRIVER_VERSION_GE(DE,MAJOR,MINOR) \ - ((DE)->major_version >= (MAJOR) && (DE)->minor_version >= (MINOR)) + ((DE)->major_version > (MAJOR) || \ + ((DE)->major_version == (MAJOR) && (DE)->minor_version >= (MINOR))) static int init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) @@ -7431,13 +7435,14 @@ void add_driver_entry(ErlDrvEntry *drv){ * Ignore result of erts_add_driver_entry, the init is not * allowed to fail when drivers are added by drivers. */ - erts_add_driver_entry(drv, NULL, rec_lock != NULL); + erts_add_driver_entry(drv, NULL, rec_lock != NULL, 0); } -int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_locked) +int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, + int driver_list_locked, int taint) { erts_driver_t *dp = erts_alloc(ERTS_ALC_T_DRIVER, sizeof(erts_driver_t)); - int res; + int err = 0; if (!driver_list_locked) { erts_rwmtx_rwlock(&erts_driver_list_lock); @@ -7454,9 +7459,21 @@ int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_lo erts_tsd_set(driver_list_lock_status_key, (void *) 1); } - res = init_driver(dp, de, handle); + if (taint) { + Eterm name_atom = erts_atom_put((byte*)de->driver_name, + sys_strlen(de->driver_name), + ERTS_ATOM_ENC_LATIN1, 0); + if (is_atom(name_atom)) + erts_add_taint(name_atom); + else + err = 1; + } - if (res != 0) { + if (!err) { + err = init_driver(dp, de, handle); + } + + if (err) { /* * Remove it all again... */ @@ -7471,7 +7488,7 @@ int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_lo erts_tsd_set(driver_list_lock_status_key, NULL); erts_rwmtx_rwunlock(&erts_driver_list_lock); } - return res; + return err; } /* Not allowed for dynamic drivers */ diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab index 88d2ef9fa3..289436da6f 100644 --- a/erts/emulator/beam/msg_instrs.tab +++ b/erts/emulator/beam/msg_instrs.tab @@ -229,13 +229,13 @@ remove_message() { dtrace_proc_str(c_p, receiver_name); token2 = SEQ_TRACE_TOKEN(c_p); if (have_seqtrace(token2)) { - tok_label = signed_val(SEQ_TRACE_T_LABEL(token2)); + tok_label = SEQ_TRACE_T_DTRACE_LABEL(token2); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token2)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token2)); } DTRACE6(message_receive, receiver_name, size_object(ERL_MESSAGE_TERM(msgp)), - c_p->msg.len - 1, tok_label, tok_lastcnt, tok_serial); + c_p->sig_qs.len - 1, tok_label, tok_lastcnt, tok_serial); } #endif UNLINK_MESSAGE(c_p, msgp); diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index bc765a8c94..8b2d9098a8 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -710,7 +710,8 @@ is_boolean Fail=f ac => jump Fail is_boolean f? xy %hot -is_function2 Fail=f acq Arity => jump Fail +is_function2 Fail=f Literal=q Arity | literal_is_export(Literal) => +is_function2 Fail=f c Arity => jump Fail is_function2 Fail=f Fun a => jump Fail is_function2 f? S s diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index c21acadd8d..be6ab57eeb 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -366,29 +366,11 @@ typedef UWord BeamInstr; # define HAVE_INT64 1 typedef unsigned long Uint64; typedef long Sint64; -# ifdef ULONG_MAX -# define ERTS_UINT64_MAX ULONG_MAX -# endif -# ifdef LONG_MAX -# define ERTS_SINT64_MAX LONG_MAX -# endif -# ifdef LONG_MIN -# define ERTS_SINT64_MIN LONG_MIN -# endif # define ErtsStrToSint64 strtol # elif SIZEOF_LONG_LONG == 8 # define HAVE_INT64 1 typedef unsigned long long Uint64; typedef long long Sint64; -# ifdef ULLONG_MAX -# define ERTS_UINT64_MAX ULLONG_MAX -# endif -# ifdef LLONG_MAX -# define ERTS_SINT64_MAX LLONG_MAX -# endif -# ifdef LLONG_MIN -# define ERTS_SINT64_MIN LLONG_MIN -# endif # define ErtsStrToSint64 strtoll # else # error "No 64-bit integer type found" @@ -402,7 +384,7 @@ typedef long long Sint64; # define ERTS_SINT64_MAX ((Sint64) ((((Uint64) 1) << 63)-1)) #endif #ifndef ERTS_SINT64_MIN -# define ERTS_SINT64_MIN (-1*(((Sint64) 1) << 63)) +# define ERTS_SINT64_MIN ((Sint64) ((((Uint64) 1) << 63))) #endif #if SIZEOF_LONG == 4 @@ -415,6 +397,16 @@ typedef int Sint32; #error Found no appropriate type to use for 'Uint32' and 'Sint32' #endif +#ifndef ERTS_UINT32_MAX +# define ERTS_UINT32_MAX (~((Uint32) 0)) +#endif +#ifndef ERTS_SINT32_MAX +# define ERTS_SINT32_MAX ((Sint32) ((((Uint32) 1) << 31)-1)) +#endif +#ifndef ERTS_SINT32_MIN +# define ERTS_SINT32_MIN ((Sint32) ((((Uint32) 1) << 31))) +#endif + #if SIZEOF_INT == 2 typedef unsigned int Uint16; typedef int Sint16; @@ -425,6 +417,16 @@ typedef short Sint16; #error Found no appropriate type to use for 'Uint16' and 'Sint16' #endif +#ifndef ERTS_UINT16_MAX +# define ERTS_UINT16_MAX (~((Uint16) 0)) +#endif +#ifndef ERTS_SINT16_MAX +# define ERTS_SINT16_MAX ((Sint16) ((((Uint16) 1) << 15)-1)) +#endif +#ifndef ERTS_SINT16_MIN +# define ERTS_SINT16_MIN ((Sint16) ((((Uint16) 1) << 15))) +#endif + #if CHAR_BIT == 8 typedef unsigned char byte; #else diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 4294fb4f46..1a68f65b52 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -9930,6 +9930,12 @@ static int tcp_recv_closed(tcp_descriptor* desc) set_busy_port(desc->inet.port, 0); inet_reply_error_am(INETP(desc), am_closed); DEBUGF(("tcp_recv_closed(%ld): busy reply 'closed'\r\n", port)); + } else { + /* No blocking send op to reply to right now. + * If next op is a send, make sure it returns {error,closed} + * rather than {error,enotconn}. + */ + desc->tcp_add_flags |= TCP_ADDF_DELAYED_CLOSE_SEND; } if (!desc->inet.active) { /* We must cancel any timer here ! */ diff --git a/erts/emulator/test/beam_literals_SUITE.erl b/erts/emulator/test/beam_literals_SUITE.erl index 09761263e2..b447ca0210 100644 --- a/erts/emulator/test/beam_literals_SUITE.erl +++ b/erts/emulator/test/beam_literals_SUITE.erl @@ -248,35 +248,58 @@ literal_type_tests(Config) when is_list(Config) -> ok. make_test([{is_function=T,L}|Ts]) -> - [test(T, L),test(T, 0, L)|make_test(Ts)]; + [guard_test(T, L),guard_test(T, 0, L),body_test(T, L),body_test(T, 0, L)|make_test(Ts)]; make_test([{T,L}|Ts]) -> - [test(T, L)|make_test(Ts)]; + [guard_test(T, L),body_test(T, L)|make_test(Ts)]; make_test([]) -> []. -test(T, L) -> - S = lists:flatten(io_lib:format("begin io:format(\"~~p~n\", [{~p,~p}]), if ~w(~w) -> true; true -> false end end. ", [T, L, T, L])), - {ok,Toks,_Line} = erl_scan:string(S), - {ok,E} = erl_parse:parse_exprs(Toks), - {value,Val,_Bs} = erl_eval:exprs(E, []), +guard_test(_, L) when is_function(L) -> + %% Skip guard tests with exports - they are not literals + {atom,erl_anno:new(0),true}; +guard_test(T, L) -> + S = io_lib:format("begin io:format(\"~~p~n\", [{~p,~p}]), if ~w(~w) -> true; true -> false end end. ", [T, L, T, L]), + {Val,Expr} = eval_string(S), + Anno = erl_anno:new(0), + {match,Anno,{atom,Anno,Val},Expr}. + +guard_test(_, _, L) when is_function(L) -> + %% Skip guard tests with exports - they are not literals + {atom,erl_anno:new(0),true}; +guard_test(T, A, L) -> + S = io_lib:format("begin io:format(\"~~p~n\", [{~p,~p,~p}]), if ~w(~w, ~w) -> true; true -> false end end. ", [T,L,A,T,L,A]), + {Val,Expr} = eval_string(S), + Anno = erl_anno:new(0), + {match,Anno,{atom,Anno,Val},Expr}. + +body_test(T, L) -> + S = io_lib:format("begin io:format(\"~~p~n\", [{~p,~p}]), ~w(~w) end. ", [T,L,T,L]), + {Val,Expr} = eval_string(S), Anno = erl_anno:new(0), - {match,Anno,{atom,Anno,Val},hd(E)}. + {match,Anno,{atom,Anno,Val},Expr}. -test(T, A, L) -> - S = lists:flatten(io_lib:format("begin io:format(\"~~p~n\", [{~p,~p,~p}]), if ~w(~w, ~w) -> true; true -> false end end. ", - [T,L,A,T,L,A])), - {ok,Toks,_Line} = erl_scan:string(S), +body_test(T, A, L) -> + S = io_lib:format("begin io:format(\"~~p~n\", [{~p,~p,~p}]), ~w(~w,~w) end. ", [T,L,A,T,L,A]), + {Val,Expr} = eval_string(S), + Anno = erl_anno:new(0), + {match,Anno,{atom,Anno,Val},Expr}. + +eval_string(S) -> + {ok,Toks,_Line} = erl_scan:string(lists:flatten(S)), {ok,E} = erl_parse:parse_exprs(Toks), {value,Val,_Bs} = erl_eval:exprs(E, []), - Anno = erl_anno:new(0), - {match,Anno,{atom,Anno,Val},hd(E)}. - + {Val,hd(E)}. + literals() -> [42, 3.14, -3, 32982724987789283473473838474, [], - xxxx]. + "abc", + <<"abc">>, + {}, + xxxx, + fun erlang:erase/0]. type_tests() -> [is_boolean, diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index d16c6a320d..22706ae8b1 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -34,7 +34,8 @@ erl_crash_dump_bytes/1, is_builtin/1, error_stacktrace/1, error_stacktrace_during_call_trace/1, - group_leader_prio/1, group_leader_prio_dirty/1]). + group_leader_prio/1, group_leader_prio_dirty/1, + is_process_alive/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -48,7 +49,8 @@ all() -> atom_to_binary, binary_to_atom, binary_to_existing_atom, erl_crash_dump_bytes, min_max, erlang_halt, is_builtin, error_stacktrace, error_stacktrace_during_call_trace, - group_leader_prio, group_leader_prio_dirty]. + group_leader_prio, group_leader_prio_dirty, + is_process_alive]. %% Uses erlang:display to test that erts_printf does not do deep recursion display(Config) when is_list(Config) -> @@ -1076,6 +1078,27 @@ group_leader_prio_test(Dirty) -> TLs), ok. +is_process_alive(Config) when is_list(Config) -> + process_flag(priority, max), + Ps = lists:map(fun (_) -> + spawn_opt(fun () -> tok_loop() end, + [{priority, high}, link]) + end, + lists:seq(1, 2*erlang:system_info(schedulers))), + receive after 1000 -> ok end, %% Wait for load to spread + lists:foreach(fun (P) -> + %% Ensure that signal order is preserved + %% and that we are not starved due to + %% priority inversion + true = erlang:is_process_alive(P), + unlink(P), + true = erlang:is_process_alive(P), + exit(P, kill), + false = erlang:is_process_alive(P) + end, + Ps), + ok. + %% helpers id(I) -> I. diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index 294c42780d..40c7cc11e1 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -2589,8 +2589,18 @@ stop_driver(Port, Name) -> ok = erl_ddll:stop(). load_driver(Dir, Driver) -> + Before = erlang:system_info(taints), case erl_ddll:load_driver(Dir, Driver) of - ok -> ok; + ok -> + After = erlang:system_info(taints), + case lists:member(Driver, Before) of + true -> + After = Before; + false -> + true = lists:member(Driver, After), + Before = lists:delete(Driver, After) + end, + ok; {error, Error} = Res -> io:format("~s\n", [erl_ddll:format_error(Error)]), Res diff --git a/erts/emulator/test/module_info_SUITE.erl b/erts/emulator/test/module_info_SUITE.erl index ba9b564fdc..46a3bba732 100644 --- a/erts/emulator/test/module_info_SUITE.erl +++ b/erts/emulator/test/module_info_SUITE.erl @@ -23,7 +23,7 @@ -include_lib("common_test/include/ct.hrl"). -export([all/0, suite/0, - exports/1,functions/1,deleted/1,native/1,info/1]). + exports/1,functions/1,deleted/1,native/1,info/1,nifs/1]). %%-compile(native). @@ -38,7 +38,7 @@ all() -> modules(). modules() -> - [exports, functions, deleted, native, info]. + [exports, functions, deleted, native, info, nifs]. %% Should return all functions exported from this module. (local) all_exported() -> @@ -62,12 +62,24 @@ exports(Config) when is_list(Config) -> All = lists:sort(?MODULE:module_info(exports)), ok. -%% Test that the list of exported functions from this module is correct. +%% Test that the list of local and exported functions from this module is +%% correct. functions(Config) when is_list(Config) -> All = all_functions(), All = lists:sort(?MODULE:module_info(functions)), ok. +nifs(Config) when is_list(Config) -> + [] = ?MODULE:module_info(nifs), + + %% erl_tracer is guaranteed to be present and contain these NIFs + TraceNIFs = erl_tracer:module_info(nifs), + true = lists:member({enabled, 3}, TraceNIFs), + true = lists:member({trace, 5}, TraceNIFs), + 2 = length(TraceNIFs), + + ok. + %% Test that deleted modules cause badarg deleted(Config) when is_list(Config) -> Data = proplists:get_value(data_dir, Config), diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index b6e15ababb..a9eb4b2768 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -1170,6 +1170,12 @@ maps(Config) when is_list(Config) -> {1, M2} = make_map_remove_nif(M2, "key3"), {0, undefined} = make_map_remove_nif(self(), key), + M1 = maps_from_list_nif(maps:to_list(M1)), + M2 = maps_from_list_nif(maps:to_list(M2)), + M3 = maps_from_list_nif(maps:to_list(M3)), + + has_duplicate_keys = maps_from_list_nif([{1,1},{1,1}]), + verify_tmpmem(TmpMem), ok. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 194ece77a2..a0aef60cf1 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -2140,24 +2140,45 @@ static ERL_NIF_TERM make_map_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_ /* maps */ static ERL_NIF_TERM maps_from_list_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM cell = argv[0]; - ERL_NIF_TERM map = enif_make_new_map(env); - ERL_NIF_TERM tuple; - const ERL_NIF_TERM *pair; - int arity = -1; + ERL_NIF_TERM *keys, *values; + ERL_NIF_TERM result, cell; + unsigned count; - if (argc != 1 && !enif_is_list(env, cell)) return enif_make_badarg(env); + if (argc != 1 || !enif_get_list_length(env, argv[0], &count)) { + return enif_make_badarg(env); + } - /* assume sorted keys */ + keys = enif_alloc(sizeof(ERL_NIF_TERM) * count * 2); + values = keys + count; - while (!enif_is_empty_list(env,cell)) { - if (!enif_get_list_cell(env, cell, &tuple, &cell)) return enif_make_badarg(env); - if (enif_get_tuple(env,tuple,&arity,&pair)) { - enif_make_map_put(env, map, pair[0], pair[1], &map); - } + cell = argv[0]; + count = 0; + + while (!enif_is_empty_list(env, cell)) { + const ERL_NIF_TERM *pair; + ERL_NIF_TERM tuple; + int arity; + + if (!enif_get_list_cell(env, cell, &tuple, &cell) + || !enif_get_tuple(env, tuple, &arity, &pair) + || arity != 2) { + enif_free(keys); + return enif_make_badarg(env); + } + + keys[count] = pair[0]; + values[count] = pair[1]; + + count++; } - return map; + if (!enif_make_map_from_arrays(env, keys, values, count, &result)) { + result = enif_make_atom(env, "has_duplicate_keys"); + } + + enif_free(keys); + + return result; } static ERL_NIF_TERM sorted_list_from_maps_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl index adc6f56c06..b3d34103f1 100644 --- a/erts/emulator/test/smoke_test_SUITE.erl +++ b/erts/emulator/test/smoke_test_SUITE.erl @@ -70,6 +70,20 @@ boot_combo(Config) when is_list(Config) -> chk_boot(Config, "+Ktrue", NOOP), chk_boot(Config, "+A42", A42), chk_boot(Config, "+Ktrue +A42", A42), + + WBTArgs = ["very_short", "short", "medium", "long", "very_long"], + WTArgs = ["very_low", "low", "medium", "high", "very_high"], + [chk_boot(Config, + " +sbwt " ++ WBT ++ + " +sbwtdcpu " ++ WBT ++ + " +sbwtdio " ++ WBT ++ + " +swt " ++ WT ++ + " +swtdcpu " ++ WT ++ + " +swtdio " ++ WT, NOOP) || WBT <- WBTArgs, WT <- WTArgs], + + WSArgs = ["legacy", "default"], + [chk_boot(Config, " +sws " ++ WS, NOOP) || WS <- WSArgs], + %% A lot more combos could be implemented... ok after diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab index ffb5f58ebf..b7bca1dc3a 100755 --- a/erts/emulator/utils/make_driver_tab +++ b/erts/emulator/utils/make_driver_tab @@ -30,6 +30,7 @@ use File::Basename; my $file = ""; my $nif = ""; my @emu_drivers = (); +my @emu_nifs = (); my @static_drivers = (); my @static_nifs = (); my $mode = 1; @@ -61,7 +62,7 @@ while (@ARGV) { } elsif ($mode == 2) { $d = basename $d; $d =~ s/_nif(\..*|)$//; # strip nif.* or just nif - push(@static_nifs, $d); + push(@emu_nifs, $d); next; } $d = basename $d; @@ -94,37 +95,33 @@ foreach (@static_drivers) { } # The array itself -print "\nErlDrvEntry *driver_tab[] =\n{\n"; +print "\nErtsStaticDriver driver_tab[] =\n{\n"; foreach (@emu_drivers) { - print " &${_}driver_entry,\n"; + print " {&${_}driver_entry, 0},\n"; } foreach (@static_drivers) { - print " NULL, /* ${_} */\n"; + print " {NULL, 1}, /* ${_} */\n"; } -print " NULL\n};\n"; +print " {NULL}\n};\n"; print "void erts_init_static_drivers() {\n"; my $index = 0; foreach (@static_drivers) { - print " driver_tab[".(scalar @emu_drivers+$index)."] = ${_}_driver_init();\n"; + print " driver_tab[".(scalar @emu_drivers+$index)."].de = ${_}_driver_init();\n"; $index++; } print "}\n"; -print <<EOF; - -typedef struct ErtsStaticNifEntry_ { - const char *nif_name; - ErtsStaticNifInitFPtr nif_init; -} ErtsStaticNifEntry; - -EOF - # prototypes +foreach (@emu_nifs) { + my $d = ${_}; + $d =~ s/\.debug//; # strip .debug + print "void *".$d."_nif_init(void);\n"; +} foreach (@static_nifs) { my $d = ${_}; $d =~ s/\.debug//; # strip .debug @@ -134,20 +131,25 @@ foreach (@static_nifs) { # The array itself print "static ErtsStaticNifEntry static_nif_tab[] =\n{\n"; +foreach (@emu_nifs) { + my $d = ${_}; + $d =~ s/\.debug//; # strip .debug + print " {\"${_}\", &".$d."_nif_init, 0},\n"; +} foreach (@static_nifs) { my $d = ${_}; $d =~ s/\.debug//; # strip .debug - print "{\"${_}\",&".$d."_nif_init},\n"; + print " {\"${_}\", &".$d."_nif_init, 1},\n"; } print " {NULL,NULL}\n};\n"; print <<EOF; -ErtsStaticNifInitFPtr erts_static_nif_get_nif_init(const char *name, int len) { +ErtsStaticNifEntry* erts_static_nif_get_nif_init(const char *name, int len) { ErtsStaticNifEntry* p; for (p = static_nif_tab; p->nif_name != NULL; p++) if (strncmp(p->nif_name, name, len) == 0 && p->nif_name[len] == 0) - return p->nif_init; + return p; return NULL; } diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index f7774c6e2e..cf6d1bacca 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -129,6 +129,8 @@ static char *plusM_other_switches[] = { /* +s arguments with values */ static char *pluss_val_switches[] = { "bt", + "bwtdcpu", + "bwtdio", "bwt", "cl", "ct", @@ -136,6 +138,8 @@ static char *pluss_val_switches[] = { "fwi", "tbt", "wct", + "wtdcpu", + "wtdio", "wt", "ws", "ss", diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex 4d1691d71a..e93f053e01 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam Binary files differindex 799c3e17fb..f5967780ad 100644 --- a/erts/preloaded/ebin/erts_internal.beam +++ b/erts/preloaded/ebin/erts_internal.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 6cfca68a56..bffa59338e 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -39,7 +39,6 @@ -export([integer_to_list/2]). -export([integer_to_binary/2]). -export([set_cpu_topology/1, format_cpu_topology/1]). --export([await_proc_exit/3]). -export([memory/0, memory/1]). -export([alloc_info/1, alloc_sizes/1]). @@ -1923,7 +1922,7 @@ element(_N, _Tuple) -> %% Not documented -type module_info_key() :: attributes | compile | exports | functions | md5 - | module | native | native_addresses. + | module | native | native_addresses | nifs. -spec erlang:get_module_info(Module, Item) -> ModuleInfo when Module :: atom(), Item :: module_info_key(), @@ -3530,33 +3529,6 @@ rvrs(Xs) -> rvrs(Xs, []). rvrs([],Ys) -> Ys; rvrs([X|Xs],Ys) -> rvrs(Xs, [X|Ys]). -%% erlang:await_proc_exit/3 is for internal use only! -%% -%% BIFs that need to await a specific process exit before -%% returning traps to erlang:await_proc_exit/3. -%% -%% NOTE: This function is tightly coupled to -%% the implementation of the -%% erts_bif_prep_await_proc_exit_*() -%% functions in bif.c. Do not make -%% any changes to it without reading -%% the comment about them in bif.c! --spec erlang:await_proc_exit(dst(), 'apply' | 'data' | 'reason', term()) -> term(). -await_proc_exit(Proc, Op, Data) -> - Mon = erlang:monitor(process, Proc), - receive - {'DOWN', Mon, process, _Proc, Reason} -> - case Op of - apply -> - {M, F, A} = Data, - erlang:apply(M, F, A); - data -> - Data; - reason -> - Reason - end - end. - -spec min(Term1, Term2) -> Minimum when Term1 :: term(), Term2 :: term(), diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index fb709e7482..da5c9c68ed 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -78,6 +78,8 @@ %% Auto import name clash -export([check_process_code/1]). +-export([is_process_alive/1, is_process_alive/2]). + %% %% Await result of send to port %% @@ -600,3 +602,22 @@ group_leader(_GL, _Pid) -> group_leader(_GL, _Pid, _Ref) -> erlang:nif_error(undefined). + +-spec erts_internal:is_process_alive(Pid, Ref) -> 'ok' when + Pid :: pid(), + Ref :: reference(). + +is_process_alive(_Pid, _Ref) -> + erlang:nif_error(undefined). + +-spec erts_internal:is_process_alive(Pid) -> boolean() when + Pid :: pid(). + +is_process_alive(Pid) -> + Ref = make_ref(), + erts_internal:is_process_alive(Pid, Ref), + receive + {Ref, Res} -> + Res + end. + diff --git a/erts/test/erlexec_SUITE.erl b/erts/test/erlexec_SUITE.erl index db993abe52..73ed0ac56a 100644 --- a/erts/test/erlexec_SUITE.erl +++ b/erts/test/erlexec_SUITE.erl @@ -400,7 +400,7 @@ emu_args(CmdLineArgs) -> {ok,[[Erl]]} = init:get_argument(progname), EmuCL = os:cmd(Erl ++ " -emu_args_exit " ++ CmdLineArgs), io:format("EmuCL = ~ts", [EmuCL]), - split_emu_clt(string:lexemes(EmuCL, [$ ,$\t,$\n,$\r])). + split_emu_clt(string:lexemes(EmuCL, [$ ,$\t,$\n,[$\r,$\n]])). split_emu_clt(EmuCLT) -> split_emu_clt(EmuCLT, [], [], [], emu). |