File 4361-Support-for-start_monitor-in-proc_lib-and-gen-behavi.patch of Package erlang

From 22aa1f15bf28b98ab1243b64c5e8508f020e6e4b Mon Sep 17 00:00:00 2001
From: Rickard Green <rickard@erlang.org>
Date: Fri, 18 Oct 2019 19:37:06 +0200
Subject: [PATCH] Support for start_monitor in proc_lib and gen behaviours

---
 erts/doc/src/erlang.xml              |  31 ++++++
 erts/preloaded/ebin/erlang.beam      | Bin 101968 -> 101912 bytes
 erts/preloaded/src/erlang.erl        |  12 +--
 lib/stdlib/doc/src/gen_event.xml     |  35 +++++++
 lib/stdlib/doc/src/gen_server.xml    |  45 ++++++++-
 lib/stdlib/doc/src/gen_statem.xml    |  56 +++++++++--
 lib/stdlib/doc/src/proc_lib.xml      |  96 ++++++++++++++----
 lib/stdlib/src/gen.erl               |  36 ++++++-
 lib/stdlib/src/gen_event.erl         |  22 ++++-
 lib/stdlib/src/gen_server.erl        |  12 +++
 lib/stdlib/src/gen_statem.erl        |  23 ++++-
 lib/stdlib/src/proc_lib.erl          | 183 ++++++++++++++++++----------------
 lib/stdlib/test/gen_event_SUITE.erl  |  51 ++++++++++
 lib/stdlib/test/gen_server_SUITE.erl |  44 +++++++++
 lib/stdlib/test/gen_statem_SUITE.erl |  58 ++++++++++-
 lib/stdlib/test/proc_lib_SUITE.erl   | 184 +++++++++++++++++++++++++++++++++--
 16 files changed, 758 insertions(+), 130 deletions(-)

diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 6932b18571..5d28ee14d0 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -205,6 +205,37 @@
 	</seealso>.</p>
       </desc>
     </datatype>
+    <datatype>
+      <name name="spawn_opt_option"></name>
+      <desc>
+        <p>Options for <seealso marker="#spawn_opt/4"><c>spawn_opt()</c></seealso>.</p>
+      </desc>
+    </datatype>
+    <datatype>
+      <name name="priority_level"></name>
+      <desc>
+        <p>Process priority level. For more info see
+        <seealso marker="#process_flag_priority"><c>process_flag(priority,
+	Level)</c></seealso> </p>
+      </desc>
+    </datatype>
+    <datatype>
+      <name name="max_heap_size"></name>
+      <desc>
+        <p>Process max heap size configuration. For more info see
+        <seealso marker="#process_flag_max_heap_size"><c>process_flag(max_heap_size,
+	MaxHeapSize)</c></seealso> </p>
+      </desc>
+    </datatype>
+    <datatype>
+      <name name="message_queue_data"></name>
+      <desc>
+        <p>Process message queue data configuration. For more info see
+        <seealso marker="#process_flag_message_queue_data"><c>process_flag(message_queue_data,
+	MQD)</c></seealso> </p>
+      </desc>
+    </datatype>
+    
 
   </datatypes>
 
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 5730e999cb..51d28e240a 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -62,6 +62,10 @@
 -export_type([timestamp/0]).
 -export_type([time_unit/0]).
 -export_type([deprecated_time_unit/0]).
+-export_type([spawn_opt_option/0]).
+-export_type([priority_level/0]).
+-export_type([max_heap_size/0]).
+-export_type([message_queue_data/0]).
 
 -type ext_binary() :: binary().
 -type timestamp() :: {MegaSecs :: non_neg_integer(),
@@ -2396,12 +2400,8 @@ setelement(_Index, _Tuple1, _Value) ->
       Function :: atom(),
       Args :: [term()],
       Options :: [Option],
-      Option :: link | monitor
-              | {priority, Level :: priority_level()}
-              | {fullsweep_after, Number :: non_neg_integer()}
-              | {min_heap_size, Size :: non_neg_integer()}
-              | {max_heap_size, Size :: max_heap_size()}
-              | {min_bin_vheap_size, VSize :: non_neg_integer()}.
+      Option :: spawn_opt_option().
+
 spawn_opt(_Tuple) ->
    erlang:nif_error(undefined).
 
diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml
index 2915c4f507..f13afd1d34 100644
--- a/lib/stdlib/doc/src/gen_event.xml
+++ b/lib/stdlib/doc/src/gen_event.xml
@@ -50,6 +50,7 @@
 gen_event module                   Callback module
 ----------------                   ---------------
 gen_event:start
+gen_event:start_monitor
 gen_event:start_link       ----->  -
 
 gen_event:add_handler
@@ -435,6 +436,40 @@ gen_event:stop             ----->  Module:terminate/2
       </desc>
     </func>
 
+    <func>
+      <name since="OTP 23.0">start_monitor() -> Result</name>
+      <name since="OTP 23.0">start_monitor(EventMgrName | Options) -> Result</name>
+      <name since="OTP 23.0">start_monitor(EventMgrName, Options) -> Result</name>
+      <fsummary>Create a stand-alone event manager process.</fsummary>
+      <type>
+        <v>EventMgrName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}</v>
+        <v>&nbsp;Name = atom()</v>
+        <v>&nbsp;GlobalName = ViaName = term()</v>
+        <v>Options = [Option]</v>
+        <v>&nbsp;Option = {debug,Dbgs} | {timeout,Time} | {hibernate_after,HibernateAfterTimeout} | {spawn_opt,SOpts}</v>
+        <v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
+        <v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v>
+        <v>&nbsp;&nbsp;SOpts = [term()]</v>
+        <v>Result = {ok,{Pid,Mon}} | {error,{already_started,Pid}}</v>
+        <v>&nbsp;Pid = pid()</v>
+      </type>
+      <desc>
+        <p>Creates a stand-alone event manager process, that is, an event
+          manager that is not part of a supervision tree (and thus has
+          no supervisor) and atomically sets up a monitor to
+	  the newly created process.</p>
+        <p>For a description of the arguments and return values, see
+          <seealso marker="#start_link/0"><c>start_link/0,1</c></seealso>.
+	Note that the return value on successful start differs from
+	<c>start_link/3,4</c>. <c>start_monitor/3,4</c> will return
+	<c>{ok,{Pid,Mon}}</c> where <c>Pid</c> is the process identifier
+	of the process, and <c>Mon</c> is a reference to the monitor
+	set up to monitor the process. If the start is not successful,
+	the caller will be blocked until the <c>DOWN</c> message has
+	been received and removed from the message queue.</p>
+      </desc>
+    </func>
+
     <func>
       <name since="">stop(EventMgrRef) -> ok</name>
       <name since="OTP 18.0">stop(EventMgrRef, Reason, Timeout) -> ok</name>
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml
index a4554d7657..4c948246f7 100644
--- a/lib/stdlib/doc/src/gen_server.xml
+++ b/lib/stdlib/doc/src/gen_server.xml
@@ -48,6 +48,7 @@
 gen_server module            Callback module
 -----------------            ---------------
 gen_server:start
+gen_server:start_monitor
 gen_server:start_link -----> Module:init/1
 
 gen_server:stop       -----> Module:terminate/2
@@ -232,7 +233,7 @@ gen_server:abcast     -----> Module:handle_cast/2
           is needed than the <c>gen_server</c> process behavior provides.</p>
         <p><c>Module</c>, <c>Options</c>, and <c>ServerName</c> have
           the same meanings as when calling
-          <seealso marker="#start_link/3"><c>start[_link]/3,4</c></seealso>.
+          <seealso marker="#start_link/3"><c>start[_link|_monitor]/3,4</c></seealso>.
           However, if <c>ServerName</c> is specified, the process must
           have been registered accordingly <em>before</em> this function
           is called.</p>
@@ -465,6 +466,43 @@ gen_server:abcast     -----> Module:handle_cast/2
       </desc>
     </func>
 
