From 3738103d0b1195e570a7525c4370cd490a5368aa Mon Sep 17 00:00:00 2001
From: Lukas Larsson <lukas.larsson@erlang-solutions.com>
Date: Mon, 29 Feb 2016 15:09:26 +0100
Subject: erts: Add 'spawned' trace event to 'procs' trace flag

OTP-13497

This trace event is triggered when a process is created from the
process that is created.
---
 erts/doc/src/erlang.xml            | 11 +++++++++++
 erts/emulator/beam/atom.names      |  1 +
 erts/emulator/beam/erl_process.c   | 13 ++++++++++++-
 erts/emulator/beam/erl_trace.c     |  6 +++---
 erts/emulator/beam/erl_trace.h     |  2 +-
 erts/emulator/test/trace_SUITE.erl |  5 ++++-
 erts/preloaded/src/erl_tracer.erl  |  2 +-
 7 files changed, 33 insertions(+), 7 deletions(-)

(limited to 'erts')

diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index abc0d56983..d6fe585c8d 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -8464,6 +8464,7 @@ timestamp() ->
           <item>
             <p>Traces process-related events.</p>
             <p>Message tags: <c><seealso marker="#trace_3_trace_messages_spawn">spawn</seealso></c>,
+            <c><seealso marker="#trace_3_trace_messages_spawned">spawned</seealso></c>,
             <c><seealso marker="#trace_3_trace_messages_exit">exit</seealso></c>,
             <c><seealso marker="#trace_3_trace_messages_register">register</seealso></c>,
             <c><seealso marker="#trace_3_trace_messages_unregister">unregister</seealso></c>,
@@ -8704,6 +8705,16 @@ timestamp() ->
             <p><c>Args</c> is supposed to be the argument list,
               but can be any term if the spawn is erroneous.</p>
           </item>
+          <tag>
+            <marker id="trace_3_trace_messages_spawned"></marker>
+            <c>{trace, Pid, spawned, Pid2, {M, F, Args}}</c>
+          </tag>
+          <item>
+            <p>When <c>Pid</c> is spawned by process <c>Pid2</c> with
+              the specified function call as entry point.</p>
+            <p><c>Args</c> is supposed to be the argument list,
+              but can be any term if the spawn is erroneous.</p>
+          </item>
           <tag>
             <marker id="trace_3_trace_messages_exit"></marker>
             <c>{trace, Pid, exit, Reason}</c>
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index bd1005867c..8c51f788c0 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -571,6 +571,7 @@ atom size
 atom sl_alloc
 atom spawn_executable
 atom spawn_driver
+atom spawned
 atom ssl_tls
 atom stack_size
 atom start
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 1398bc9c61..a520005c35 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -11176,12 +11176,23 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
             locks &= ~(ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
             erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
             erts_smp_proc_unlock(parent, ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
-            trace_proc_spawn(parent, p->common.id, mod, func, args);
+            trace_proc_spawn(parent, am_spawn, p->common.id, mod, func, args);
             if (so->flags & SPO_LINK)
                 trace_proc(parent, locks, parent, am_link, p->common.id);
         }
     }
 
