aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/beam/bif.c38
-rw-r--r--erts/emulator/beam/bif.h61
-rw-r--r--erts/emulator/beam/bif.tab1
-rw-r--r--erts/emulator/beam/dist.c68
-rw-r--r--erts/emulator/beam/dist.h6
-rw-r--r--erts/emulator/beam/erl_bif_info.c74
-rw-r--r--erts/emulator/beam/erl_bif_trace.c3
-rw-r--r--erts/emulator/beam/erl_db_util.c33
-rw-r--r--erts/emulator/beam/erl_message.c9
-rw-r--r--erts/emulator/beam/erl_node_tables.c8
-rw-r--r--erts/emulator/beam/erl_posix_str.c6
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c245
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.h25
-rw-r--r--erts/emulator/beam/erl_process.c104
-rw-r--r--erts/emulator/beam/erl_process.h17
-rw-r--r--erts/emulator/beam/erlang_dtrace.d15
-rw-r--r--erts/emulator/beam/io.c27
-rw-r--r--erts/emulator/beam/msg_instrs.tab4
-rw-r--r--erts/emulator/beam/sys.h40
-rw-r--r--erts/emulator/test/bif_SUITE.erl27
-rw-r--r--erts/preloaded/ebin/erlang.beambin103248 -> 102724 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin14712 -> 15104 bytes
-rw-r--r--erts/preloaded/src/erlang.erl28
-rw-r--r--erts/preloaded/src/erts_internal.erl21
-rw-r--r--erts/test/erlexec_SUITE.erl2
25 files changed, 532 insertions, 330 deletions
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_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_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_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_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 9f02c34742..be1306cd79 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -10536,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);
@@ -10668,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;
@@ -10683,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;
}
@@ -10765,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:
@@ -10794,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)
@@ -12787,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);
@@ -12908,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 cec93cbb9b..f7c6c3435b 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1253,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.
*/
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/io.c b/erts/emulator/beam/io.c
index b2afdc6bf2..9f87285b71 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -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;
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/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/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/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 4d1691d71a..e93f053e01 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index 799c3e17fb..f5967780ad 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index f8221868e2..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]).
@@ -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).