Re: "previous frame inner to this frame" error when unwinding fibers

Tom Tromey <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>
Tom> Yeah, the API on the branch is very simple.

I made a new branch and reworked it a bit, dropping a few stale parts.
It's in my github as "green-threads-v2"; you can try it if you want.

I've appended a sample .py that works with the "vireo" user-space
threads package so you can see how it works.

I still haven't implemented a way for green threads to know when to stop
unwinding.  And, I haven't added a way to indicate that the "inner than"
requirement should be lifted.

If you have ideas for how those ought to work, that would be good to
hear.  We talked about doing this in an unwinder but it seems kind of
heavy to require an unwinder to supplement green threads; though maybe
in your case that's ok.

One thought I had was to have a callback on the green thread object that
could be passed a frame to see if it is the outermost frame.  This way
green threads, at least, could stop unwinding at their scheduler; and
users wanting to debug a scheduler could switch to a "real" thread to
see that.

Maybe inner-than could just be an optional flag passed to
create_green_thread.

Tom


import gdb

thread_map = {}

main_thread = None

# From glibc/sysdeps/unix/sysv/linux/x86/sys/ucontext.h
x8664_regs = [ 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14',
               'r15', 'rdi', 'rsi', 'rbp', 'rbx', 'rdx', 'rax',
               'rcx', 'rsp', 'rip', 'efl', 'csgsfs', 'err',
               'trapno', 'oldmask', 'cr2' ]

def vireo_current():
    return int(gdb.parse_and_eval('curenv')) + 1

class VireoGreenThread:
    def __init__(self, tid):
        self.tid = tid

    def _get_state(self):
        return gdb.parse_and_eval('envs')[self.tid]['state']

    def fetch(self, reg):
        """Fetch REG from memory."""
        global x8664_regs
        global thread_map
        thread = thread[self.tid]
        state = self._get_state()
        gregs = state['uc_mcontext']['gregs']
        for i in range(0, len(x8664_regs)):
            if reg is None or reg == x8664_regs[i]:
                thread.write_register(x8664_regs[i], gregs[i])

    def store(self, reg):
        global x8664_regs
        global thread_map
        thread = thread[self.tid]
        state = self._get_state()
        gregs = state['uc_mcontext']['gregs']
        for i in range(0, len(x8664_regs)):
            if reg is None or reg == x8664_regs[i]:
                gregs[i] = thread.read_register(x8664_regs[i])

    def name(self):
        return "Vireo Thread " + str(self.tid)

    def underlying_thread(self):
        if vireo_current() == self.tid:
            global main_thread
            return main_thread
        return None

class VFinish(gdb.FinishBreakpoint):
    def stop(self):
        tid = int(self.return_value) + 1
        global thread_map
        thread_map[tid] = gdb.create_green_thread(tid, VireoGreenThread(tid))
        return False

class VCreate(gdb.Breakpoint):
    def stop(self):
        VFinish(gdb.newest_frame(), True)
        return False

class VExit(gdb.Breakpoint):
    def stop(self):
        global main_thread
        if main_thread is None:
            main_thread = gdb.selected_thread()
        global thread_map
        tid = vireo_current()
        if tid in thread_map:
            thread_map[tid].set_exited()
            del thread_map[tid]

VCreate('vireo_create', internal=True)
VExit('vireo_exit', internal=True)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.