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

@ -389,11 +389,10 @@ class OfflineImap:
else: else:
# 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,39 +104,37 @@ 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)
if thread.exit_exception is not None:
if isinstance(thread.exit_exception, SystemExit):
# Bring a SystemExit into the main thread.
# Do not send it back to UI layer right now.
# Maybe later send it to ui.terminate?
raise SystemExit
ui.threadException(thread) # Expected to terminate the program.
# 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:
break # Exit the loop here.
else:
ui.threadExited(thread)
except Empty: except Empty:
pass pass
def threadexited(thread):
"""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):
# Bring a SystemExit into the main thread.
# Do not send it back to UI layer right now.
# Maybe later send it to ui.terminate?
raise SystemExit
ui.threadException(thread) # Expected to terminate
sys.exit(100) # Just in case...
elif thread.exit_message == NORMAL_EXIT:
return True
else:
ui.threadExited(thread)
return False
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
thread has exited and to provide for the ability for it to find out thread has exited and to provide for the ability for it to find out
@ -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."""