From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18583 invoked by alias); 13 Jul 2010 17:57:57 -0000 Mailing-List: contact archer-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: List-Id: Received: (qmail 18568 invoked by uid 22791); 13 Jul 2010 17:57:53 -0000 X-SWARE-Spam-Status: No, hits=-6.0 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org From: Tom Tromey To: Project Archer Subject: "info mutex" Date: Tue, 13 Jul 2010 17:57:00 -0000 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-SW-Source: 2010-q3/txt/msg00024.txt.bz2 I saw a request for something like this from a user, and so I took a stab at implementing it yesterday. This adds a new "info mutex" command that shows the current threads grouped by mutex. In particular it tries to show what threads are blocking on a mutex, and what thread owns that mutex. As is, it only works for pthread mutexes, and you need the glibc debuginfo installed. Also the output is not as pretty as "info thread": (gdb) info mutex Threads not waiting for a lock: Thread 18453 Mutex 0x8049874: Owned by thread 18453 * Thread 18456 A couple Python API notes arising from this work: * It would be nice to have a way to print a thread the way the GDB core does it. Say, some extended to_string method on gdb.Thread. * Probably ThreadHolder should be in our library. * For things like the mutex specifics, it would be nice if libraries could add their own information when the library-related .py code is loaded. Maybe we need some generic mechanism for this, since I think we already also want this for frame filters. I don't think this code is fully baked enough to check in, but I wanted to post it in case other people are interested. Tom import gdb class ThreadHolder: """A class that can be used with the 'with' statement to save and restore the current thread while operating on some other thread.""" def __init__(self, thread): self.thread = thread def __enter__(self): self.save = gdb.selected_thread() self.thread.switch() def __exit__ (self, exc_type, exc_value, traceback): try: self.save.switch() except: pass return None def print_thread (thr, owner): "A helper function to nicely print a gdb.Thread." if thr == selected_thread: print "* ", else: print " ", if owner: print "Owned by thread", else: print "Thread", (pid, lwp, tid) = thr.ptid print "%d " % lwp # FIXME - function, file name, etc class InfoMutex(gdb.Command): def __init__ (self): gdb.Command.__init__ (self, "info mutex", gdb.COMMAND_NONE) def invoke (self, arg, from_tty): # Map a mutex ID to the LWP owning the mutex. owner = {} # Map an LWP id to a thread object. threads = {} # Map a mutex ID to a list of thread objects that are waiting # for the lock. mutexes = {} for inf in gdb.inferiors(): for thr in inf.threads(): id = thr.ptid[1] threads[id] = thr with ThreadHolder (thr): frame = gdb.selected_frame() lock_name = None for n in range(5): if frame is None: break fn_sym = frame.function() if fn_sym is not None and (fn_sym.name == '__pthread_mutex_lock' or fn_sym.name == '__pthread_mutex_lock_full' or fn_sym.name == 'pthread_mutex_timedlock'): m = frame.read_var ('mutex') lock_name = long (m) if lock_name not in owner: owner[lock_name] = long (m['__data']['__owner']) break frame = frame.older() if lock_name not in mutexes: mutexes[lock_name] = [] mutexes[lock_name] += [thr] selected_thread = gdb.selected_thread() for id in mutexes.keys(): if id is None: print "Threads not waiting for a lock:" else: print "Mutex 0x%x:" % id print_thread (threads[owner[id]], True) for thr in mutexes[id]: print_thread (thr, False) print InfoMutex()