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:
parent
83e8fca2e0
commit
de84c3941c
@ -7,7 +7,8 @@ ChangeLog
|
||||
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
|
||||
the signal to reread the configuration (Dmitrijs Ledkovs)
|
||||
* Honor the timezone of emails (Tobias Thierer)
|
||||
|
@ -309,7 +309,7 @@ UNIX Signals
|
||||
============
|
||||
|
||||
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
|
||||
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
|
||||
is used.
|
||||
|
||||
SIGQUIT dumps stack traces for all threads and tries to dump process
|
||||
core.
|
||||
|
||||
Folder filtering and nametrans
|
||||
==============================
|
||||
|
||||
|
@ -28,6 +28,7 @@ from offlineimap import accounts, threadutil, syncmaster
|
||||
from offlineimap.error import OfflineImapError
|
||||
from offlineimap.ui import UI_LIST, setglobalui, getglobalui
|
||||
from offlineimap.CustomConfig import CustomConfigParser
|
||||
from offlineimap.utils import stacktrace
|
||||
|
||||
|
||||
class OfflineImap:
|
||||
@ -341,12 +342,16 @@ class OfflineImap:
|
||||
getglobalui().warn("Terminating NOW (this may "\
|
||||
"take a few seconds)...")
|
||||
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.SIGUSR1,sig_handler)
|
||||
signal.signal(signal.SIGUSR2,sig_handler)
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
signal.signal(signal.SIGQUIT, sig_handler)
|
||||
|
||||
#various initializations that need to be performed:
|
||||
offlineimap.mbnames.init(self.config, syncaccounts)
|
||||
|
25
offlineimap/utils/stacktrace.py
Normal file
25
offlineimap/utils/stacktrace.py
Normal 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")
|
Loading…
Reference in New Issue
Block a user