From: ara.t.howard@... Date: 2007-03-06T03:18:32+09:00 Subject: Re: Thead.parent, revisited. Or: Building a call stack. On Tue, 6 Mar 2007, Erik Veenstra wrote: > 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?... :} class Thread class << self alias_method "__new__", "new" def new *a, &b child '__new__', *a, &b end alias_method "__start__", "start" def start *a, &b child '__start__', *a, &b end private def child as, *a, &b parent = Thread.current send(as, *a) do |*a| Thread.current.parent = parent b.call *a end end end def parent self['parent'] end def parent= parent self['parent'] = parent end def ancestors return self['ancestors'] if self['ancestors'] list = [t = self] while((t = t.parent)) list << t end self['ancestors'] = list end end -a -- be kind whenever possible... it is always possible. - the dalai lama