<div dir="ltr"><div><br><br>On Mon, Sep 30, 2019 at 1:57 PM Duncan Paul Attard <<a href="mailto:duncan.attard.01@um.edu.mt">duncan.attard.01@um.edu.mt</a>> wrote:<br>><br>> I am tracing an Erlang process, say, `P` by invoking the BIF `erlang:trace(Pid_P, true, [set_on_spawn, procs, send, 'receive'])` from some process. As per the Erlang docs, the latter process becomes the tracer for `P`, which I shall call `Trc_Q`.<br>><br>> Suppose now, that process `P` spawns a new process `Q`. Since the flag `set_on_spawn` was specified in the call to `erlang:trace/3` above, `Q` will automatically be traced by `Trc_P` as well.<br>><br>> ---<br>><br>> I want to spawn a **new** tracer, `Trc_Q`, and transfer the ownership of tracing `Q` to it, so that the resulting configuration will be that of process `P` being traced by tracer `Trc_P`, `Q` by `Trc_Q`.<br>><br><br></div>Unfortunately I do not have any ideas on how to accomplish this.<br><div><br>> However, Erlang permits **at most** one tracer per process, so I cannot achieve said configuration by invoking `erlang:trace(Pid_Q, true, ..)` from `Trc_Q`. The only way possible is to do it in two steps:<br>><br>> 1. Tracer `Trc_Q` calls `erlang:trace(Pid_Q, false, ..)` to stop `Trc_P` from tracing `Q`;<br>> 2. `Trc_Q` calls `erlang:trace(Pid_Q, true, ..)` again to start tracing `Q`.<br>><br>> In the time span between steps **1.** and **2.** above, it might be possible that trace events by process `Q` are **lost** because at that moment, there is no tracer attached. One way of mitigating this is to perform the following:<br>><br>> 1. Suspend process `Q` by calling `erlang:suspend_process(Pid_Q)` from `Trc_Q` (note that as per Erlang docs, `Trc_Q` remains blocked until `Q` is eventually suspended by the VM);<br>> 2. `Trc_Q` calls `erlang:trace(Pid_Q, false, ..)` to stop `Trc_P` from tracing `Q`;<br>> 3. `Trc_Q` calls `erlang:trace(Pid_Q, true, ..)` again to start tracing `Q`;<br>> 4. Finally, `Trc_Q` calls `erlang:resume_process(Pid_Q)` so that `Q` can continue executing.<br>><br>> From what I was able to find out, while `Q` is suspended, messages sent to it are queued, and when resumed, `Trc_Q` receives the `{trace, Pid_Q, receive, Msg}` trace events accordingly without any loss.<br>><br><br>This is not a feature, it is a bug (introduced in erts 10.0, OTP 21.0) that will be fixed. The trace message should have been delivered even though the receiver was suspended.<br><br>You cannot even rely on this behavior while this bug is present. If you (or any process in the system) send the suspended process a non-message signal (monitor, demonitor, link, unlink, exit, process_info, ...), the bug will be bypassed and the trace message will be delivered.<br><br>> However, I am hesitant to use suspend/resume, since the Erlang docs explicitly say that these are to be used for *debugging purposes only*.<br><br>Mission accomplished! :-)<br><br>> Any idea as to why this is the case?<br>><br><br>The language was designed with other communication primitives intended for use. Suspend/Resume was explicitly introduced for debugging purposes only, and not for usage by ordinary Erlang programs. They will most likely not disappear, but debug functionality in general are not treated as carefully by us at OTP as other ordinary functionality with regards to compatibility, etc. We for example removed the automatic deadlock prevention in suspend_process() that existed prior to erts 10.0 due to performance reasons.<br><br>Regards,<br>Rickard<br>--<br>Rickard Green, Erlang/OTP, Ericsson AB</div></div>