+    <func>
+      <name since="OTP 23.0">start_monitor(Module, Args, Options) -> Result</name>
+      <name since="OTP 23.0">start_monitor(ServerName, Module, Args, Options) -> Result</name>
+      <fsummary>Create a standalone <c>gen_server</c> process.</fsummary>
+      <type>
+        <v>ServerName = {local,Name} | {global,GlobalName}</v>
+        <v>&nbsp;&nbsp;| {via,Module,ViaName}</v>
+        <v>&nbsp;Name = atom()</v>
+        <v>&nbsp;GlobalName = ViaName = term()</v>
+        <v>Module = atom()</v>
+        <v>Args = term()</v>
+        <v>Options = [Option]</v>
+        <v>&nbsp;Option = {debug,Dbgs} | {timeout,Time} | {hibernate_after,HibernateAfterTimeout} | {spawn_opt,SOpts}</v>
+        <v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
+        <v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v>
+        <v>&nbsp;&nbsp;SOpts = [term()]</v>
+        <v>Result = {ok,{Pid,Mon}} | ignore | {error,Error}</v>
+        <v>&nbsp;Pid = pid()</v>
+        <v>&nbsp;Error = {already_started,Pid} | term()</v>
+      </type>
+      <desc>
+        <p>Creates a standalone <c>gen_server</c> process, that is, a
+          <c>gen_server</c> process that is not part of a supervision tree
+          (and thus has no supervisor) and atomically sets up a monitor to
+	  the newly created server.</p>
+        <p>For a description of arguments and return values, see
+        <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>.
+	Note that the return value on successful start differs from
+	<c>start_link/3,4</c>. <c>start_monitor/3,4</c> will return
+	<c>{ok,{Pid,Mon}}</c> where <c>Pid</c> is the process identifier
+	of the server, and <c>Mon</c> is a reference to the monitor
+	set up to monitor the server. If the start is not successful,
+	the caller will be blocked until the <c>DOWN</c> message has
+	been received and removed from the message queue.</p>
+      </desc>
+    </func>
+
     <func>
       <name since="OTP 18.0">stop(ServerRef) -> ok</name>
       <name since="OTP 18.0">stop(ServerRef, Reason, Timeout) -> ok</name>
@@ -782,8 +820,9 @@ gen_server:abcast     -----> Module:handle_cast/2
       </type>
       <desc>
         <p>Whenever a <c>gen_server</c> process is started using
-          <seealso marker="#start/3"><c>start/3,4</c></seealso> or
-          <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>,
+          <seealso marker="#start/3"><c>start/3,4</c></seealso>,
+          <seealso marker="#start_monitor/3"><c>start_monitor/3,4</c></seealso>,
+          or <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>,
           this function is called by the new process to initialize.</p>
         <p><c>Args</c> is the <c>Args</c> argument provided to the start
           function.</p>
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index aaa26df18d..2a3ee8c37d 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -135,6 +135,7 @@
 gen_statem module            Callback module
 -----------------            ---------------
 gen_statem:start
+gen_statem:start_monitor
 gen_statem:start_link -----> Module:init/1
 
 Server start or code change
@@ -293,6 +294,7 @@ erlang:'!'            -----> Module:StateName/3
       </seealso>
       for
       <seealso marker="#start/3"><c>start/3,4</c></seealso>,
+      <seealso marker="#start_monitor/3"><c>start_monitor/3,4</c></seealso>, or
       <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso> or
       <seealso marker="#enter_loop/4"><c>enter_loop/4,5,6</c></seealso>,
       that may be used to automatically hibernate the server.
@@ -526,8 +528,18 @@ handle_event(_, _, State, Data) ->
       <name name="start_ret"/>
       <desc>
 	<p>
-	  Return value from the start functions, for example,
-	  <seealso marker="#start_link/3"><c>start_link/3</c></seealso>.
+	  Return value from the <c>start()</c> and <c>start_link()</c> functions,
+	  for example, <seealso marker="#start_link/3"><c>start_link/3</c></seealso>.
+	</p>
+      </desc>
+    </datatype>
+    <datatype>
+      <name name="start_mon_ret"/>
+      <desc>
+	<p>
+	  Return value from the
+	  <seealso marker="#start_monitor/3"><c>start_monitor()</c></seealso>
+	  functions.
 	</p>
       </desc>
     </datatype>
@@ -1553,16 +1565,16 @@ handle_event(_, _, State, Data) ->
 	<p>
 	  <c><anno>Module</anno></c>, <c><anno>Opts</anno></c>
 	  have the same meaning as when calling
-	  <seealso marker="#start_link/3"><c>start[_link]/3,4</c></seealso>.
+	  <seealso marker="#start_link/3"><c>start[_link|_monitor]/3,4</c></seealso>.
 	</p>
 	<p>
 	  If <c><anno>Server</anno></c> is <c>self()</c> an anonymous
 	  server is created just as when using 
-	  <seealso marker="#start_link/3"><c>start[_link]/3</c></seealso>.
+	  <seealso marker="#start_link/3"><c>start[_link|_monitor]/3</c></seealso>.
 	  If <c><anno>Server</anno></c> is a
 	  <seealso marker="#type-server_name"><c>server_name()</c></seealso>
 	  a named server is created just as when using
-	  <seealso marker="#start_link/4"><c>start[_link]/4</c></seealso>.
+	  <seealso marker="#start_link/4"><c>start[_link|_monitor]/4</c></seealso>.
 	  However, the
 	  <seealso marker="#type-server_name"><c>server_name()</c></seealso>
 	  name must have been registered accordingly
@@ -1749,6 +1761,35 @@ handle_event(_, _, State, Data) ->
       </desc>
     </func>
 
+    <func>
+      <name name="start_monitor" arity="3" since="OTP 23.0"/>
+      <name name="start_monitor" arity="4" since="OTP 23.0"/>
+      <fsummary>Create a standalone <c>gen_statem</c> process.</fsummary>
+      <desc>
+        <p>
+	  Creates a standalone <c>gen_statem</c> process according to
+	  OTP design principles (using
+	  <seealso marker="proc_lib"><c>proc_lib</c></seealso>
+	  primitives) and atomically sets up a monitor to
+	  the newly created process.
+	  As it does not get linked to the calling process,
+	  this start function cannot be used by a supervisor
+	  to start a child.
+	</p>
+	<p>
+	  For a description of arguments and return values, see
+	  <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>.
+	  Note that the return value on successful start differs from
+	  <c>start_link/3,4</c>. <c>start_monitor/3,4</c> will return
+	  <c>{ok,{Pid,Mon}}</c> where <c>Pid</c> is the process identifier
+	  of the process, and <c>Mon</c> is a reference to the monitor
+	  set up to monitor the process. If the start is not successful,
+	  the caller will be blocked until the <c>DOWN</c> message has
+	  been received and removed from the message queue.
+	</p>
+      </desc>
+    </func>
+
     <func>
       <name name="stop" arity="1" since="OTP 19.0"/>
       <fsummary>Synchronously stop a generic server.</fsummary>
@@ -1962,7 +2003,8 @@ handle_event(_, _, State, Data) ->
 	<marker id="Module:init-1"/>
 	<p>
 	  Whenever a <c>gen_statem</c> is started using
-	  <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>
+	  <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>,
+	  <seealso marker="#start_monitor/3"><c>start_monitor/3,4</c></seealso>,
 	  or
 	  <seealso marker="#start/3"><c>start/3,4</c></seealso>,
 	  this function is called by the new process to initialize
diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml
index aeb9f48735..9debbfb8d0 100644
--- a/lib/stdlib/doc/src/proc_lib.xml
+++ b/lib/stdlib/doc/src/proc_lib.xml
@@ -86,13 +86,11 @@
       </desc>
     </datatype>
     <datatype>
-      <name name="priority_level"/>
-    </datatype>
-    <datatype>
-      <name name="max_heap_size"/>
+      <name name="start_spawn_option"/>
       <desc>
