diff options
-rw-r--r-- | erts/doc/src/erlang.xml | 166 | ||||
-rw-r--r-- | erts/emulator/beam/atom.names | 3 | ||||
-rw-r--r-- | erts/emulator/beam/bif.c | 9 | ||||
-rw-r--r-- | erts/emulator/beam/dist.c | 45 | ||||
-rw-r--r-- | erts/emulator/beam/erl_monitor_link.h | 9 | ||||
-rw-r--r-- | erts/emulator/beam/erl_proc_sig_queue.c | 30 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.c | 42 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.h | 9 | ||||
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 90 | ||||
-rw-r--r-- | erts/preloaded/ebin/erlang.beam | bin | 108756 -> 108936 bytes | |||
-rw-r--r-- | erts/preloaded/src/erlang.erl | 24 |
11 files changed, 325 insertions, 102 deletions
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 3f39a4651a..05d0685501 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -6690,12 +6690,13 @@ true</pre> <marker id="spawn_request_success_message"/> <p> If the spawn operation succeeds, a new process is - created on the node identified by <c><anno>Node</anno></c> - and the caller will be sent a message on the form + created on the node identified by <c><anno>Node</anno></c>. + When a spawn operation succeeds, the caller will by + default be sent a message on the form <c>{<anno>ReplyTag</anno>, <anno>ReqId</anno>, ok, Pid}</c> where <c>Pid</c> is the process identifier of the - newly created process. Such a message is referred - to as a <i>success message</i> below in the text. + newly created process. Such a message is referred to as a + <i>success message</i> below in the text. <c><anno>ReplyTag</anno></c> is by default the atom <c>spawn_reply</c> unless modified by the <c>{reply_tag, <anno>ReplyTag</anno>}</c> option. The @@ -6705,14 +6706,15 @@ true</pre> </p> <marker id="spawn_request_error_message"/> - <p>If the spawn operation fails, a + <p>The spawn operation fails either if creation of a new process + failed or if the spawn operation was interrupted by a connection + failure. When a spawn operation fails, the caller will by default + be sent a message on the form <c>{<anno>ReplyTag</anno>, <anno>ReqId</anno>, error, Reason}</c> - message will be sent to the caller. Such a message is referred - to as an <i>error message</i> below in the text. The spawn operation - fail either if creation of a new process failed or if the - spawn operation was interrupted by a connection failure. - Currently the following failure <c>Reason</c>s are defined, but - other reasons can appear at any time without prior notice:</p> + where <c>Reason</c> is the error reason. Such a message is + referred to as an <i>error message</i> below in the text. + Currently the following spawn error <c>Reason</c>s are defined, + but other reasons can appear at any time without prior notice:</p> <taglist> <tag><c>badopt</c></tag> <item> @@ -6722,14 +6724,6 @@ true</pre> support different options. </p> </item> - <tag><c>system_limit</c></tag> - <item> - <p> - Could not create a new process due to that some - system limit was reached. Typically the process table - was full. - </p> - </item> <tag><c>notsup</c></tag> <item> <p> @@ -6749,6 +6743,14 @@ true</pre> not have been created. </p> </item> + <tag><c>system_limit</c></tag> + <item> + <p> + Could not create a new process due to that some + system limit was reached. Typically the process table + was full. + </p> + </item> </taglist> <p>Valid <c><anno>Option</anno></c>s:</p> <taglist> @@ -6763,26 +6765,26 @@ true</pre> newly created process. The <c><anno>ReqId</anno></c> returned by <c>spawn_request()</c> is also used as monitor reference as if it was returned from - <c>monitor(process, Pid)</c>. A <c>'DOWN'</c> message - for the corresponding monitor is guaranteed not - to be delivered before the - <seealso marker="#spawn_request_success_message"><i>success - message</i></seealso>. The monitor can not be + <c>monitor(process, Pid)</c>. + </p> + <p> + The monitor will not be activated for the calling + process until the spawn operation has succeeded. + The monitor can not be <seealso marker="#demonitor/1">demonitored</seealso> - before the operation has succeeded and the <i>success - message</i> has been delivered. If the operation does - not succeed and an - <seealso marker="#spawn_request_error_message"><i>error - message</i></seealso> is delivered, no <c>'DOWN'</c> - message will be delivered. + before the operation has succeeded. A <c>'DOWN'</c> + message for the corresponding monitor is guaranteed + not to be delivered before a + <seealso marker="#spawn_request_success_message"><i>success + message</i></seealso> that corresponds to the spawn + operation. If the spawn operation fails, no + <c>'DOWN'</c> message will be delivered. </p> <p> If the connection between the nodes involved in the spawn operation is lost during the spawn - operation, the spawn operation will fail and an - <i>error message</i> with a <c>Reason</c> of - <c>noconnection</c> will be delivered to the - caller of <c>spawn_request()</c>. A new process + operation, the spawn operation will fail with an + error reason of <c>noconnection</c>. A new process may or may not have been created. </p> </item> @@ -6795,27 +6797,72 @@ true</pre> process had called <seealso marker="#link/1"><c>link(Pid)</c></seealso> where <c>Pid</c> is the process identifier of the - newly created process. An exit signal due to the - link is guaranteed not to be delivered before the + newly created process. + </p> + <p> + The link will not be activated for the calling + process until the spawn operation has succeeded. + The link can not be removed before the operation + has succeeded. An exit signal due to the link is + guaranteed not to be delivered before a <seealso marker="#spawn_request_success_message"><i>success - message</i></seealso>. If the spawn operation fail, an - <seealso marker="#spawn_request_error_message"><i>error - message</i></seealso> is delivered, but no exit signal - due to the link will be delivered to the caller of - <c>spawn_request()</c>. + message</i></seealso> that corresponds to the spawn + operation. If the spawn operation fails, no + exit signal due to the link will be delivered to + the caller of <c>spawn_request()</c>. </p> <p> If the connection between the nodes involved in the spawn operation is lost during the spawn - operation, the spawn operation will fail and an - <i>error message</i> with a <c>Reason</c> of - <c>noconnection</c> will be delivered to the - caller of <c>spawn_request()</c>. A new process - may or may not have been created. If it has been - created, it will be delivered an exit signal with - an exit reason of <c>noconnection</c>. + operation, the spawn operation will fail with + an error reason of <c>noconnection</c>. A new + process may or may not have been created. If it + has been created, it will be delivered an exit + signal with an exit reason of <c>noconnection</c>. </p> </item> + <tag><c>{reply, <anno>Reply</anno>}</c></tag> + <item> + <p>Valid <c>Reply</c> values:</p> + <taglist> + <tag><c>yes</c></tag> + <item><p> + A spawn reply message will be sent to the caller + regardless of whether the operation succeeds or + not. If the call to <c>spawn_request()</c> returns + without raising an exception and the <c>reply</c> + option is set to <c>yes</c>, the caller is + guaranteed to be delivered either a + <seealso marker="#spawn_request_success_message"><i>success + message</i></seealso> or an + <seealso marker="#spawn_request_error_message"><i>error + message</i></seealso>. The <c>reply</c> option is by + default set to <c>yes</c>. + </p></item> + <tag><c>no</c></tag> + <item><p> + No spawn reply message will be sent to the caller + when the spawn operation completes. This regardless of + whether the operation succeeds or not. + </p></item> + <tag><c>error_only</c></tag> + <item><p> + No spawn reply message will be sent to the caller + if the spawn operation succeeds, but an + <seealso marker="#spawn_request_error_message"><i>error + message</i></seealso> will be sent to the caller + if the operation fails. + </p></item> + <tag><c>success_only</c></tag> + <item><p> + No spawn reply message will be sent to the caller + if the spawn operation fails, but a + <seealso marker="#spawn_request_success_message"><i>success + message</i></seealso> will be sent to the caller + if the operation succeeds. + </p></item> + </taglist> + </item> <tag><c>{reply_tag, <anno>ReplyTag</anno>}</c></tag> <item> <p> @@ -6823,7 +6870,7 @@ true</pre> the reply message. That is, in the <seealso marker="#spawn_request_success_message"><i>success</i></seealso> or <seealso marker="#spawn_request_error_message"><i>error</i></seealso> - message that will be sent to the caller due to the + message that is sent to the caller due to the spawn operation. The default reply tag is the atom <c>spawn_reply</c>. </p> @@ -6855,23 +6902,12 @@ true</pre> </list> <p> Note that not all individual <c><anno>Option</anno></c>s - are checked when the spawn request is sent, but instead - on reception of the request. Therefore an invalid option + are checked when the spawn request is sent. Some + <c><anno>Option</anno></c>s can only be checked on + reception of the request. Therefore an invalid option does <em>not</em> cause a <c>badarg</c> exception, but - will cause the spawn operation to fail. An - <seealso marker="#spawn_request_error_message"><i>error - message</i></seealso> with a <c>Reason</c> of <c>badopt</c> - will be sent to the caller. - </p> - <p> - If the call to <c>spawn_request()</c> returns without - raising an exception, the caller is guaranteed to be - delivered either a - <seealso marker="#spawn_request_success_message"><i>success - message</i></seealso> or an - <seealso marker="#spawn_request_error_message"><i>error - message</i></seealso> - as described above. + will cause the spawn operation to fail with an error + reason of <c>badopt</c>. </p> <p> A spawn request can be abandoned by calling diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index dac3f73689..3ea7677b6d 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -250,6 +250,7 @@ atom erlang atom erl_signal_server atom error_handler atom error_logger +atom error_only atom erts_code_purger atom erts_debug atom erts_dflags @@ -560,6 +561,7 @@ atom register atom registered_name atom reload atom rem +atom reply atom reply_tag atom report_errors atom reset @@ -638,6 +640,7 @@ atom stop atom stream atom strict_monotonic atom strict_monotonic_timestamp +atom success_only atom sunrm atom suspend atom suspended diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index b63ef36662..1756d5c0b8 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -742,7 +742,7 @@ BIF_RETTYPE spawn_opt_4(BIF_ALIST_4) * - Bad types * - Bad options */ - opts_error = erts_parse_spawn_opts(&so, BIF_ARG_4, NULL); + opts_error = erts_parse_spawn_opts(&so, BIF_ARG_4, NULL, 0); if (opts_error) { Sint arity; if (is_not_atom(BIF_ARG_1) || is_not_atom(BIF_ARG_2)) @@ -804,7 +804,7 @@ BIF_RETTYPE erts_internal_spawn_request_4(BIF_ALIST_4) * - Bad types * - Bad options */ - opts_error = erts_parse_spawn_opts(&so, BIF_ARG_4, &tag); + opts_error = erts_parse_spawn_opts(&so, BIF_ARG_4, &tag, !0); if (arity > MAX_SMALL) goto system_limit; if (opts_error) { @@ -857,8 +857,9 @@ badopt: /* fall through... */ send_error: { Eterm ref = erts_make_ref(BIF_P); - erts_send_local_spawn_reply(BIF_P, ERTS_PROC_LOCK_MAIN, NULL, - tag, ref, error, am_undefined); + if (!(so.flags & SPO_NO_EMSG)) + erts_send_local_spawn_reply(BIF_P, ERTS_PROC_LOCK_MAIN, NULL, + tag, ref, error, am_undefined); BIF_RET(ref); } diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 01fbf97bb7..3091e322bc 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -2518,7 +2518,7 @@ int erts_net_message(Port *prt, goto invalid_message; } - opts_error = erts_parse_spawn_opts(&so, opts, NULL); + opts_error = erts_parse_spawn_opts(&so, opts, NULL, 0); if (opts_error) { ErtsDSigSendContext ctx; if (opts_error > 1) @@ -5291,9 +5291,10 @@ BIF_RETTYPE erts_internal_dist_spawn_request_4(BIF_ALIST_4) DistEntry *dep = NULL; Eterm list; ErtsDSigSendContext ctx; - int code, link = 0, monitor = 0; + int code, link = 0, monitor = 0, success_message, error_message; ok_result = THE_NON_VALUE; + success_message = error_message = !0; if (!is_node_name_atom(node)) goto badarg; @@ -5345,9 +5346,34 @@ BIF_RETTYPE erts_internal_dist_spawn_request_4(BIF_ALIST_4) switch (tp[1]) { case am_reply_tag: + tag = tp[2]; + + if (0) { + case am_reply: + switch (tp[2]) { + case am_error_only: + success_message = 0; + error_message = !0; + break; + case am_success_only: + success_message = !0; + error_message = 0; + break; + case am_no: + success_message = 0; + error_message = 0; + break; + case am_yes: + success_message = !0; + error_message = !0; + break; + default: + goto badarg; + } + } + if (BIF_ARG_4 != am_spawn_request) goto badarg; - tag = tp[2]; rm_opts++; new_opts = list; @@ -5404,7 +5430,8 @@ BIF_RETTYPE erts_internal_dist_spawn_request_4(BIF_ALIST_4) list = CDR(cp); if (is_tuple_arity(car, 2)) { Eterm *tp = tuple_val(car); - if (am_reply_tag == tp[1]) { + if (am_reply_tag == tp[1] + || am_reply == tp[1]) { rm_cnt++; /* skip option */ if (rm_cnt == rm_opts) { @@ -5480,6 +5507,11 @@ BIF_RETTYPE erts_internal_dist_spawn_request_4(BIF_ALIST_4) mdp->origin.flags |= ERTS_ML_FLG_SPAWN_MONITOR; if (link) mdp->origin.flags |= ERTS_ML_FLG_SPAWN_LINK; + if (!success_message) + mdp->origin.flags |= ERTS_ML_FLG_SPAWN_NO_SMSG; + if (!error_message) + mdp->origin.flags |= ERTS_ML_FLG_SPAWN_NO_EMSG; + erts_monitor_tree_insert(&ERTS_P_MONITORS(BIF_P), &mdp->origin); inserted = erts_monitor_dist_insert(&mdp->target, dep->mld); @@ -5565,8 +5597,9 @@ notsup: /* fall through... */ send_error: ASSERT(is_value(ok_result)); - erts_send_local_spawn_reply(BIF_P, ERTS_PROC_LOCK_MAIN, NULL, - tag, ref, error, am_undefined); + if (error_message) + erts_send_local_spawn_reply(BIF_P, ERTS_PROC_LOCK_MAIN, NULL, + tag, ref, error, am_undefined); ERTS_BIF_PREP_RET(ret_val, ok_result); goto do_return; } diff --git a/erts/emulator/beam/erl_monitor_link.h b/erts/emulator/beam/erl_monitor_link.h index 5b0caa65a1..e10bb27077 100644 --- a/erts/emulator/beam/erl_monitor_link.h +++ b/erts/emulator/beam/erl_monitor_link.h @@ -435,9 +435,18 @@ #define ERTS_ML_FLG_SPAWN_MONITOR (((Uint16) 1) << 6) #define ERTS_ML_FLG_SPAWN_LINK (((Uint16) 1) << 7) #define ERTS_ML_FLG_SPAWN_ABANDONED (((Uint16) 1) << 8) +#define ERTS_ML_FLG_SPAWN_NO_SMSG (((Uint16) 1) << 9) +#define ERTS_ML_FLG_SPAWN_NO_EMSG (((Uint16) 1) << 10) #define ERTS_ML_FLG_DBG_VISITED (((Uint16) 1) << 15) +#define ERTS_ML_FLGS_SPAWN (ERTS_ML_FLG_SPAWN_PENDING \ + | ERTS_ML_FLG_SPAWN_MONITOR \ + | ERTS_ML_FLG_SPAWN_LINK \ + | ERTS_ML_FLG_SPAWN_ABANDONED \ + | ERTS_ML_FLG_SPAWN_NO_SMSG \ + | ERTS_ML_FLG_SPAWN_NO_EMSG) + /* Flags that should be the same on both monitor/link halves */ #define ERTS_ML_FLGS_SAME \ (ERTS_ML_FLG_EXTENDED|ERTS_ML_FLG_NAME) diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c index ce6533ae36..efccb5fcb6 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.c +++ b/erts/emulator/beam/erl_proc_sig_queue.c @@ -2456,8 +2456,12 @@ convert_to_down_message(Process *c_p, /* Should only happen when connection breaks... */ ASSERT(reason == am_noconnection); - if (mdp->origin.flags & ERTS_ML_FLG_SPAWN_ABANDONED) { - /* Operation has been abandoned... */ + if (mdp->origin.flags & (ERTS_ML_FLG_SPAWN_ABANDONED + | ERTS_ML_FLG_SPAWN_NO_EMSG)) { + /* + * Operation has been been abandoned or + * error message has been disabled... + */ erts_monitor_release(*omon); *omon = NULL; return 1; @@ -2499,14 +2503,14 @@ convert_to_down_message(Process *c_p, mp->data.heap_frag = tag_hfrag; } } - mdep->u.name = NIL; /* Restore to normal monitor */ + + /* Restore to normal monitor */ + mdep->u.name = NIL; + mdp->origin.flags &= ~ERTS_ML_FLGS_SPAWN; ERL_MESSAGE_FROM(mp) = am_undefined; ERL_MESSAGE_TERM(mp) = TUPLE4(hp, tag, ref, am_error, reason); - mdp->origin.flags &= ~(ERTS_ML_FLG_SPAWN_PENDING - | ERTS_ML_FLG_SPAWN_MONITOR - | ERTS_ML_FLG_SPAWN_LINK); } else { /* @@ -3430,7 +3434,8 @@ handle_dist_spawn_reply(Process *c_p, ErtsSigRecvTracing *tracing, ASSERT(is_not_atom(result) || !datap->link); /* delete monitor structure... */ adjust_monitor = 0; - if (omon->flags & ERTS_ML_FLG_SPAWN_ABANDONED) + if (omon->flags & (ERTS_ML_FLG_SPAWN_ABANDONED + | ERTS_ML_FLG_SPAWN_NO_EMSG)) convert_to_message = 0; } else if (omon->flags & ERTS_ML_FLG_SPAWN_ABANDONED) { @@ -3491,7 +3496,10 @@ handle_dist_spawn_reply(Process *c_p, ErtsSigRecvTracing *tracing, else { /* Success... */ ASSERT(is_external_pid(result)); - + + if (omon->flags & ERTS_ML_FLG_SPAWN_NO_SMSG) + convert_to_message = 0; + if (datap->link) { cnt++; erts_link_tree_insert(&ERTS_P_LINKS(c_p), datap->link); @@ -3510,9 +3518,7 @@ handle_dist_spawn_reply(Process *c_p, ErtsSigRecvTracing *tracing, Eterm *hp; mdep = (ErtsMonitorDataExtended *) erts_monitor_to_data(omon); hp = &(mdep)->heap[0]; - omon->flags &= ~(ERTS_ML_FLG_SPAWN_PENDING - | ERTS_ML_FLG_SPAWN_MONITOR - | ERTS_ML_FLG_SPAWN_LINK); + omon->flags &= ~ERTS_ML_FLGS_SPAWN; ERTS_INIT_OFF_HEAP(&oh); oh.first = mdep->uptr.ohhp; omon->other.item = copy_struct(result, @@ -3530,6 +3536,8 @@ handle_dist_spawn_reply(Process *c_p, ErtsSigRecvTracing *tracing, */ ErtsMonitorData *mdp = erts_monitor_to_data(omon); + omon->flags &= ~ERTS_ML_FLGS_SPAWN; + erts_monitor_tree_delete(&ERTS_P_MONITORS(c_p), omon); if (erts_monitor_dist_delete(&mdp->target)) diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 88820ed099..16d8230533 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -11486,7 +11486,8 @@ alloc_process(ErtsRunQueue *rq, int bound, erts_aint32_t state) } int -erts_parse_spawn_opts(ErlSpawnOpts *sop, Eterm opts_list, Eterm *tag) +erts_parse_spawn_opts(ErlSpawnOpts *sop, Eterm opts_list, Eterm *tag, + int message_opt) { /* * Returns: @@ -11614,6 +11615,27 @@ erts_parse_spawn_opts(ErlSpawnOpts *sop, Eterm opts_list, Eterm *tag) result = -1; else sop->scheduler = (int) scheduler; + } else if (arg == am_reply) { + if (!message_opt) + result = -1; + else if (val == am_error_only) { + sop->flags |= SPO_NO_SMSG; + sop->flags &= ~SPO_NO_EMSG; + } + else if (val == am_success_only) { + sop->flags &= ~SPO_NO_SMSG; + sop->flags |= SPO_NO_EMSG; + } + else if (val == am_no) { + sop->flags |= SPO_NO_SMSG; + sop->flags |= SPO_NO_EMSG; + } + else if (val == am_yes) { + sop->flags &= ~SPO_NO_SMSG; + sop->flags &= ~SPO_NO_EMSG; + } + else + result = -1; } else if (arg == am_reply_tag) { if (!tag) result = -1; @@ -12099,14 +12121,16 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). seq_trace_update_serial(p); token = SEQ_TRACE_TOKEN(p); } - - /* - * Ensure spawn reply success message reach parent before - * any down or exit signals from child... - */ - erts_send_local_spawn_reply(parent, locks, p, - so->tag, spawn_ref, - p->common.id, token); + + if (!(so->flags & SPO_NO_SMSG)) { + /* + * Ensure spawn reply success message reach parent before + * any down or exit signals from child... + */ + erts_send_local_spawn_reply(parent, locks, p, + so->tag, spawn_ref, + p->common.id, token); + } } else { /* synchronous spawn */ diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index c44df297b4..f38008004f 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1337,6 +1337,8 @@ void erts_check_for_holes(Process* p); #define SPO_IX_MAX_HEAP_SIZE 9 #define SPO_IX_SCHEDULER 10 #define SPO_IX_ASYNC 11 +#define SPO_IX_NO_SMSG 12 +#define SPO_IX_NO_EMSG 13 #define SPO_NO_INDICES (SPO_IX_ASYNC+1) @@ -1352,8 +1354,10 @@ void erts_check_for_holes(Process* p); #define SPO_MAX_HEAP_SIZE (1 << SPO_IX_MAX_HEAP_SIZE) #define SPO_SCHEDULER (1 << SPO_IX_SCHEDULER) #define SPO_ASYNC (1 << SPO_IX_ASYNC) +#define SPO_NO_SMSG (1 << SPO_IX_NO_SMSG) +#define SPO_NO_EMSG (1 << SPO_IX_NO_EMSG) -#define SPO_MAX_FLAG SPO_ASYNC +#define SPO_MAX_FLAG SPO_NO_EMSG #define SPO_USE_ARGS \ (SPO_MIN_HEAP_SIZE \ @@ -1898,7 +1902,8 @@ Eterm erts_bind_schedulers(Process *c_p, Eterm how); ErtsRunQueue *erts_schedid2runq(Uint); Process *erts_schedule(ErtsSchedulerData *, Process*, int); void erts_schedule_misc_op(void (*)(void *), void *); -int erts_parse_spawn_opts(ErlSpawnOpts *sop, Eterm opts_list, Eterm *tag); +int erts_parse_spawn_opts(ErlSpawnOpts *sop, Eterm opts_list, Eterm *tag, + int success_message_opt); void erts_send_local_spawn_reply(Process *parent, ErtsProcLocks parent_locks, Process *child, Eterm tag, Eterm ref, diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 1643416298..a6210a3ca2 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -73,7 +73,8 @@ spawn_request_abandon_bif/1, dist_spawn_monitor/1, spawn_old_node/1, - spawn_new_node/1]). + spawn_new_node/1, + spawn_request_reply_option/1]). -export([prio_server/2, prio_client/2, init/1, handle_event/2]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -111,6 +112,7 @@ all() -> dist_spawn_monitor, spawn_old_node, spawn_new_node, + spawn_request_reply_option, otp_6237, {group, processes_bif}, {group, otp_7738}, garb_other_running, @@ -3222,6 +3224,92 @@ spawn_current_node_test(Node, Disconnect) -> ok end. +spawn_request_reply_option(Config) when is_list(Config) -> + spawn_request_reply_option_test(node()), + {ok, Node} = start_node(Config), + spawn_request_reply_option_test(Node). + +spawn_request_reply_option_test(Node) -> + io:format("Testing on node: ~p~n", [Node]), + Parent = self(), + Done1 = make_ref(), + RID1 = spawn_request(Node, fun () -> Parent ! Done1 end, [{reply, yes}]), + receive Done1 -> ok end, + receive + {spawn_reply, RID1, ok, _} -> ok + after 0 -> + ct:fail(missing_spawn_reply) + end, + Done2 = make_ref(), + RID2 = spawn_request(Node, fun () -> Parent ! Done2 end, [{reply, success_only}]), + receive Done2 -> ok end, + receive + {spawn_reply, RID2, ok, _} -> ok + after 0 -> + ct:fail(missing_spawn_reply) + end, + Done3 = make_ref(), + RID3 = spawn_request(Node, fun () -> Parent ! Done3 end, [{reply, error_only}]), + receive Done3 -> ok end, + receive + {spawn_reply, RID3, _, _} -> + ct:fail(unexpected_spawn_reply) + after 0 -> + ok + end, + Done4 = make_ref(), + RID4 = spawn_request(Node, fun () -> Parent ! Done4 end, [{reply, no}]), + receive Done4 -> ok end, + receive + {spawn_reply, RID4, _, _} -> + ct:fail(unexpected_spawn_reply) + after 0 -> + ok + end, + RID5 = spawn_request(Node, fun () -> ok end, [{reply, yes}, bad_option]), + receive + {spawn_reply, RID5, error, badopt} -> ok + end, + RID6 = spawn_request(Node, fun () -> ok end, [{reply, success_only}, bad_option]), + receive + {spawn_reply, RID6, error, badopt} -> ct:fail(unexpected_spawn_reply) + after 1000 -> ok + end, + RID7 = spawn_request(Node, fun () -> ok end, [{reply, error_only}, bad_option]), + receive + {spawn_reply, RID7, error, badopt} -> ok + end, + RID8 = spawn_request(Node, fun () -> ok end, [{reply, no}, bad_option]), + receive + {spawn_reply, RID8, error, badopt} -> ct:fail(unexpected_spawn_reply) + after 1000 -> ok + end, + case Node == node() of + true -> + ok; + false -> + stop_node(Node), + RID9 = spawn_request(Node, fun () -> ok end, [{reply, yes}]), + receive + {spawn_reply, RID9, error, noconnection} -> ok + end, + RID10 = spawn_request(Node, fun () -> ok end, [{reply, success_only}]), + receive + {spawn_reply, RID10, error, noconnection} -> ct:fail(unexpected_spawn_reply) + after 1000 -> ok + end, + RID11 = spawn_request(Node, fun () -> ok end, [{reply, error_only}]), + receive + {spawn_reply, RID11, error, noconnection} -> ok + end, + RID12 = spawn_request(Node, fun () -> ok end, [{reply, no}]), + receive + {spawn_reply, RID12, error, noconnection} -> ct:fail(unexpected_spawn_reply) + after 1000 -> ok + end, + ok + end. + processes_term_proc_list(Config) when is_list(Config) -> Tester = self(), diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex 2e420bf0e5..1abc466577 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 3fc8b7e2a6..63a280f24d 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -3173,8 +3173,11 @@ spawn_request(F) -> -spec spawn_request(Fun, Options) -> ReqId when Fun :: function(), - Option :: {reply_tag, ReplyTag} | spawn_opt_option(), + Option :: {reply_tag, ReplyTag} + | {reply, Reply} + | spawn_opt_option(), ReplyTag :: term(), + Reply :: yes | no | error_only | success_only, Options :: [Option], ReqId :: reference(); (Node, Fun) -> ReqId when @@ -3207,8 +3210,13 @@ spawn_request(A1, A2) -> Node :: node(), Fun :: function(), Options :: [Option], - Option :: monitor | link | {reply_tag, ReplyTag} | OtherOption, + Option :: monitor + | link + | {reply_tag, ReplyTag} + | {reply, Reply} + | OtherOption, ReplyTag :: term(), + Reply :: yes | no | error_only | success_only, OtherOption :: term(), ReqId :: reference(); (Module, Function, Args) -> @@ -3249,8 +3257,11 @@ spawn_request(M, F, A) -> Module :: module(), Function :: atom(), Args :: [term()], - Option :: {reply_tag, ReplyTag} | spawn_opt_option(), + Option :: {reply_tag, ReplyTag} + | {reply, Reply} + | spawn_opt_option(), ReplyTag :: term(), + Reply :: yes | no | error_only | success_only, Options :: [Option], ReqId :: reference(). @@ -3280,8 +3291,13 @@ spawn_request(M, F, A, O) -> Function :: atom(), Args :: [term()], Options :: [Option], - Option :: monitor | link | {reply_tag, ReplyTag} | OtherOption, + Option :: monitor + | link + | {reply_tag, ReplyTag} + | {reply, Reply} + | OtherOption, ReplyTag :: term(), + Reply :: yes | no | error_only | success_only, OtherOption :: term(), ReqId :: reference(). |