In order to build a diagram of all method calls in an
application, I created a set_trace_func function. This function
builds a call stack. Each thread in each process should have
its own call stack, initialized to the call stack of the parent
process or the parent thread.
The call stacks are stored in the array stack_per_thread. The
initial call stack is an empty array:
stack_per_thread = []
stack_per_thread[[Process.pid, Thread.current]] = []
Creating a new call stack after a fork (both process fork and
thread fork) is done like this:
stack = (stack_per_thread[[Process.pid, Thread.current]] ||=
stack.dup)
Process forks are not a problem, since the last call stack
before the process fork is the one with which the child process
has to continue and does continue.
However, threads are a bit of a problem. Threads don’t have a
parent, which means that it’s not possible to clone the call
stack of the parent thread. I currently fake the concept
“parent thread” by assuming that the last running thread is the
parent thread.
If Parent.thread existed, everything would be perfectly fine:
stack = (stack_per_thread[[Process.pid, Thread.current]] ||=
stack_per_thread[[Process.pid, Thread.parent]].dup)
I observed a couple of traces and noticed, empirically, that a
new thread always gets a couple of CPU cycles (and hence calls
to set_trace_func). If this is always true, my assumption (“the
last thread is the parent thread”) is no problem. If the parent
process can spawn many threads before any of them gets some CPU
cycles, well, then we do have a problem… :{
Ideas? Related work? Anybody able to understand the C code?
Matz?.. :}
gegroet,
Erik V. - http://www.erikveen.dds.nl/