Implement stack trace dump for all running threads on SIGQUIT

This is handy when we're debugging the thread locks: we can try to
understand which thread does what and how it was called.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
This commit is contained in:
Eygene Ryabinkin 2013-01-28 22:49:29 +04:00
parent 83e8fca2e0
commit de84c3941c
4 changed files with 36 additions and 2 deletions

View File

@ -7,7 +7,8 @@ ChangeLog
WIP (add new stuff for the next release) WIP (add new stuff for the next release)
======================================== ========================================
======= * Dump stacktrace for all threads on SIGQUIT: ease debugging
of threading and other issues
* SIGHUP is now handled as the termination notification rather than * SIGHUP is now handled as the termination notification rather than
the signal to reread the configuration (Dmitrijs Ledkovs) the signal to reread the configuration (Dmitrijs Ledkovs)
* Honor the timezone of emails (Tobias Thierer) * Honor the timezone of emails (Tobias Thierer)

View File

@ -309,7 +309,7 @@ UNIX Signals
============ ============
OfflineImap listens to the unix signals SIGUSR1, SIGUSR2, SIGTERM, OfflineImap listens to the unix signals SIGUSR1, SIGUSR2, SIGTERM,
SIGINT, SIGHUP: SIGINT, SIGHUP, SIGQUIT:
If sent a SIGUSR1 it will abort any current (or next future) sleep of all If sent a SIGUSR1 it will abort any current (or next future) sleep of all
accounts that are configured to "autorefresh". In effect, this will trigger a accounts that are configured to "autorefresh". In effect, this will trigger a
@ -326,6 +326,9 @@ in each account, close keep alive connections, remove locks on the
accounts and exit. It may take up to 10 seconds, if autorefresh option accounts and exit. It may take up to 10 seconds, if autorefresh option
is used. is used.
SIGQUIT dumps stack traces for all threads and tries to dump process
core.
Folder filtering and nametrans Folder filtering and nametrans
============================== ==============================

View File

@ -28,6 +28,7 @@ from offlineimap import accounts, threadutil, syncmaster
from offlineimap.error import OfflineImapError from offlineimap.error import OfflineImapError
from offlineimap.ui import UI_LIST, setglobalui, getglobalui from offlineimap.ui import UI_LIST, setglobalui, getglobalui
from offlineimap.CustomConfig import CustomConfigParser from offlineimap.CustomConfig import CustomConfigParser
from offlineimap.utils import stacktrace
class OfflineImap: class OfflineImap:
@ -341,12 +342,16 @@ class OfflineImap:
getglobalui().warn("Terminating NOW (this may "\ getglobalui().warn("Terminating NOW (this may "\
"take a few seconds)...") "take a few seconds)...")
accounts.Account.set_abort_event(self.config, 3) accounts.Account.set_abort_event(self.config, 3)
elif sig == signal.SIGQUIT:
stacktrace.dump (sys.stderr)
os.abort()
signal.signal(signal.SIGHUP,sig_handler) signal.signal(signal.SIGHUP,sig_handler)
signal.signal(signal.SIGUSR1,sig_handler) signal.signal(signal.SIGUSR1,sig_handler)
signal.signal(signal.SIGUSR2,sig_handler) signal.signal(signal.SIGUSR2,sig_handler)
signal.signal(signal.SIGTERM, sig_handler) signal.signal(signal.SIGTERM, sig_handler)
signal.signal(signal.SIGINT, sig_handler) signal.signal(signal.SIGINT, sig_handler)
signal.signal(signal.SIGQUIT, sig_handler)
#various initializations that need to be performed: #various initializations that need to be performed:
offlineimap.mbnames.init(self.config, syncaccounts) offlineimap.mbnames.init(self.config, syncaccounts)

View File

@ -0,0 +1,25 @@
# Copyright 2013 Eygene A. Ryabinkin
# Functions to perform stack tracing (for multithreaded programs
# as well as for single-threaded ones).
import sys
import threading
import traceback
def dump(out):
""" Dumps current stack trace into I/O object 'out' """
id2name = {}
for th in threading.enumerate():
id2name[th.ident] = th.name
n = 0
for i, stack in sys._current_frames().items():
out.write ("\n# Thread #%d (id=%d), %s\n" % \
(n, i, id2name[i]))
n = n + 1
for f, lno, name, line in traceback.extract_stack (stack):
out.write ('File: "%s", line %d, in %s' % \
(f, lno, name))
if line:
out.write (" %s" % (line.strip()))
out.write ("\n")