-        <p>See <seealso marker="erts:erlang#process_flag_max_heap_size">
-          erlang:process_flag(max_heap_size, MaxHeapSize)</seealso>.</p>
+        <p>A restricted set of <seealso marker="#type-spawn_option">spawn
+	options</seealso>. Most notably <c>monitor</c> is <em>not</em> part
+	of these options.</p>
       </desc>
     </datatype>
     <datatype>
@@ -295,8 +293,31 @@ init(Parent) ->
       <desc>
         <p>Spawns a new process and initializes it as described in the
           beginning of this manual page. The process is spawned using the
-          <seealso marker="erts:erlang#spawn_opt/2"><c>spawn_opt</c></seealso>
+          <seealso marker="erts:erlang#spawn_opt/2"><c>erlang:spawn_opt</c></seealso>
           BIFs.</p>
+      </desc>
+    </func>
+
+    <func>
+      <name name="start" arity="3" since=""/>
+      <name name="start" arity="4" since=""/>
+      <name name="start" arity="5" since=""/>
+      <fsummary>Start a new process synchronously.</fsummary>
+      <desc>
+        <p>Starts a new process synchronously. Spawns the process and
+          waits for it to start. When the process has started, it
+          <em>must</em> call
+          <seealso marker="#init_ack/2"><c>init_ack(Parent, Ret)</c></seealso>
+          or <seealso marker="#init_ack/1"><c>init_ack(Ret)</c></seealso>,
+          where <c>Parent</c> is the process that evaluates this
+          function. At this time, <c>Ret</c> is returned.</p>
+        <p>If <c><anno>Time</anno></c> is specified as an integer, this
+          function waits for <c><anno>Time</anno></c> milliseconds for the
+          new process to call <c>init_ack</c>, or <c>Ret = {error, timeout}</c>
+	  will be returned, and the process is killed.</p>
+        <p>Argument <c><anno>SpawnOpts</anno></c>, if specified, is passed
+          as the last argument to the <seealso marker="erts:erlang#spawn_opt/2">
+          <c>spawn_opt/2,3,4,5</c></seealso> BIF.</p>
         <note>
           <p>Using spawn option <c>monitor</c> is not
             allowed. It causes the function to fail with reason
@@ -306,29 +327,68 @@ init(Parent) ->
     </func>
 
     <func>
-      <name name="start" arity="3" since=""/>
-      <name name="start" arity="4" since=""/>
-      <name name="start" arity="5" since=""/>
       <name name="start_link" arity="3" since=""/>
       <name name="start_link" arity="4" since=""/>
       <name name="start_link" arity="5" since=""/>
       <fsummary>Start a new process synchronously.</fsummary>
       <desc>
-        <p>Starts a new process synchronously. Spawns the process and
-          waits for it to start. When the process has started, it
+        <p>
+	  Starts a new process synchronously. Spawns the process and
+          waits for it to start. A link is atomically set on the
+	  newly spawned process. When the process has started, it
+          <em>must</em> call
+          <seealso marker="#init_ack/2"><c>init_ack(Parent, Ret)</c></seealso>
+          or <seealso marker="#init_ack/1"><c>init_ack(Ret)</c></seealso>,
+          where <c>Parent</c> is the process that evaluates this
+          function. At this time, <c>Ret</c> is returned.</p>
+        <p>If <c><anno>Time</anno></c> is specified as an integer, this
+          function waits for <c><anno>Time</anno></c> milliseconds for the
+          new process to call <c>init_ack</c>, or <c>Ret = {error, timeout}</c>
+	  will be returned, and the process is killed.</p>
+        <p>If the process crashes before it has called <c>init_ack/1,2</c>,
+          <c>Ret = {error, <anno>Reason</anno>}</c> will be returned if
+	  the calling process traps exits.</p>
+        <p>Argument <c><anno>SpawnOpts</anno></c>, if specified, is passed
+          as the last argument to the <seealso marker="erts:erlang#spawn_opt/2">
+          <c>spawn_opt/2,3,4,5</c></seealso> BIF.</p>
+        <note>
+          <p>Using spawn option <c>monitor</c> is not
+            allowed. It causes the function to fail with reason
+            <c>badarg</c>.</p>
+        </note>
+      </desc>
+    </func>
+
+    <func>
+      <name name="start_monitor" arity="3" since="OTP 23.0"/>
+      <name name="start_monitor" arity="4" since="OTP 23.0"/>
+      <name name="start_monitor" arity="5" since="OTP 23.0"/>
+      <fsummary>Start a new process synchronously.</fsummary>
+      <desc>
+        <p>
+	  Starts a new process synchronously. Spawns the process and
+          waits for it to start. A monitor is atomically set on the
+	  newly spawned process. When the process has started, it
           <em>must</em> call
           <seealso marker="#init_ack/2"><c>init_ack(Parent, Ret)</c></seealso>
           or <seealso marker="#init_ack/1"><c>init_ack(Ret)</c></seealso>,
           where <c>Parent</c> is the process that evaluates this
           function. At this time, <c>Ret</c> is returned.</p>
-        <p>If function <c>start_link/3,4,5</c> is used and
-          the process crashes before it has called <c>init_ack/1,2</c>,
-          <c>{error, <anno>Reason</anno>}</c> is returned if the calling
-          process traps exits.</p>
         <p>If <c><anno>Time</anno></c> is specified as an integer, this
           function waits for <c><anno>Time</anno></c> milliseconds for the
-          new process to call <c>init_ack</c>, or <c>{error, timeout}</c> is
-          returned, and the process is killed.</p>
+          new process to call <c>init_ack</c>, or <c>Ret = {error, timeout}</c>
+	  will be returned, and the process is killed.</p>
+	<p>
+	  The return value is <c>{Ret, Mon}</c> where <c>Ret</c> corresponds
+	  to the <c>Ret</c> argument in the call to <c>init_ack()</c>, and
+	  <c>Mon</c> is the monitor reference of the monitor that has been
+	  set up.
+	</p>
+	<p>
+	  A <c>'DOWN'</c> message will be delivered to the caller if
+	  this function returns, and the spawned process terminates. This is
+	  true also in the case when the operation times out.
+	</p>
         <p>Argument <c><anno>SpawnOpts</anno></c>, if specified, is passed
           as the last argument to the <seealso marker="erts:erlang#spawn_opt/2">
           <c>spawn_opt/2,3,4,5</c></seealso> BIF.</p>
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index a7f743bd4c..d0619cbb63 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -38,7 +38,7 @@
 
 %%-----------------------------------------------------------------
 
--type linkage()    :: 'link' | 'nolink'.
+-type linkage()    :: 'monitor' | 'link' | 'nolink'.
 -type emgr_name()  :: {'local', atom()}
                     | {'global', term()}
                     | {'via', Module :: module(), Name :: term()}.
@@ -95,6 +95,13 @@ do_spawn(GenMod, link, Mod, Args, Options) ->
 			[GenMod, self(), self(), Mod, Args, Options], 
 			Time,
 			spawn_opts(Options));
+do_spawn(GenMod, monitor, Mod, Args, Options) ->
+    Time = timeout(Options),
+    Ret = proc_lib:start_monitor(?MODULE, init_it,
+                                 [GenMod, self(), self(), Mod, Args, Options], 
+                                 Time,
+                                 spawn_opts(Options)),
+    monitor_return(Ret);
 do_spawn(GenMod, _, Mod, Args, Options) ->
     Time = timeout(Options),
     proc_lib:start(?MODULE, init_it,
@@ -108,6 +115,13 @@ do_spawn(GenMod, link, Name, Mod, Args, Options) ->
 			[GenMod, self(), self(), Name, Mod, Args, Options],
 			Time,
 			spawn_opts(Options));
