threading: simplify the monitoring code for threads
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
parent
87cf6bda02
commit
a1f40af033
@ -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)
|
||||||
|
@ -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."""
|
||||||
|
Loading…
Reference in New Issue
Block a user