summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--erts/doc/src/erlang.xml166
-rw-r--r--erts/emulator/beam/atom.names3
-rw-r--r--erts/emulator/beam/bif.c9
-rw-r--r--erts/emulator/beam/dist.c45
-rw-r--r--erts/emulator/beam/erl_monitor_link.h9
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c30
-rw-r--r--erts/emulator/beam/erl_process.c42
-rw-r--r--erts/emulator/beam/erl_process.h9
-rw-r--r--erts/emulator/test/process_SUITE.erl90
-rw-r--r--erts/preloaded/ebin/erlang.beambin108756 -> 108936 bytes
-rw-r--r--erts/preloaded/src/erlang.erl24
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
index 2e420bf0e5..1abc466577 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
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().