+    if (IS_TRACED_FL(p, F_TRACE_PROCS)) {
+        if (locks & (ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE)) {
+            locks &= ~(ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
+            erts_smp_proc_unlock(p, locks & (ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE));
+            erts_smp_proc_unlock(parent, locks & (ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE));
+        }
+        trace_proc_spawn(p, am_spawned, parent->common.id, mod, func, args);
+        if (so->flags & SPO_LINK)
+            trace_proc(p, locks, p, am_getting_linked, parent->common.id);
+    }
+
     /*
      * Check if this process should be initially linked to its parent.
      */
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 5ba58e9350..3027e34968 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -1249,20 +1249,20 @@ trace_proc(Process *c_p, ErtsProcLocks c_p_locks,
  * and 'args' may be a deep term.
  */
 void
-trace_proc_spawn(Process *p, Eterm pid,
+trace_proc_spawn(Process *p, Eterm what, Eterm pid,
 		 Eterm mod, Eterm func, Eterm args)
 {
     ErtsTracerNif *tnif = NULL;
     if (is_tracer_proc_enabled(p, ERTS_PROC_LOCKS_ALL &
                                ~(ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE),
-                               &p->common, &tnif, am_spawn)) {
+                               &p->common, &tnif, what)) {
         Eterm mfa;
         Eterm* hp;
 
         hp = HAlloc(p, 4);
         mfa = TUPLE3(hp, mod, func, args);
         hp += 4;
-        send_to_tracer_nif(p, &p->common, p->common.id, tnif, am_spawn, pid, mfa);
+        send_to_tracer_nif(p, &p->common, p->common.id, tnif, what, pid, mfa);
     }
 }
 
diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h
index 0fefd6f70d..14d0c36016 100644
--- a/erts/emulator/beam/erl_trace.h
+++ b/erts/emulator/beam/erl_trace.h
@@ -100,7 +100,7 @@ void erts_trace_exception(Process* p, BeamInstr mfa[], Eterm class, Eterm value,
 void erts_trace_return_to(Process *p, BeamInstr *pc);
 void trace_sched(Process*, ErtsProcLocks, Eterm);
 void trace_proc(Process*, ErtsProcLocks, Process*, Eterm, Eterm);
-void trace_proc_spawn(Process*, Eterm pid, Eterm mod, Eterm func, Eterm args);
+void trace_proc_spawn(Process*, Eterm what, Eterm pid, Eterm mod, Eterm func, Eterm args);
 void save_calls(Process *p, Export *);
 void trace_gc(Process *p, Eterm what);
 /* port tracing */
diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl
index d9974bd6f7..b7f312635e 100644
--- a/erts/emulator/test/trace_SUITE.erl
+++ b/erts/emulator/test/trace_SUITE.erl
@@ -312,12 +312,14 @@ procs_trace(Config) when is_list(Config) ->
     Proc2 = spawn(?MODULE, process, [Self]),
     io:format("Proc2 = ~p ~n", [Proc2]),
     %%
-    1 = erlang:trace(Proc1, true, [procs]),
+    1 = erlang:trace(Proc1, true, [procs, set_on_first_spawn]),
     MFA = {?MODULE, process, [Self]},
     %%
     %% spawn, link
     Proc1 ! {spawn_link_please, Self, MFA},
     Proc3 = receive {spawned, Proc1, P3} -> P3 end,
+    receive {trace, Proc3, spawned, Proc1, MFA} -> ok end,
+    receive {trace, Proc3, getting_linked, Proc1} -> ok end,
     {trace, Proc1, spawn, Proc3, MFA} = receive_first_trace(),
     io:format("Proc3 = ~p ~n", [Proc3]),
     {trace, Proc1, link, Proc3} = receive_first_trace(),
@@ -328,6 +330,7 @@ procs_trace(Config) when is_list(Config) ->
     Reason3 = make_ref(),
     Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
     receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
+    receive {trace, Proc3, exit, Reason3} -> ok end,
     {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(),
     Proc1 ! {trap_exit_please, false},
     receive_nothing(),
diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl
index a8da2b4c14..2177e48f60 100644
--- a/erts/preloaded/src/erl_tracer.erl
+++ b/erts/preloaded/src/erl_tracer.erl
@@ -5,7 +5,7 @@
 -type tracee() :: port() | pid() | undefined.
 -type trace_tag() :: send | send_to_non_existing_process | 'receive' |
                      call | return_to | return_from | exception_from |
-                     spawn | exit | link | unlink | getting_linked |
+                     spawn | spawned | exit | link | unlink | getting_linked |
                      getting_unlinked | register | unregister | in | out |
                      in_exiting | out_exiting | out_exited |
                      open | closed | gc_start | gc_end.
-- 
cgit v1.2.3