summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRickard Green <rickard@erlang.org>2021-04-20 16:45:54 +0200
committerRickard Green <rickard@erlang.org>2021-04-22 18:46:08 +0200
commit15ac634091f25df3a46c7f354711773167602994 (patch)
tree837d8d48ed3c00e63c38f70098d05de25a7fc697
parentfd68be9571caaee596ef5c04badfd2dae145a60c (diff)
downloaderlang-15ac634091f25df3a46c7f354711773167602994.tar.gz
Ensure reply signals from ports respect signal order
The reply signal from a port to a process, when the process called one of the 'port_*' BIFs, could pass before other signals sent from the port to the process. That is, the reply signal could be delivered too early.
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/bif.c47
-rw-r--r--erts/emulator/beam/bif.h9
-rw-r--r--erts/emulator/beam/erl_bif_port.c389
4 files changed, 283 insertions, 163 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index ceb8c56623..d7bcf61a53 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -119,6 +119,7 @@ atom badarg badarith badarity badfile badfun badkey badmap badmatch badsig
atom bag
atom band
atom big
+atom bif_handle_signals_return
atom bif_return_trap
atom binary
atom binary_copy_trap
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 000397e790..b9cce0022d 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4847,7 +4847,50 @@ static BIF_RETTYPE bif_return_trap(BIF_ALIST_2)
BIF_RET(res);
}
+static BIF_RETTYPE
+bif_handle_signals_return(BIF_ALIST_1)
+{
+ int local_only = BIF_P->flags & F_LOCAL_SIGS_ONLY;
+ int sres, sreds, reds_left;
+ erts_aint32_t state;
+
+ reds_left = ERTS_BIF_REDS_LEFT(BIF_P);
+ sreds = reds_left;
+
+ if (!local_only) {
+ erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MSGQ);
+ erts_proc_sig_fetch(BIF_P);
+ erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MSGQ);
+ }
+
+ state = erts_atomic32_read_nob(&BIF_P->state);
+ sres = erts_proc_sig_handle_incoming(BIF_P, &state, &sreds,
+ sreds, !0);
+
+ BUMP_REDS(BIF_P, (int) sreds);
+ reds_left -= sreds;
+
+ if (state & ERTS_PSFLG_EXITING) {
+ BIF_P->flags &= ~F_LOCAL_SIGS_ONLY;
+ ERTS_BIF_EXITED(BIF_P);
+ }
+ if (!sres | (reds_left <= 0)) {
+ /*
+ * More signals to handle or out of reds; need
+ * to yield and continue. Prevent fetching of
+ * more signals by setting local-sigs-only flag.
+ */
+ BIF_P->flags |= F_LOCAL_SIGS_ONLY;
+ ERTS_BIF_YIELD1(&erts_bif_handle_signals_return_export,
+ BIF_P, BIF_ARG_1);
+ }
+
+ BIF_P->flags &= ~F_LOCAL_SIGS_ONLY;
+ BIF_RET(BIF_ARG_1);
+}
+
Export bif_return_trap_export;
+Export erts_bif_handle_signals_return_export;
void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a,
Eterm (*bif)(BIF_ALIST))
@@ -4874,6 +4917,10 @@ void erts_init_bif(void)
am_erlang, am_bif_return_trap, 2,
&bif_return_trap);
+ erts_init_trap_export(&erts_bif_handle_signals_return_export,
+ am_erlang, am_bif_handle_signals_return, 1,
+ &bif_handle_signals_return);
+
erts_await_result = erts_export_put(am_erts_internal,
am_await_result,
1);
diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h
index cf9f61c0b8..bad047b92f 100644
--- a/erts/emulator/beam/bif.h
+++ b/erts/emulator/beam/bif.h
@@ -462,6 +462,15 @@ do { \
BIF_TRAP4((TRP), (P), (A0), (A1), (A2), (A3)); \
} while (0)
+extern Export erts_bif_handle_signals_return_export;
+
+#define ERTS_BIF_HANDLE_SIGNALS_RETURN(P, VAL) \
+ BIF_TRAP1(&erts_bif_handle_signals_return_export, (P), (VAL))
+
+#define ERTS_BIF_PREP_HANDLE_SIGNALS_RETURN(Ret, P, Val) \
+ ERTS_BIF_PREP_TRAP1((Ret), &erts_bif_handle_signals_return_export, \
+ (P), (Val))
+
#define ERTS_BIF_PREP_EXITED(RET, PROC) \
do { \
KILL_CATCHES((PROC)); \
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index ed825d3dda..40a2fb96d6 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -167,7 +167,7 @@ BIF_RETTYPE erts_internal_port_command_3(BIF_ALIST_3)
BIF_RETTYPE res;
Port *prt;
int flags = 0;
- Eterm ref;
+ erts_aint32_t state;
if (is_not_nil(BIF_ARG_3)) {
Eterm l = BIF_ARG_3;
@@ -188,51 +188,59 @@ BIF_RETTYPE erts_internal_port_command_3(BIF_ALIST_3)
prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_badarg);
-
- if (flags & ERTS_PORT_SIG_FLG_FORCE) {
- if (!(prt->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY))
- BIF_RET(am_notsup);
+ ERTS_BIF_PREP_RET(res, am_badarg);
+ else if ((flags & ERTS_PORT_SIG_FLG_FORCE)
+ && !(prt->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY)) {
+ ERTS_BIF_PREP_RET(res, am_notsup);
}
-
+ else {
+ Eterm ref;
#ifdef DEBUG
- ref = NIL;
+ ref = NIL;
#endif
- switch (erts_port_output(BIF_P, flags, prt, prt->common.id, BIF_ARG_2, &ref)) {
- case ERTS_PORT_OP_BADARG:
- case ERTS_PORT_OP_DROPPED:
- ERTS_BIF_PREP_RET(res, am_badarg);
- break;
- case ERTS_PORT_OP_BUSY:
- ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
- if (flags & ERTS_PORT_SIG_FLG_NOSUSPEND)
- ERTS_BIF_PREP_RET(res, am_false);
- else {
- erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, prt);
- ERTS_BIF_PREP_YIELD3(res, bif_export[BIF_erts_internal_port_command_3],
- BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
- }
- break;
- case ERTS_PORT_OP_BUSY_SCHEDULED:
- ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
- /* Fall through... */
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ordinary_ref(ref));
- ERTS_BIF_PREP_RET(res, ref);
- break;
- case ERTS_PORT_OP_DONE:
- ERTS_BIF_PREP_RET(res, am_true);
- break;
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_output() result");
- break;
+ switch (erts_port_output(BIF_P, flags, prt, prt->common.id,
+ BIF_ARG_2, &ref)) {
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ ERTS_BIF_PREP_RET(res, am_badarg);
+ break;
+ case ERTS_PORT_OP_BUSY:
+ ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
+ if (flags & ERTS_PORT_SIG_FLG_NOSUSPEND)
+ ERTS_BIF_PREP_RET(res, am_false);
+ else {
+ erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, prt);
+ ERTS_BIF_PREP_YIELD3(res, bif_export[BIF_erts_internal_port_command_3],
+ BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
+ }
+ break;
+ case ERTS_PORT_OP_BUSY_SCHEDULED:
+ ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
+ /* Fall through... */
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ordinary_ref(ref));
+ BIF_RET(ref);
+ case ERTS_PORT_OP_DONE:
+ ERTS_BIF_PREP_RET(res, am_true);
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_output() result");
+ ERTS_BIF_PREP_RET(res, am_internal_error);
+ break;
+ }
}
- if (ERTS_PROC_IS_EXITING(BIF_P)) {
+ state = erts_atomic32_read_acqb(&BIF_P->state);
+ if (state & ERTS_PSFLG_EXITING) {
KILL_CATCHES(BIF_P); /* Must exit */
ERTS_BIF_PREP_ERROR(res, BIF_P, EXC_ERROR);
}
+ else {
+ /* Ensure signal order is preserved... */
+ if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))
+ ERTS_BIF_PREP_HANDLE_SIGNALS_RETURN(res, BIF_P, res);
+ }
return res;
}
@@ -242,41 +250,46 @@ BIF_RETTYPE erts_internal_port_call_3(BIF_ALIST_3)
Port* prt;
Eterm retval;
Uint uint_op;
- unsigned int op;
erts_aint32_t state;
prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_badarg);
-
- if (!term_to_Uint(BIF_ARG_2, &uint_op))
- BIF_RET(am_badarg);
-
- if (uint_op > (Uint) UINT_MAX)
- BIF_RET(am_badarg);
-
- op = (unsigned int) uint_op;
-
- switch (erts_port_call(BIF_P, prt, op, BIF_ARG_3, &retval)) {
- case ERTS_PORT_OP_DROPPED:
- case ERTS_PORT_OP_BADARG:
retval = am_badarg;
- break;
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ordinary_ref(retval));
- break;
- case ERTS_PORT_OP_DONE:
- ASSERT(is_not_internal_ref(retval));
- break;
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_call() result");
- retval = am_internal_error;
- break;
+ else if (!term_to_Uint(BIF_ARG_2, &uint_op))
+ retval = am_badarg;
+ else if (uint_op > (Uint) UINT_MAX)
+ retval = am_badarg;
+ else {
+ unsigned int op = (unsigned int) uint_op;
+
+ switch (erts_port_call(BIF_P, prt, op, BIF_ARG_3, &retval)) {
+ case ERTS_PORT_OP_DROPPED:
+ case ERTS_PORT_OP_BADARG:
+ retval = am_badarg;
+ break;
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ordinary_ref(retval));
+ /* Signal order preserved by reply... */
+ BIF_RET(retval);
+ break;
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_call() result");
+ retval = am_internal_error;
+ break;
+ }
}
state = erts_atomic32_read_acqb(&BIF_P->state);
if (state & ERTS_PSFLG_EXITING)
ERTS_BIF_EXITED(BIF_P);
+ else {
+ /* Ensure signal order is preserved... */
+ if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))
+ ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
+ }
BIF_RET(retval);
}
@@ -286,41 +299,45 @@ BIF_RETTYPE erts_internal_port_control_3(BIF_ALIST_3)
Port* prt;
Eterm retval;
Uint uint_op;
- unsigned int op;
erts_aint32_t state;
prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_badarg);
-
- if (!term_to_Uint(BIF_ARG_2, &uint_op))
- BIF_RET(am_badarg);
-
- if (uint_op > (Uint) UINT_MAX)
- BIF_RET(am_badarg);
-
- op = (unsigned int) uint_op;
-
- switch (erts_port_control(BIF_P, prt, op, BIF_ARG_3, &retval)) {
- case ERTS_PORT_OP_BADARG:
- case ERTS_PORT_OP_DROPPED:
retval = am_badarg;
- break;
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ordinary_ref(retval));
- break;
- case ERTS_PORT_OP_DONE:
- ASSERT(is_not_internal_ref(retval));
- break;
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_control() result");
- retval = am_internal_error;
- break;
+ else if (!term_to_Uint(BIF_ARG_2, &uint_op))
+ retval = am_badarg;
+ else if (uint_op > (Uint) UINT_MAX)
+ retval = am_badarg;
+ else {
+ unsigned int op = (unsigned int) uint_op;
+
+ switch (erts_port_control(BIF_P, prt, op, BIF_ARG_3, &retval)) {
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ retval = am_badarg;
+ break;
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ordinary_ref(retval));
+ /* Signal order preserved by reply... */
+ BIF_RET(retval);
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_control() result");
+ retval = am_internal_error;
+ break;
+ }
}
state = erts_atomic32_read_acqb(&BIF_P->state);
if (state & ERTS_PSFLG_EXITING)
ERTS_BIF_EXITED(BIF_P);
+ else {
+ /* Ensure signal order is preserved... */
+ if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))
+ ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
+ }
BIF_RET(retval);
}
@@ -331,30 +348,44 @@ BIF_RETTYPE erts_internal_port_control_3(BIF_ALIST_3)
*/
BIF_RETTYPE erts_internal_port_close_1(BIF_ALIST_1)
{
- Eterm ref;
+ Eterm retval;
Port *prt;
+ prt = sig_lookup_port(BIF_P, BIF_ARG_1);
+ if (!prt)
+ retval = am_badarg;
+ else {
+
#ifdef DEBUG
- ref = NIL;
+ retval = NIL;
#endif
- prt = sig_lookup_port(BIF_P, BIF_ARG_1);
- if (!prt)
- BIF_RET(am_badarg);
-
- switch (erts_port_exit(BIF_P, 0, prt, BIF_P->common.id, am_normal, &ref)) {
- case ERTS_PORT_OP_BADARG:
- case ERTS_PORT_OP_DROPPED:
- BIF_RET(am_badarg);
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ordinary_ref(ref));
- BIF_RET(ref);
- case ERTS_PORT_OP_DONE:
- BIF_RET(am_true);
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_exit() result");
- BIF_RET(am_internal_error);
+ switch (erts_port_exit(BIF_P, 0, prt, BIF_P->common.id,
+ am_normal, &retval)) {
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ retval = am_badarg;
+ break;
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ordinary_ref(retval));
+ /* Signal order preserved by reply... */
+ BIF_RET(retval);
+ break;
+ case ERTS_PORT_OP_DONE:
+ retval = am_true;
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_exit() result");
+ retval = am_internal_error;
+ break;
+ }
}
+
+ /* Ensure signal order is preserved... */
+ if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P))
+ ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
+
+ BIF_RET(retval);
}
/*
@@ -363,32 +394,42 @@ BIF_RETTYPE erts_internal_port_close_1(BIF_ALIST_1)
*/
BIF_RETTYPE erts_internal_port_connect_2(BIF_ALIST_2)
{
- Eterm ref;
+ Eterm retval;
Port* prt;
prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_badarg);
-
+ retval = am_badarg;
+ else {
#ifdef DEBUG
- ref = NIL;
+ retval = NIL;
#endif
- switch (erts_port_connect(BIF_P, 0, prt, BIF_P->common.id, BIF_ARG_2, &ref)) {
- case ERTS_PORT_OP_BADARG:
- case ERTS_PORT_OP_DROPPED:
- BIF_RET(am_badarg);
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ordinary_ref(ref));
- BIF_RET(ref);
- break;
- case ERTS_PORT_OP_DONE:
- BIF_RET(am_true);
- break;
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_connect() result");
- BIF_RET(am_internal_error);
+ switch (erts_port_connect(BIF_P, 0, prt, BIF_P->common.id,
+ BIF_ARG_2, &retval)) {
+ case ERTS_PORT_OP_BADARG:
+ case ERTS_PORT_OP_DROPPED:
+ retval = am_badarg;
+ break;
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ordinary_ref(retval));
+ /* Signal order preserved by reply... */
+ BIF_RET(retval);
+ case ERTS_PORT_OP_DONE:
+ retval = am_true;
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_connect() result");
+ retval = am_internal_error;
+ break;
+ }
}
+
+ /* Ensure signal order is preserved... */
+ if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P))
+ ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
+
+ BIF_RET(retval);
}
BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1)
@@ -399,33 +440,44 @@ BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1)
if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_undefined);
+ retval = am_undefined;
+ else {
+ switch (erts_port_info(BIF_P, prt, THE_NON_VALUE, &retval)) {
+ case ERTS_PORT_OP_BADARG:
+ retval = am_badarg;
+ break;
+ case ERTS_PORT_OP_DROPPED:
+ retval = am_undefined;
+ break;
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ordinary_ref(retval));
+ /* Signal order preserved by reply... */
+ BIF_RET(retval);
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
+ retval = am_internal_error;
+ break;
+ }
+ }
}
else if (is_external_port(BIF_ARG_1)) {
if (external_port_dist_entry(BIF_ARG_1) == erts_this_dist_entry)
- BIF_RET(am_undefined);
+ retval = am_undefined;
else
- BIF_RET(am_badarg);
+ retval = am_badarg;
}
else {
- BIF_RET(am_badarg);
- }
-
- switch (erts_port_info(BIF_P, prt, THE_NON_VALUE, &retval)) {
- case ERTS_PORT_OP_BADARG:
- BIF_RET(am_badarg);
- case ERTS_PORT_OP_DROPPED:
- BIF_RET(am_undefined);
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ordinary_ref(retval));
- BIF_RET(retval);
- case ERTS_PORT_OP_DONE:
- ASSERT(is_not_internal_ref(retval));
- BIF_RET(retval);
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
- BIF_RET(am_internal_error);
+ retval = am_badarg;
}
+
+ /* Ensure signal order is preserved... */
+ if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P))
+ ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
+
+ BIF_RET(retval);
}
@@ -437,33 +489,44 @@ BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2)
if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
prt = sig_lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_undefined);
+ retval = am_undefined;
+ else {
+ switch (erts_port_info(BIF_P, prt, BIF_ARG_2, &retval)) {
+ case ERTS_PORT_OP_BADARG:
+ retval = am_badarg;
+ break;
+ case ERTS_PORT_OP_DROPPED:
+ retval = am_undefined;
+ break;
+ case ERTS_PORT_OP_SCHEDULED:
+ ASSERT(is_internal_ordinary_ref(retval));
+ /* Signal order preserved by reply... */
+ BIF_RET(retval);
+ case ERTS_PORT_OP_DONE:
+ ASSERT(is_not_internal_ref(retval));
+ break;
+ default:
+ ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
+ retval = am_internal_error;
+ break;
+ }
+ }
}
else if (is_external_port(BIF_ARG_1)) {
if (external_port_dist_entry(BIF_ARG_1) == erts_this_dist_entry)
- BIF_RET(am_undefined);
+ retval = am_undefined;
else
- BIF_RET(am_badarg);
+ retval = am_badarg;
}
else {
- BIF_RET(am_badarg);
- }
-
- switch (erts_port_info(BIF_P, prt, BIF_ARG_2, &retval)) {
- case ERTS_PORT_OP_BADARG:
- BIF_RET(am_badarg);
- case ERTS_PORT_OP_DROPPED:
- BIF_RET(am_undefined);
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ordinary_ref(retval));
- BIF_RET(retval);
- case ERTS_PORT_OP_DONE:
- ASSERT(is_not_internal_ref(retval));
- BIF_RET(retval);
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
- BIF_RET(am_internal_error);
+ retval = am_badarg;
}
+
+ /* Ensure signal order is preserved... */
+ if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P))
+ ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
+
+ BIF_RET(retval);
}
/*