Add a debug thread that dumps tracebacks.

Start and extra thread that blocks on a threading event until SIGUSR1 is
received. Then dump the tracebacks for all threads except itself. This
is only really useful as a debug tool for deadlocks, so we might want to
hide it behind a flag?
This commit is contained in:
Thomas Adamcik 2012-09-09 22:48:08 +02:00
parent db3a201795
commit 88f0ffb9f2
2 changed files with 35 additions and 3 deletions

View File

@ -36,7 +36,7 @@ from mopidy.utils.deps import list_deps_optparse_callback
from mopidy.utils.log import setup_logging
from mopidy.utils.path import get_or_create_folder, get_or_create_file
from mopidy.utils.process import (exit_handler, stop_remaining_actors,
stop_actors_by_class)
stop_actors_by_class, DebugThread)
from mopidy.utils.settings import list_settings_optparse_callback
@ -44,7 +44,12 @@ logger = logging.getLogger('mopidy.main')
def main():
debug_thread = DebugThread()
debug_thread.start()
signal.signal(signal.SIGUSR1, debug_thread.handler)
signal.signal(signal.SIGTERM, exit_handler)
loop = gobject.MainLoop()
try:
options = parse_options()

View File

@ -1,7 +1,9 @@
import logging
import signal
import sys
import thread
import threading
import traceback
from pykka import ActorDeadError
from pykka.registry import ActorRegistry
@ -10,6 +12,9 @@ from mopidy import SettingsError
logger = logging.getLogger('mopidy.utils.process')
signals = dict((k, v) for v, k in signal.__dict__.iteritems()
if v.startswith('SIG') and not v.startswith('SIG_'))
def exit_process():
logger.debug(u'Interrupting main...')
thread.interrupt_main()
@ -17,8 +22,6 @@ def exit_process():
def exit_handler(signum, frame):
"""A :mod:`signal` handler which will exit the program on signal."""
signals = dict((k, v) for v, k in signal.__dict__.iteritems()
if v.startswith('SIG') and not v.startswith('SIG_'))
logger.info(u'Got %s signal', signals[signum])
exit_process()
@ -65,3 +68,27 @@ class BaseThread(threading.Thread):
def run_inside_try(self):
raise NotImplementedError
class DebugThread(threading.Thread):
daemon = True
name = 'DebugThread'
event = threading.Event()
def handler(self, signum, frame):
logger.info(u'Got %s signal', signals[signum])
self.event.set()
def run(self):
while True:
self.event.wait()
threads = dict((t.ident, t.name) for t in threading.enumerate())
for ident, frame in sys._current_frames().items():
if self.ident == ident:
continue
print "## Thread: %s (%s) ##" % (threads[ident], ident)
print ''.join(traceback.format_stack(frame))
self.event.clear()