+do_spawn(GenMod, monitor, Name, Mod, Args, Options) ->
+    Time = timeout(Options),
+    Ret = proc_lib:start_monitor(?MODULE, init_it,
+                                 [GenMod, self(), self(), Name, Mod, Args, Options],
+                                 Time,
+                                 spawn_opts(Options)),
+    monitor_return(Ret);
 do_spawn(GenMod, _, Name, Mod, Args, Options) ->
     Time = timeout(Options),
     proc_lib:start(?MODULE, init_it,
@@ -115,6 +129,26 @@ do_spawn(GenMod, _, Name, Mod, Args, Options) ->
 		   Time,
 		   spawn_opts(Options)).
 
+
+%%
+%% Adjust monitor returns for OTP gen behaviours...
+%%
+%% If an OTP behaviour is introduced that 'init_ack's
+%% other results, this has code has to be moved out
+%% into all behaviours as well as adjusted...
+%%
+monitor_return({{ok, Pid}, Mon}) when is_pid(Pid), is_reference(Mon) ->
+    %% Successful start_monitor()...
+    {ok, {Pid, Mon}};
+monitor_return({Error, Mon}) when is_reference(Mon) ->
+    %% Failure; wait for spawned process to terminate
+    %% and release resources, then return the error...
+    receive
+        {'DOWN', Mon, process, _Pid, _Reason} ->
+            ok
+    end,
+    Error.
+
 %%-----------------------------------------------------------------
 %% Initiate the new process.
 %% Register the name using the Rfunc function
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 8213282867..f95d721fbb 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -31,9 +31,14 @@
 %%% Re-written by Joe with new functional interface !
 %%% Modified by Martin - uses proc_lib, sys and gen!
 
