threading: simplify the monitoring code for threads

Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Nicolas Sebrecht 2016-05-12 05:29:49 +02:00
parent 87cf6bda02
commit a1f40af033
2 changed files with 31 additions and 32 deletions

View File

@ -390,10 +390,9 @@ class OfflineImap:
# multithreaded # multithreaded
t = threadutil.ExitNotifyThread(target=syncmaster.syncitall, t = threadutil.ExitNotifyThread(target=syncmaster.syncitall,
name='Sync Runner', name='Sync Runner',
kwargs = {'accounts': syncaccounts, kwargs={'accounts': syncaccounts, 'config': self.config})
'config': self.config})
t.start() t.start()
threadutil.exitnotifymonitorloop(threadutil.threadexited) threadutil.exitnotifymonitorloop()
if not options.dryrun: if not options.dryrun:
offlineimap.mbnames.write(True) offlineimap.mbnames.write(True)

View File

@ -22,7 +22,6 @@ except ImportError: # python3
from queue import Queue, Empty from queue import Queue, Empty
import traceback import traceback
import os.path import os.path
import sys
from offlineimap.ui import getglobalui from offlineimap.ui import getglobalui
@ -87,7 +86,7 @@ class threadlist:
exitthreads = Queue() exitthreads = Queue()
def exitnotifymonitorloop(callback): def exitnotifymonitorloop():
"""An infinite "monitoring" loop watching for finished ExitNotifyThread's. """An infinite "monitoring" loop watching for finished ExitNotifyThread's.
This one is supposed to run in the main thread. This one is supposed to run in the main thread.
@ -105,38 +104,36 @@ def exitnotifymonitorloop(callback):
""" """
global exitthreads global exitthreads
do_loop = True ui = getglobalui()
while do_loop:
while True:
# Loop forever and call 'callback' for each thread that exited # Loop forever and call 'callback' for each thread that exited
try: try:
# we need a timeout in the get() call, so that ctrl-c can throw # We need a timeout in the get() call, so that ctrl-c can throw
# a SIGINT (http://bugs.python.org/issue1360). A timeout with empty # a SIGINT (http://bugs.python.org/issue1360). A timeout with empty
# Queue will raise `Empty`. # Queue will raise `Empty`.
thrd = exitthreads.get(True, 60) thread = exitthreads.get(True, 60)
# request to abort when callback returns true # request to abort when callback returns true
do_loop = (callback(thrd) != True)
except Empty:
pass
def threadexited(thread): if thread.exit_exception is not None:
"""Called when a thread exits.
Main thread is aborted when this returns True."""
ui = getglobalui()
if thread.exit_exception:
if isinstance(thread.exit_exception, SystemExit): if isinstance(thread.exit_exception, SystemExit):
# Bring a SystemExit into the main thread. # Bring a SystemExit into the main thread.
# Do not send it back to UI layer right now. # Do not send it back to UI layer right now.
# Maybe later send it to ui.terminate? # Maybe later send it to ui.terminate?
raise SystemExit raise SystemExit
ui.threadException(thread) # Expected to terminate ui.threadException(thread) # Expected to terminate the program.
sys.exit(100) # Just in case... # Should never hit this line.
raise AssertionError("thread has 'exit_exception' set to"
" '%s' [%s] but this value is unexpected"
" and the ui did not stop the program."%
(repr(thread.exit_exception), type(thread.exit_exception)))
elif thread.exit_message == NORMAL_EXIT: elif thread.exit_message == NORMAL_EXIT:
return True break # Exit the loop here.
else: else:
ui.threadExited(thread) ui.threadExited(thread)
return False except Empty:
pass
class ExitNotifyThread(Thread): class ExitNotifyThread(Thread):
"""This class is designed to alert a "monitor" to the fact that a """This class is designed to alert a "monitor" to the fact that a
@ -145,7 +142,10 @@ class ExitNotifyThread(Thread):
bail out when the mainloop dies. bail out when the mainloop dies.
The thread can set instance variables self.exit_message for a human The thread can set instance variables self.exit_message for a human
readable reason of the thread exit.""" readable reason of the thread exit.
There is one instance of this class at runtime. The main thread waits for
the monitor to end."""
profiledir = None profiledir = None
"""Class variable that is set to the profile directory if required.""" """Class variable that is set to the profile directory if required."""