Thead.parent, revisited. Or: Building a call stack.

E

Erik Veenstra

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/
 
A

ara.t.howard

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
 
A

ara.t.howard

Yep, I know. That's a "work around". But, as we've discussed
before [1], it's not water tight.

"Thread#start doesn't reuse Thread.new. Neither does
rb_thread_create(), which is used in e.g. TK."

oh right. forgot.

check out ThreadGroup - i think it's properties may allow someone to hack what
you're after. just looking at that today - but out of time now...

-a
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top