From dc9ff931423b57e64abde0f1de7133f334abb780 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Mon, 25 Nov 2013 15:34:03 +0100 Subject: Ensure exit signal due to link precede port BIF return --- erts/doc/src/erlang.xml | 162 ++++++++++++++++++++++++++++++------- erts/emulator/beam/bif.c | 37 +++++++-- erts/emulator/beam/erl_bif_port.c | 34 +++++--- erts/emulator/beam/erl_port_task.h | 11 ++- erts/emulator/beam/io.c | 2 + 5 files changed, 198 insertions(+), 48 deletions(-) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index cbb25c2cf2..062caadad3 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -3032,7 +3032,10 @@ os_prompt% (see below), being synchronous, and that the port does not reply with {Port, closed}. Any process may close a port with port_close/1, not only the port owner - (the connected process).

+ (the connected process). If the calling process is linked to + port identified by Port, an exit signal due + to that link will be received by the process prior to the return + from port_close/1.

For comparison: Port ! {self(), close} fails with badarg if Port cannot be sent to (i.e., Port refers neither to a port nor to a process). If @@ -3041,6 +3044,7 @@ os_prompt% the port replies with {Port, closed} when all buffers have been flushed and the port really closes, but if the calling process is not the port owner the port owner fails with badsig.

+

Note that any process can close a port using Port ! {PortOwner, close} just as if it itself was the port owner, but the reply always goes to the port owner.

@@ -3050,8 +3054,17 @@ os_prompt% implementation has been synchronous. port_close/1 is however still fully synchronous. This due to its error behavior.

-

Failure: badarg if Port is not an open port or - the registered name of an open port.

+

Failure:

+ + badarg + + If Port is not an identifier of an open + port, or the registered name of an open port. If the calling + process was linked to the previously open port identified by + Port, an exit signal due to this link + was received by the process prior to this exception. + + @@ -3086,8 +3099,11 @@ os_prompt% badarg - If Port is not an open port or the registered name - of an open port. + If Port is not an identifier of an open + port, or the registered name of an open port. If the calling + process was linked to the previously open port identified by + Port, an exit signal due to this link + was received by the process prior to this exception. badarg @@ -3130,8 +3146,11 @@ os_prompt% badarg - If Port is not an open port or the registered name - of an open port. + If Port is not an identifier of an open + port, or the registered name of an open port. If the calling + process was linked to the previously open port identified by + Port, an exit signal due to this link + was received by the process prior to this exception. badarg @@ -3198,9 +3217,20 @@ os_prompt% implementation has been synchronous. port_connect/2 is however still fully synchronous. This due to its error behavior.

-

Failure: badarg if Port is not an open port - or the registered name of an open port, or if Pid is - not an existing local pid.

+

Failures:

+ + badarg + + If Port is not an identifier of an open + port, or the registered name of an open port. If the calling + process was linked to the previously open port identified by + Port, an exit signal due to this link + was received by the process prior to this exception. + + badarg + If process identified by Pid is not an existing + local process. +
@@ -3236,12 +3266,33 @@ os_prompt% binary term format and sent to the port.

Returns: a term from the driver. The meaning of the returned data also depends on the port driver.

-

Failure: badarg if Port is not an open port or - the registered name of an open port, if Operation - cannot fit in a 32-bit integer, if the port driver does not - support synchronous control operations, or if the port driver - so decides for any reason (probably something wrong with - Operation or Data).

+

Failures:

+ + badarg + + If Port is not an identifier of an open + port, or the registered name of an open port. If the calling + process was linked to the previously open port identified by + Port, an exit signal due to this link + was received by the process prior to this exception. + + badarg + + If Operation does not fit in a + 32-bit integer. + + badarg + + If the port driver does not support synchronous control + operations. + + badarg + + If the port driver so decides for any reason (probably + something wrong with Operation, or + Data). + +
@@ -3251,7 +3302,12 @@ os_prompt%

Returns a list containing tuples with information about the Port, or undefined if the port is not open. The order of the tuples is not defined, nor are all the - tuples mandatory.

+ tuples mandatory. + If undefined is returned and the calling process + was linked to a previously open port identified by + Port, an exit signal due to this link + was received by the process prior to the return from + port_info/1.

Currently the result will containt information about the following Items: registered_name (if the port has a registered name), id, connected, links, @@ -3269,7 +3325,11 @@ os_prompt%

Pid is the process identifier of the process connected to the port.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3281,7 +3341,11 @@ os_prompt%

Index is the internal index of the port. This index may be used to separate ports.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3293,7 +3357,11 @@ os_prompt%

Bytes is the total number of bytes read from the port.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3305,7 +3373,11 @@ os_prompt%