+%%%
+%%% NOTE: If init_ack() return values are modified, see comment
+%%%       above monitor_return() in gen.erl!
+%%%
 
 -export([start/0, start/1, start/2,
          start_link/0, start_link/1, start_link/2,
+         start_monitor/0, start_monitor/1, start_monitor/2,
          stop/1, stop/3,
 	 notify/2, sync_notify/2,
 	 add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3,
@@ -130,11 +130,12 @@
                     | {'logfile', string()}.
 -type option() :: {'timeout', timeout()}
                 | {'debug', [debug_flag()]}
-                | {'spawn_opt', [proc_lib:spawn_option()]}
+                | {'spawn_opt', [proc_lib:start_spawn_option()]}
                 | {'hibernate_after', timeout()}.
 -type emgr_ref()  :: atom() | {atom(), atom()} |  {'global', term()}
                    | {'via', atom(), term()} | pid().
 -type start_ret() :: {'ok', pid()} | {'error', term()}.
+-type start_mon_ret() :: {'ok', {pid(),reference()}} | {'error', term()}.
 -type request_id() :: term().
 
 %%---------------------------------------------------------------------------
@@ -186,6 +192,20 @@ start_link(Options) when is_list(Options) ->
 start_link(Name, Options) ->
     gen:start(?MODULE, link, Name, ?NO_CALLBACK, [], Options).
 
+-spec start_monitor() -> start_mon_ret().
+start_monitor() ->
+    gen:start(?MODULE, monitor, ?NO_CALLBACK, [], []).
+
+-spec start_monitor(emgr_name() | [option()]) -> start_mon_ret().
+start_monitor(Name) when is_tuple(Name) ->
+    gen:start(?MODULE, monitor, Name, ?NO_CALLBACK, [], []);
+start_monitor(Options) when is_list(Options) ->
+    gen:start(?MODULE, monitor, ?NO_CALLBACK, [], Options).
+
+-spec start_monitor(emgr_name(), [option()]) -> start_mon_ret().
+start_monitor(Name, Options) ->
+    gen:start(?MODULE, monitor, Name, ?NO_CALLBACK, [], Options).
+
 %% -spec init_it(pid(), 'self' | pid(), emgr_name(), module(), [term()], [_]) -> 
 init_it(Starter, self, Name, Mod, Args, Options) ->
     init_it(Starter, self(), Name, Mod, Args, Options);
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 44e9231ebe..5dce5e78ad 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -19,6 +19,11 @@
 %%
 -module(gen_server).
 
+%%%
+%%% NOTE: If init_ack() return values are modified, see comment
+%%%       above monitor_return() in gen.erl!
+%%%
+
 %%% ---------------------------------------------------
 %%%
 %%% The idea behind THIS server is that the user module
@@ -89,6 +94,7 @@
 %% API
 -export([start/3, start/4,
 	 start_link/3, start_link/4,
+         start_monitor/3, start_monitor/4,
 	 stop/1, stop/3,
 	 call/2, call/3,
          send_request/2, wait_response/2, check_response/2,
@@ -199,6 +205,12 @@ start_link(Mod, Args, Options) ->
 start_link(Name, Mod, Args, Options) ->
     gen:start(?MODULE, link, Name, Mod, Args, Options).
 
+start_monitor(Mod, Args, Options) ->
+    gen:start(?MODULE, monitor, Mod, Args, Options).
+
+start_monitor(Name, Mod, Args, Options) ->
+    gen:start(?MODULE, monitor, Name, Mod, Args, Options).
+
 
 %% -----------------------------------------------------------------
 %% Stop a generic server and wait for it to terminate.
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index 8965af253b..a98c98b802 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -21,9 +21,15 @@
 
 -include("logger.hrl").
 
+%%%
+%%% NOTE: If init_ack() return values are modified, see comment
+%%%       above monitor_return() in gen.erl!
+%%%
+
 %% API
 -export(
    [start/3,start/4,start_link/3,start_link/4,
+    start_monitor/3,start_monitor/4,
     stop/1,stop/3,
     cast/2,call/2,call/3,
     send_request/2,wait_response/1,wait_response/2,check_response/2,
@@ -456,12 +462,13 @@ timeout_event_type(Type) ->
       | {'via', RegMod :: module(), ViaName :: term()}.
 -type start_opt() ::
         {'timeout', Time :: timeout()}
-      | {'spawn_opt', [proc_lib:spawn_option()]}
+      | {'spawn_opt', [proc_lib:start_spawn_option()]}
       | enter_loop_opt().
 -type start_ret() ::
         {'ok', pid()}
       | 'ignore'
       | {'error', term()}.
+-type start_mon_ret() ::  {'ok', {pid(),reference()}} | 'ignore' | {'error', term()}.
 -type enter_loop_opt() ::
 	{'hibernate_after', HibernateAfterTimeout :: timeout()}
       | {'debug', Dbgs :: [sys:debug_option()]}.
@@ -496,6 +503,20 @@ start_link(Module, Args, Opts) ->
 start_link(ServerName, Module, Args, Opts) ->
     gen:start(?MODULE, link, ServerName, Module, Args, Opts).
 
+%% Start and monitor a state machine
+-spec start_monitor(
+	Module :: module(), Args :: term(), Opts :: [start_opt()]) ->
+		   start_mon_ret().
+start_monitor(Module, Args, Opts) ->
+    gen:start(?MODULE, monitor, Module, Args, Opts).
+%%
+-spec start_monitor(
+	ServerName :: server_name(),
+	Module :: module(), Args :: term(), Opts :: [start_opt()]) ->
+		   start_mon_ret().
+start_monitor(ServerName, Module, Args, Opts) ->
+    gen:start(?MODULE, monitor, ServerName, Module, Args, Opts).
+
 %% Stop a state machine
 -spec stop(ServerRef :: server_ref()) -> ok.
 stop(ServerRef) ->
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index cfbaf8b242..504d663059 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -28,6 +28,7 @@
          spawn/3, spawn_link/3, spawn/4, spawn_link/4,
          spawn_opt/2, spawn_opt/3, spawn_opt/4, spawn_opt/5,
 	 start/3, start/4, start/5, start_link/3, start_link/4, start_link/5,
+         start_monitor/3, start_monitor/4, start_monitor/5,
 	 hibernate/3,
 	 init_ack/1, init_ack/2,
 	 init_p/3,init_p/5,format/1,format/2,format/3,report_cb/2,
@@ -39,25 +40,21 @@
 -export([wake_up/3]).
 
 -export_type([spawn_option/0]).
+-export_type([start_spawn_option/0]).
 
 -include("logger.hrl").
 
 %%-----------------------------------------------------------------------------
 
--type priority_level() :: 'high' | 'low' | 'max' | 'normal'.
--type max_heap_size()  :: non_neg_integer() |
-                          #{ size => non_neg_integer(),
-                             kill => true,
-                             error_logger => true}.
--type spawn_option()   :: 'link'
-                        | 'monitor'
-                        | {'priority', priority_level()}
-                        | {'max_heap_size', max_heap_size()}
-                        | {'min_heap_size', non_neg_integer()}
-                        | {'min_bin_vheap_size', non_neg_integer()}
-                        | {'fullsweep_after', non_neg_integer()}
-                        | {'message_queue_data',
-                             'off_heap' | 'on_heap' | 'mixed' }.
+-type start_spawn_option() :: 'link'
+                            | {'priority', erlang:priority_level()}
+                            | {'max_heap_size', erlang:max_heap_size()}
+                            | {'min_heap_size', non_neg_integer()}
+                            | {'min_bin_vheap_size', non_neg_integer()}
+                            | {'fullsweep_after', non_neg_integer()}
+                            | {'message_queue_data', erlang:message_queue_data() }.
+
+-type spawn_option()   :: erlang:spawn_opt_option().
 
 -type dict_or_pid()    :: pid()
                         | (ProcInfo :: [_])
@@ -65,6 +62,14 @@
 
 %%-----------------------------------------------------------------------------
 
+-define(VERIFY_NO_MONITOR_OPT(M, F, A, T, Opts),
+        case lists:member(monitor, Opts) of
+            true -> erlang:error(badarg, [M,F,A,T,Opts]);
+            false -> ok
+        end).
+
+%%-----------------------------------------------------------------------------
+
 -spec spawn(Fun) -> pid() when
       Fun :: function().
 
@@ -141,17 +146,16 @@ spawn_link(Node, M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
     Ancestors = get_ancestors(),
     erlang:spawn_link(Node, ?MODULE, init_p, [Parent,Ancestors,M,F,A]).
 
--spec spawn_opt(Fun, SpawnOpts) -> pid() when
+-spec spawn_opt(Fun, SpawnOpts) -> pid() | {pid(), reference()} when
       Fun :: function(),
       SpawnOpts :: [spawn_option()].
 
 spawn_opt(F, Opts) when is_function(F) ->
     Parent = get_my_name(),
     Ancestors = get_ancestors(),
-    check_for_monitor(Opts),
     erlang:spawn_opt(?MODULE, init_p, [Parent,Ancestors,F],Opts).
 
--spec spawn_opt(Node, Function, SpawnOpts) -> pid() when
+-spec spawn_opt(Node, Function, SpawnOpts) -> pid() | {pid(), reference()} when
       Node :: node(),
       Function :: function(),
       SpawnOpts :: [spawn_option()].
@@ -159,10 +163,9 @@ spawn_opt(F, Opts) when is_function(F) ->
 spawn_opt(Node, F, Opts) when is_function(F) ->
     Parent = get_my_name(),
     Ancestors = get_ancestors(),
-    check_for_monitor(Opts),
     erlang:spawn_opt(Node, ?MODULE, init_p, [Parent,Ancestors,F], Opts).
 
--spec spawn_opt(Module, Function, Args, SpawnOpts) -> pid() when
+-spec spawn_opt(Module, Function, Args, SpawnOpts) -> pid() | {pid(), reference()} when
       Module :: module(),
       Function :: atom(),
       Args :: [term()],
@@ -171,10 +174,9 @@ spawn_opt(Node, F, Opts) when is_function(F) ->
 spawn_opt(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
     Parent = get_my_name(),
     Ancestors = get_ancestors(),
-    check_for_monitor(Opts),
     erlang:spawn_opt(?MODULE, init_p, [Parent,Ancestors,M,F,A], Opts).
 
--spec spawn_opt(Node, Module, Function, Args, SpawnOpts) -> pid() when
+-spec spawn_opt(Node, Module, Function, Args, SpawnOpts) -> pid() | {pid(), reference()} when
       Node :: node(),
       Module :: module(),
       Function :: atom(),
@@ -184,30 +186,13 @@ spawn_opt(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
 spawn_opt(Node, M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
     Parent = get_my_name(),
     Ancestors = get_ancestors(),
-    check_for_monitor(Opts),
     erlang:spawn_opt(Node, ?MODULE, init_p, [Parent,Ancestors,M,F,A], Opts).
 
-%% OTP-6345
-%% monitor spawn_opt option is currently not possible to use
-check_for_monitor(SpawnOpts) ->
-    case lists:member(monitor, SpawnOpts) of
-	true ->
-	    erlang:error(badarg);
-	false ->
-	    false
-    end.
-
 spawn_mon(M,F,A) ->
     Parent = get_my_name(),
     Ancestors = get_ancestors(),
     erlang:spawn_monitor(?MODULE, init_p, [Parent,Ancestors,M,F,A]).
 
-spawn_opt_mon(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
-    Parent = get_my_name(),
-    Ancestors = get_ancestors(),
-    check_for_monitor(Opts),
-    erlang:spawn_opt(?MODULE, init_p, [Parent,Ancestors,M,F,A], [monitor|Opts]).
-
 -spec hibernate(Module, Function, Args) -> no_return() when
       Module :: module(),
       Function :: atom(),
@@ -216,14 +201,6 @@ spawn_opt_mon(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->
 hibernate(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
     erlang:hibernate(?MODULE, wake_up, [M, F, A]).
 
-ensure_link(SpawnOpts) ->
-    case lists:member(link, SpawnOpts) of
-	true -> 
-	    SpawnOpts;
-	false ->
-	    [link|SpawnOpts]
-    end.
-
 -spec init_p(pid(), [pid()], function()) -> term().
 
 init_p(Parent, Ancestors, Fun) when is_function(Fun) ->
@@ -299,20 +276,32 @@ start(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
       Ret :: term() | {error, Reason :: term()}.
 
 start(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) ->
-    PidRef = spawn_mon(M, F, A),
-    sync_wait_mon(PidRef, Timeout).
+    sync_start(spawn_mon(M, F, A), Timeout).
 
 -spec start(Module, Function, Args, Time, SpawnOpts) -> Ret when
       Module :: module(),
       Function :: atom(),
       Args :: [term()],
       Time :: timeout(),
-      SpawnOpts :: [spawn_option()],
+      SpawnOpts :: [start_spawn_option()],
       Ret :: term() | {error, Reason :: term()}.
 
 start(M, F, A, Timeout, SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->
-    PidRef = spawn_opt_mon(M, F, A, SpawnOpts),
-    sync_wait_mon(PidRef, Timeout).
+    ?VERIFY_NO_MONITOR_OPT(M, F, A, Timeout, SpawnOpts),
+    sync_start(?MODULE:spawn_opt(M, F, A, [monitor|SpawnOpts]), Timeout).
+
+sync_start({Pid, Ref}, Timeout) ->
+    receive
+	{ack, Pid, Return} ->
+	    erlang:demonitor(Ref, [flush]),
+            Return;
+	{'DOWN', Ref, process, Pid, Reason} ->
+            {error, Reason}
+    after Timeout ->
+	    erlang:demonitor(Ref, [flush]),
+            kill_flush(Pid),
+            {error, timeout}
+    end.
 
 -spec start_link(Module, Function, Args) -> Ret when
       Module :: module(),
@@ -331,60 +320,88 @@ start_link(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
       Ret :: term() | {error, Reason :: term()}.
 
 start_link(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) ->
-    Pid = ?MODULE:spawn_link(M, F, A),
-    sync_wait(Pid, Timeout).
+    sync_start_link(?MODULE:spawn_link(M, F, A), Timeout).
 
 -spec start_link(Module, Function, Args, Time, SpawnOpts) -> Ret when
       Module :: module(),
       Function :: atom(),
       Args :: [term()],
       Time :: timeout(),
-      SpawnOpts :: [spawn_option()],
+      SpawnOpts :: [start_spawn_option()],
       Ret :: term() | {error, Reason :: term()}.
 
 start_link(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->
-    Pid = ?MODULE:spawn_opt(M, F, A, ensure_link(SpawnOpts)),
-    sync_wait(Pid, Timeout).
+    ?VERIFY_NO_MONITOR_OPT(M, F, A, Timeout, SpawnOpts),
+    sync_start_link(?MODULE:spawn_opt(M, F, A, [link|SpawnOpts]), Timeout).
 
-sync_wait(Pid, Timeout) ->
+sync_start_link(Pid, Timeout) ->
     receive
 	{ack, Pid, Return} ->
-	    Return;
+            Return;
 	{'EXIT', Pid, Reason} ->
-	    {error, Reason}
+            {error, Reason}
     after Timeout ->
-	    unlink(Pid),
-	    exit(Pid, kill),
-	    flush(Pid),
-	    {error, timeout}
+            kill_flush(Pid),
+            {error, timeout}
     end.
 
-sync_wait_mon({Pid, Ref}, Timeout) ->
+-spec start_monitor(Module, Function, Args) -> {Ret, Mon} when
+      Module :: module(),
+      Function :: atom(),
+      Args :: [term()],
+      Mon :: reference(),
+      Ret :: term() | {error, Reason :: term()}.
+
+start_monitor(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
+    start_monitor(M, F, A, infinity).
+
+-spec start_monitor(Module, Function, Args, Time) -> {Ret, Mon} when
+      Module :: module(),
+      Function :: atom(),
+      Args :: [term()],
+      Time :: timeout(),
+      Mon :: reference(),
+      Ret :: term() | {error, Reason :: term()}.
+
+start_monitor(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) ->
+    sync_start_monitor(spawn_mon(M, F, A), Timeout).
+
+-spec start_monitor(Module, Function, Args, Time, SpawnOpts) -> {Ret, Mon} when
+      Module :: module(),
+      Function :: atom(),
+      Args :: [term()],
+      Time :: timeout(),
+      SpawnOpts :: [start_spawn_option()],
+      Mon :: reference(),
+      Ret :: term() | {error, Reason :: term()}.
+
+start_monitor(M,F,A,Timeout,SpawnOpts) when is_atom(M),
+                                            is_atom(F),
+                                            is_list(A) ->
+    ?VERIFY_NO_MONITOR_OPT(M, F, A, Timeout, SpawnOpts),
+    sync_start_monitor(?MODULE:spawn_opt(M, F, A, [monitor|SpawnOpts]),
+                       Timeout).
+
+sync_start_monitor({Pid, Ref}, Timeout) ->
     receive
 	{ack, Pid, Return} ->
-	    erlang:demonitor(Ref, [flush]),
-	    Return;
-	{'DOWN', Ref, _Type, Pid, Reason} ->
-	    {error, Reason};
-	{'EXIT', Pid, Reason} -> %% link as spawn_opt?
-	    erlang:demonitor(Ref, [flush]),
-	    {error, Reason}
+            {Return, Ref};
+	{'DOWN', Ref, process, Pid, Reason} = Down ->
+            self() ! Down,
+            {{error, Reason}, Ref}
     after Timeout ->
-	    erlang:demonitor(Ref, [flush]),
-	    exit(Pid, kill),
-	    flush(Pid),
-	    {error, timeout}
+            kill_flush(Pid),
+            {{error, timeout}, Ref}
     end.
 
--spec flush(pid()) -> 'true'.
+-spec kill_flush(Pid) -> 'ok' when
+      Pid :: pid().
 
-flush(Pid) ->
-    receive
-	{'EXIT', Pid, _} ->
-	    true
-    after 0 ->
-	    true
-    end.
+kill_flush(Pid) ->
+    unlink(Pid),
+    exit(Pid, kill),
+    receive {'EXIT', Pid, _} -> ok after 0 -> ok end,
+    ok.
 
 -spec init_ack(Parent, Ret) -> 'ok' when
       Parent :: pid(),
diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl
index 880b10117c..f77a45ccfd 100644
--- a/lib/stdlib/test/gen_event_SUITE.erl
+++ b/lib/stdlib/test/gen_event_SUITE.erl
@@ -112,6 +112,11 @@ start(Config) when is_list(Config) ->
     [] = gen_event:which_handlers(Pid1),
     ok = gen_event:stop(Pid1),
 
+    {ok, {Pid1b,Mon1b}} = gen_event:start_monitor(), %anonymous
+    [] = gen_event:which_handlers(Pid1b),
+    ok = gen_event:stop(Pid1b),
+    receive {'DOWN',Mon1b,process,Pid1b,_} -> ok end,
+
     {ok, Pid2} = gen_event:start(?LMGR),
     [] = gen_event:which_handlers(my_dummy_name),
     [] = gen_event:which_handlers(Pid2),
@@ -122,21 +127,45 @@ start(Config) when is_list(Config) ->
     [] = gen_event:which_handlers(Pid3),
     ok = gen_event:stop(my_dummy_name),
 
+    {ok, {Pid3b,Mon3b}} = gen_event:start_monitor(?LMGR),
+    [] = gen_event:which_handlers(my_dummy_name),
+    [] = gen_event:which_handlers(Pid3b),
+    ok = gen_event:stop(my_dummy_name),
+    receive {'DOWN',Mon3b,process,Pid3b,_} -> ok end,
+
     {ok, Pid4} = gen_event:start_link(?GMGR),
     [] = gen_event:which_handlers(?GMGR),
     [] = gen_event:which_handlers(Pid4),
     ok = gen_event:stop(?GMGR),
 
+    {ok, {Pid4b,Mon4b}} = gen_event:start_monitor(?GMGR),
+    [] = gen_event:which_handlers(?GMGR),
+    [] = gen_event:which_handlers(Pid4b),
+    ok = gen_event:stop(?GMGR),
+    receive {'DOWN',Mon4b,process,Pid4b,_} -> ok end,
+
     {ok, Pid5} = gen_event:start_link({via, dummy_via, my_dummy_name}),
     [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
     [] = gen_event:which_handlers(Pid5),
     ok = gen_event:stop({via, dummy_via, my_dummy_name}),
 
+    {ok, {Pid5b,Mon5b}} = gen_event:start_monitor({via, dummy_via, my_dummy_name}),
+    [] = gen_event:which_handlers({via, dummy_via, my_dummy_name}),
+    [] = gen_event:which_handlers(Pid5b),
+    ok = gen_event:stop({via, dummy_via, my_dummy_name}),
+    receive {'DOWN',Mon5b,process,Pid5b,_} -> ok end,
+
     {ok, _} = gen_event:start_link(?LMGR),
     {error, {already_started, _}} = gen_event:start_link(?LMGR),
     {error, {already_started, _}} = gen_event:start(?LMGR),
     ok = gen_event:stop(my_dummy_name),
 
+    {ok, {Pid5c,Mon5c}} = gen_event:start_monitor(?LMGR),
+    {error, {already_started, Pid5c}} = gen_event:start_monitor(?LMGR),
+    {error, {already_started, Pid5c}} = gen_event:start(?LMGR),
+    ok = gen_event:stop(my_dummy_name),
+    receive {'DOWN',Mon5c,process,Pid5c,_} -> ok end,
+
     {ok, Pid6} = gen_event:start_link(?GMGR),
     {error, {already_started, _}} = gen_event:start_link(?GMGR),
     {error, {already_started, _}} = gen_event:start(?GMGR),
@@ -148,6 +177,17 @@ start(Config) when is_list(Config) ->
 	    ct:fail(exit_gen_event)
     end,
 
+    {ok, {Pid6b,Mon6b}} = gen_event:start_monitor(?GMGR),
+    {error, {already_started, _}} = gen_event:start_monitor(?GMGR),
+    {error, {already_started, _}} = gen_event:start(?GMGR),
+
+    ok = gen_event:stop(?GMGR, shutdown, 10000),
+    receive
+	{'DOWN', Mon6b, process, Pid6b, shutdown} -> ok
+    after 10000 ->
+	    ct:fail(exit_gen_event)
+    end,
+
     {ok, Pid7} = gen_event:start_link({via, dummy_via, my_dummy_name}),
     {error, {already_started, _}} = gen_event:start_link({via, dummy_via, my_dummy_name}),
     {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}),
@@ -159,6 +199,17 @@ start(Config) when is_list(Config) ->
 	    ct:fail(exit_gen_event)
     end,
 
+    {ok, {Pid7b,Mon7b}} = gen_event:start_monitor({via, dummy_via, my_dummy_name}),
+    {error, {already_started, _}} = gen_event:start_monitor({via, dummy_via, my_dummy_name}),
+    {error, {already_started, _}} = gen_event:start({via, dummy_via, my_dummy_name}),
+
+    exit(Pid7b, shutdown),
+    receive
+	{'DOWN', Mon7b, process, Pid7b, shutdown} -> ok
+    after 10000 ->
+	    ct:fail(exit_gen_event)
+    end,
+
     process_flag(trap_exit, OldFl),
     ok.
 
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index e29195e895..9794b9ee8d 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -161,6 +161,18 @@ start(Config) when is_list(Config) ->
 	    ct:fail(not_stopped)
     end,
 
+    %% anonymous monitored
+    {ok, {Pid1b, Mon1b}} =
+	gen_server:start_monitor(gen_server_SUITE, [], []),
+    ok = gen_server:call(Pid1b, started_p),
+    ok = gen_server:call(Pid1b, stop),
+    receive
+	{'DOWN', Mon1b, process, Pid1b, stopped} ->
+	    ok
+    after 5000 ->
+	    ct:fail(not_stopped)
+    end,
+
     %% local register
     {ok, Pid2} =
 	gen_server:start({local, my_test_name},
@@ -191,6 +203,22 @@ start(Config) when is_list(Config) ->
 	    ct:fail(not_stopped)
     end,
 
+    %% local register monitored
+    {ok, {Pid3b, Mon3b}} =
+	gen_server:start_monitor({local, my_test_name},
+                                 gen_server_SUITE, [], []), 
+    ok = gen_server:call(my_test_name, started_p),
+    {error, {already_started, Pid3b}} =
+	gen_server:start_monitor({local, my_test_name},
+                                 gen_server_SUITE, [], []),
+    ok = gen_server:call(my_test_name, stop),
+    receive
+	{'DOWN', Mon3b, process, Pid3b, stopped} ->
+	    ok
+    after 5000 ->
+	    ct:fail(not_stopped)
+    end,
+
     %% global register
     {ok, Pid4} =
 	gen_server:start({global, my_test_name},
@@ -219,6 +247,22 @@ start(Config) when is_list(Config) ->
 	    ct:fail(not_stopped)
     end,
 
+    %% global register monitored
+    {ok, {Pid5b, Mon5b}} =
+	gen_server:start_monitor({global, my_test_name},
+                                 gen_server_SUITE, [], []), 
+    ok = gen_server:call({global, my_test_name}, started_p),
+    {error, {already_started, Pid5b}} =
+	gen_server:start_monitor({global, my_test_name},
+                                 gen_server_SUITE, [], []),
+    ok = gen_server:call({global, my_test_name}, stop),
+    receive
+	{'DOWN', Mon5b, process, Pid5b, stopped} ->
+	    ok
+    after 5000 ->
+	    ct:fail(not_stopped)
+    end,
+
     %% via register
     dummy_via:reset(),
     {ok, Pid6} =
diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl
index 053233df9b..3ef5c7f7b3 100644
--- a/lib/stdlib/test/gen_statem_SUITE.erl
+++ b/lib/stdlib/test/gen_statem_SUITE.erl
@@ -130,8 +130,18 @@ start1(Config) ->
 %%	?EXPECT_FAILURE(gen_statem:call(Pid0, hej), Reason),
 
     %%process_flag(trap_exit, OldFl),
-    ok = verify_empty_msgq().
+    ok = verify_empty_msgq(),
 
+    {ok,{Pid1,Mon1}} = gen_statem:start_monitor(?MODULE, start_arg(Config, []), []),
+    ok = do_func_test(Pid1),
+    ok = do_sync_func_test(Pid1),
+    stop_it(Pid1),
+    receive
+        {'DOWN', Mon1, process, Pid1, _Reason} ->
+            ok
+    end,
+    ok = verify_empty_msgq().
+    
 %% anonymous w. shutdown
 start2(Config) ->
     %% Dont link when shutdown
@@ -186,7 +196,7 @@ start6(Config) ->
 
     ok = verify_empty_msgq().
 
-%% global register linked
+%% global register linked & monitored
 start7(Config) ->
     STM = {global,my_stm},
 
@@ -196,6 +206,8 @@ start7(Config) ->
 	gen_statem:start_link(STM, ?MODULE, start_arg(Config, []), []),
     {error,{already_started,Pid}} =
 	gen_statem:start(STM, ?MODULE, start_arg(Config, []), []),
+    {error,{already_started,Pid}} =
+	gen_statem:start_monitor(STM, ?MODULE, start_arg(Config, []), []),
 
     ok = do_func_test(Pid),
     ok = do_sync_func_test(Pid),
@@ -203,6 +215,28 @@ start7(Config) ->
     ok = do_sync_func_test(STM),
     stop_it(STM),
 
+    ok = verify_empty_msgq(),
+
+    {ok,{Pid1,Mon1}} =
+	gen_statem:start_monitor(STM, ?MODULE, start_arg(Config, []), []),
+    {error,{already_started,Pid1}} =
+	gen_statem:start_link(STM, ?MODULE, start_arg(Config, []), []),
+    {error,{already_started,Pid1}} =
+	gen_statem:start(STM, ?MODULE, start_arg(Config, []), []),
+    {error,{already_started,Pid1}} =
+	gen_statem:start_monitor(STM, ?MODULE, start_arg(Config, []), []),
+
+    ok = do_func_test(Pid1),
+    ok = do_sync_func_test(Pid1),
+    ok = do_func_test(STM),
+    ok = do_sync_func_test(STM),
+    stop_it(STM),
+
+    receive
+        {'DOWN', Mon1, process, Pid1, _Reason} ->
+            ok
+    end,
+
     ok = verify_empty_msgq().
 
 
@@ -226,7 +260,7 @@ start8(Config) ->
     %%process_flag(trap_exit, OldFl),
     ok = verify_empty_msgq().
 
-%% local register linked
+%% local register linked & monitored
 start9(Config) ->
     %%OldFl = process_flag(trap_exit, true),
     Name = my_stm,
@@ -244,6 +278,24 @@ start9(Config) ->
     stop_it(Pid),
 
     %%process_flag(trap_exit, OldFl),
+    ok = verify_empty_msgq(),
+
+    {ok,{Pid1,Mon1}} =
+	gen_statem:start_monitor(STM, ?MODULE, start_arg(Config, []), []),
+    {error,{already_started,Pid1}} =
+	gen_statem:start_monitor(STM, ?MODULE, start_arg(Config, []), []),
+
+    ok = do_func_test(Pid1),
+    ok = do_sync_func_test(Pid1),
+    ok = do_func_test(Name),
+    ok = do_sync_func_test(Name),
+    stop_it(Pid1),
+
+    receive
+        {'DOWN', Mon1, process, Pid1, _Reason} ->
+            ok
+    end,
+
     ok = verify_empty_msgq().
 
 %% global register
diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl
index 127b1317e4..545ad63b9a 100644
--- a/lib/stdlib/test/proc_lib_SUITE.erl
+++ b/lib/stdlib/test/proc_lib_SUITE.erl
@@ -27,8 +27,12 @@
 -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
 	 init_per_group/2,end_per_group/2, 
 	 crash/1, stacktrace/1, sync_start_nolink/1, sync_start_link/1,
-         spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, '\x{447}'/0,
-	 hibernate/1, stop/1, t_format/1, t_format_arbitrary/1]).
+         sync_start_monitor/1, sync_start_monitor_link/1,
+         sync_start_timeout/1, sync_start_link_timeout/1,
+         sync_start_monitor_link_timeout/1,
+         spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, sp6/1, sp7/1,
+         sp8/1, sp9/1, sp10/1,
+         '\x{447}'/0, hibernate/1, stop/1, t_format/1, t_format_arbitrary/1]).
 -export([ otp_6345/1, init_dont_hang/1]).
 
 -export([hib_loop/1, awaken/1]).
@@ -55,7 +59,10 @@ all() ->
 
 groups() -> 
     [{tickets, [], [otp_6345, init_dont_hang]},
-     {sync_start, [], [sync_start_nolink, sync_start_link]}].
+     {sync_start, [], [sync_start_nolink, sync_start_link,
+                       sync_start_monitor, sync_start_monitor_link,
+                       sync_start_timeout, sync_start_link_timeout,
+                       sync_start_monitor_link_timeout]}].
 
 init_per_suite(Config) ->
     Config.
@@ -275,6 +282,84 @@ sync_start_link(Config) when is_list(Config) ->
     end,
     ok.
 
+sync_start_monitor(Config) when is_list(Config) ->
+    _Pid = spawn_link(?MODULE, sp6, [self()]),
+    receive
+	{sync_started, _} -> ct:fail(async_start)
+    after 1000 -> ok
+    end,
+    receive
+	{Pid2, init} ->
+	    Pid2 ! go_on
+    end,
+    receive
+	{sync_started, _} -> ok
+    after 1000 -> ct:fail(no_sync_start)
+    end,
+    receive received_down -> ok
+    after 2000 -> ct:fail(no_down)
+    end,
+    ok.
+
+sync_start_monitor_link(Config) when is_list(Config) ->
+    _Pid = spawn_link(?MODULE, sp7, [self()]),
+    receive
+	{sync_started, _} -> ct:fail(async_start)
+    after 1000 -> ok
+    end,
+    receive
+	{Pid2, init} ->
+	    Pid2 ! go_on
+    end,
+    receive
+	{sync_started, _} -> ok
+    after 1000 -> ct:fail(no_sync_start)
+    end,
+    receive received_down -> ok
+    after 1000 -> ct:fail(no_down)
+    end,
+    receive received_exit -> ok
+    after 1000 -> ct:fail(no_exit)
+    end,
+    ok.
+
+sync_start_timeout(Config) when is_list(Config) ->
+    _Pid = spawn_link(?MODULE, sp8, [self()]),
+    receive done -> ok end,
+    receive {received_exit, _} = M1 -> ct:fail(M1)
+    after 0 -> ok
+    end,
+    receive {received_down, _} = M2 -> ct:fail(M2)
+    after 0 -> ok
+    end,
+    ok.
+
+sync_start_link_timeout(Config) when is_list(Config) ->
+    _Pid = spawn_link(?MODULE, sp9, [self()]),
+    receive done -> ok end,
+    receive {received_exit, _} = M1 -> ct:fail(M1)
+    after 0 -> ok
+    end,
+    receive {received_down, _} = M2 -> ct:fail(M2)
+    after 0 -> ok
+    end,
+    ok.
+    
+sync_start_monitor_link_timeout(Config) when is_list(Config) ->
+    _Pid = spawn_link(?MODULE, sp10, [self()]),
+    receive done -> ok end,
+    receive {received_exit, _} = M1 -> ct:fail(M1)
+    after 0 -> ok
+    end,
+    receive
+        {received_down, R} ->
+            killed = R,
+            ok
+    after 0 -> ct:fail(no_down)
+    end,
+    ok.
+    
+
 spawn_opt(Config) when is_list(Config) ->
     F = fun sp1/0,
     {name,Fname} = erlang:fun_info(F, name),
@@ -313,6 +398,89 @@ sp5(Tester) ->
     Pid = proc_lib:start(?MODULE, sp4, [self(), Tester]),
     Tester ! {sync_started, Pid}.
 
+sp6(Tester) ->
+    process_flag(trap_exit, true),
+    {Pid, Mon} = proc_lib:start_monitor(?MODULE, sp4, [self(), Tester]),
+    Tester ! {sync_started, Pid},
+    receive
+        {'EXIT', Pid, normal} ->
+            exit(received_exit)
+    after 1000 ->
+            ok
+    end,
+    receive
+        {'DOWN', Mon, process, Pid, normal} ->
+            Tester ! received_down
+    end.
+
+sp7(Tester) ->
+    process_flag(trap_exit, true),
+    {Pid, Mon} = proc_lib:start_monitor(?MODULE, sp4, [self(), Tester], infinity, [link]),
+    Tester ! {sync_started, Pid},
+    receive
+        {'EXIT', Pid, normal} ->
+            Tester ! received_exit
+    end,
+    receive
+        {'DOWN', Mon, process, Pid, normal} ->
+            Tester ! received_down
+    end.
+
+sp8(Tester) ->
+    process_flag(trap_exit, true),
+    {error,timeout} = proc_lib:start(?MODULE, sp4, [self(), Tester], 500, [link]),
+    receive after 500 -> ok end,
+    receive
+        {'EXIT', _Pid1, Reason1} ->
+            Tester ! {received_exit, Reason1}
+    after 0 ->
+            ok
+    end,
+    receive
+        {'DOWN', _Mon2, process, _Pid2, Reason2} ->
+            Tester ! {received_down, Reason2}
+    after 0 ->
+            ok
+    end,
+    Tester ! done.
+
+sp9(Tester) ->
+    process_flag(trap_exit, true),
+    {error,timeout} = proc_lib:start_link(?MODULE, sp4, [self(), Tester], 500),
+    receive after 500 -> ok end,
+    receive
+        {'EXIT', _Pid1, Reason1} ->
+            Tester ! {received_exit, Reason1}
+    after 0 ->
+            ok
+    end,
+    receive
+        {'DOWN', _Mon, process, _Pid2, Reason2} ->
+            Tester ! {received_down, Reason2}
+    after 0 ->
+            ok
+    end,
+    Tester ! done.
+    
+
+sp10(Tester) ->
+    process_flag(trap_exit, true),
+    {{error,timeout}, Mon} = proc_lib:start_monitor(?MODULE, sp4, [self(), Tester], 500, [link]),
+    receive after 500 -> ok end,
+    receive
+        {'EXIT', _Pid1, Reason1} ->
+            Tester ! {received_exit, Reason1}
+    after 0 ->
+            ok
+    end,
+    receive
+        {'DOWN', Mon, process, _Pid2, Reason2} ->
+            Tester ! {received_down, Reason2}
+    after 0 ->
+            ok
+    end,
+    Tester ! done.
+
 sp4(Parent, Tester) ->
     Tester ! {self(), init},
     receive
@@ -421,10 +589,12 @@ hib_receive_messages(N) ->
 %% 'monitor' spawn_opt option.
 otp_6345(Config) when is_list(Config) ->
     Opts = [link,monitor],
-    {'EXIT', {badarg,[{proc_lib,check_for_monitor,_,_}|_Stack]}} =
-	(catch proc_lib:start(?MODULE, otp_6345_init, [self()],
-			      1000, Opts)),
-    ok.
+    try
+        blupp = proc_lib:start(?MODULE, otp_6345_init, [self()],
+                               1000, Opts)
+    catch
+        error:badarg -> ok
+    end.
 
 otp_6345_init(Parent) ->
     proc_lib:init_ack(Parent, {ok, self()}),
-- 
2.16.4

openSUSE Build Service is sponsored by