Pids is a list of the process identifiers of the processes that the port is linked to.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3320,7 +3392,11 @@ os_prompt% that these results are highly implementation specific and might change in the future.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3334,7 +3410,11 @@ os_prompt% that the port itself might have allocated memory which is not included in Bytes.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3346,7 +3426,11 @@ os_prompt%

Monitors represent processes that this port is monitoring.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3358,7 +3442,11 @@ os_prompt%

Name is the command name set by open_port/2.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3373,7 +3461,11 @@ os_prompt% Command}, Options). If the port is not the result of spawning an OS process, the value is undefined.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3389,7 +3481,11 @@ os_prompt% or Port ! {Owner, {command, Data}.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3412,7 +3508,11 @@ os_prompt% in bytes, queued by the port using the ERTS driver queue implementation.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

@@ -3424,7 +3524,11 @@ os_prompt%

RegisteredName is the registered name of the port. If the port has no registered name, [] is returned.

If the port identified by Port is not open, - undefined is returned.

+ undefined is returned. If undefined is returned and + the calling process was linked to a previously open port identified + by Port, an exit signal due to this link + was received by the process prior to the return from + port_info/2.

Failure: badarg if Port is not a local port identifier, or an atom.

diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 755c5e6882..13d31285b2 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -160,7 +160,10 @@ BIF_RETTYPE link_1(BIF_ALIST_1) if (is_internal_port(BIF_ARG_1)) { int send_link_signal = 0; - Port *prt = erts_port_lookup(BIF_ARG_1, ERTS_PORT_SFLGS_INVALID_LOOKUP); + Port *prt = erts_port_lookup(BIF_ARG_1, + (erts_port_synchronous_ops + ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP + : ERTS_PORT_SFLGS_INVALID_LOOKUP)); if (!prt) { goto res_no_proc; } @@ -1363,11 +1366,22 @@ BIF_RETTYPE exit_2(BIF_ALIST_2) */ if (is_internal_port(BIF_ARG_1)) { - Port *prt = erts_port_lookup(BIF_ARG_1, ERTS_PORT_SFLGS_INVALID_LOOKUP); + Eterm ref, *refp; + Uint32 invalid_flags; + Port *prt; + + if (erts_port_synchronous_ops) { + refp = &ref; + invalid_flags = ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP; + } + else { + refp = NULL; + invalid_flags = ERTS_PORT_SFLGS_INVALID_LOOKUP; + } + + prt = erts_port_lookup(BIF_ARG_1, invalid_flags); if (prt) { - Eterm ref; - Eterm *refp = erts_port_synchronous_ops ? &ref : NULL; ErtsPortOpResult res; #ifdef DEBUG @@ -1875,7 +1889,10 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend, Eterm *refp) { if (rp) goto send_message; - pt = erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP); + pt = erts_port_lookup(id, + (erts_port_synchronous_ops + ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP + : ERTS_PORT_SFLGS_INVALID_LOOKUP)); if (pt) { portid = id; goto port_common; @@ -1905,7 +1922,10 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend, Eterm *refp) { int ret_val; portid = to; - pt = erts_port_lookup(portid, ERTS_PORT_SFLGS_INVALID_LOOKUP); + pt = erts_port_lookup(portid, + (erts_port_synchronous_ops + ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP + : ERTS_PORT_SFLGS_INVALID_LOOKUP)); port_common: ret_val = 0; @@ -1994,7 +2014,10 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend, Eterm *refp) { rp = erts_proc_lookup_raw(id); if (rp) goto send_message; - pt = erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP); + pt = erts_port_lookup(id, + (erts_port_synchronous_ops + ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP + : ERTS_PORT_SFLGS_INVALID_LOOKUP)); if (pt) { portid = id; goto port_common; diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index 109c54fd7f..3cd53ef65d 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -84,7 +84,7 @@ BIF_RETTYPE open_port_2(BIF_ALIST_2) } static ERTS_INLINE Port * -lookup_port(Process *c_p, Eterm id_or_name) +lookup_port(Process *c_p, Eterm id_or_name, Uint32 invalid_flags) { /* TODO: Implement nicer lookup in register... */ Eterm id; @@ -92,7 +92,19 @@ lookup_port(Process *c_p, Eterm id_or_name) id = erts_whereis_name_to_id(c_p, id_or_name); else id = id_or_name; - return erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP); + return erts_port_lookup(id, invalid_flags); +} + +static ERTS_INLINE Port * +sig_lookup_port(Process *c_p, Eterm id_or_name) +{ + return lookup_port(c_p, id_or_name, ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP); +} + +static ERTS_INLINE Port * +data_lookup_port(Process *c_p, Eterm id_or_name) +{ + return lookup_port(c_p, id_or_name, ERTS_PORT_SFLGS_INVALID_LOOKUP); } /* @@ -125,7 +137,7 @@ BIF_RETTYPE erts_internal_port_command_3(BIF_ALIST_3) BIF_RET(am_badarg); } - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = sig_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_RET(am_badarg); @@ -185,7 +197,7 @@ BIF_RETTYPE erts_internal_port_call_3(BIF_ALIST_3) unsigned int op; erts_aint32_t state; - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = sig_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_RET(am_badarg); @@ -235,7 +247,7 @@ BIF_RETTYPE erts_internal_port_control_3(BIF_ALIST_3) unsigned int op; erts_aint32_t state; - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = sig_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_RET(am_badarg); @@ -290,7 +302,7 @@ BIF_RETTYPE erts_internal_port_close_1(BIF_ALIST_1) ref = NIL; #endif - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = sig_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_RET(am_badarg); @@ -320,7 +332,7 @@ BIF_RETTYPE erts_internal_port_connect_2(BIF_ALIST_2) Eterm ref; Port* prt; - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = sig_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_RET(am_badarg); @@ -352,7 +364,7 @@ BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1) Port* prt; if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) { - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = sig_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_RET(am_undefined); } @@ -391,7 +403,7 @@ BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2) Port* prt; if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) { - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = sig_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_RET(am_undefined); } @@ -523,7 +535,7 @@ BIF_RETTYPE port_set_data_2(BIF_ALIST_2) erts_aint_t data; Port* prt; - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = data_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_ERROR(BIF_P, BADARG); @@ -564,7 +576,7 @@ BIF_RETTYPE port_get_data_1(BIF_ALIST_1) erts_aint_t data; Port* prt; - prt = lookup_port(BIF_P, BIF_ARG_1); + prt = data_lookup_port(BIF_P, BIF_ARG_1); if (!prt) BIF_ERROR(BIF_P, BADARG); diff --git a/erts/emulator/beam/erl_port_task.h b/erts/emulator/beam/erl_port_task.h index e4d964146e..123253a057 100644 --- a/erts/emulator/beam/erl_port_task.h +++ b/erts/emulator/beam/erl_port_task.h @@ -77,6 +77,7 @@ extern erts_smp_atomic_t erts_port_task_outstanding_io_tasks; #define ERTS_PTS_FLG_HAVE_NS_TASKS (((erts_aint32_t) 1) << 8) #define ERTS_PTS_FLG_PARALLELISM (((erts_aint32_t) 1) << 9) #define ERTS_PTS_FLG_FORCE_SCHED (((erts_aint32_t) 1) << 10) +#define ERTS_PTS_FLG_EXITING (((erts_aint32_t) 1) << 11) #define ERTS_PTS_FLGS_BUSY \ (ERTS_PTS_FLG_BUSY_PORT | ERTS_PTS_FLG_BUSY_PORT_Q) @@ -86,7 +87,8 @@ extern erts_smp_atomic_t erts_port_task_outstanding_io_tasks; | ERTS_PTS_FLG_HAVE_BUSY_TASKS \ | ERTS_PTS_FLG_HAVE_TASKS \ | ERTS_PTS_FLG_EXEC \ - | ERTS_PTS_FLG_FORCE_SCHED) + | ERTS_PTS_FLG_FORCE_SCHED \ + | ERTS_PTS_FLG_EXITING) #define ERTS_PORT_TASK_DEFAULT_BUSY_PORT_Q_HIGH 8192 #define ERTS_PORT_TASK_DEFAULT_BUSY_PORT_Q_LOW 4096 @@ -135,6 +137,7 @@ ERTS_GLB_INLINE void erts_port_task_fini_sched(ErtsPortTaskSched *ptsp); ERTS_GLB_INLINE void erts_port_task_sched_lock(ErtsPortTaskSched *ptsp); ERTS_GLB_INLINE void erts_port_task_sched_unlock(ErtsPortTaskSched *ptsp); ERTS_GLB_INLINE int erts_port_task_sched_lock_is_locked(ErtsPortTaskSched *ptsp); +ERTS_GLB_INLINE void erts_port_task_sched_enter_exiting_state(ErtsPortTaskSched *ptsp); #ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS ERTS_GLB_INLINE int erts_port_task_have_outstanding_io_tasks(void); @@ -225,6 +228,12 @@ erts_port_task_fini_sched(ErtsPortTaskSched *ptsp) #endif } +ERTS_GLB_INLINE void +erts_port_task_sched_enter_exiting_state(ErtsPortTaskSched *ptsp) +{ + erts_smp_atomic32_read_bor_nob(&ptsp->flags, ERTS_PTS_FLG_EXITING); +} + #ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS ERTS_GLB_INLINE int diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 6911fd8241..9076bbe73c 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -3601,6 +3601,8 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed) if (send_closed) set_state_flags |= ERTS_PORT_SFLG_SEND_CLOSED; + erts_port_task_sched_enter_exiting_state(&p->sched); + state = erts_atomic32_read_bor_mb(&p->state, set_state_flags); state |= set_state_flags; -- cgit v1.2.3