From fdae87aa6effa80ef317794292b48f90c9ec9ba6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 9 Oct 2020 22:53:21 +0530 Subject: [PATCH] When restarting detect actual parent process death instead of sleeping for two seconds This should hopefully fix the issue with restarts not working on some Windows machines because the parent process takes longer than two seconds to die. --- src/calibre/gui2/main.py | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index a0fa608fae..e0ee88296f 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -353,12 +353,20 @@ class GuiRunner(QObject): self.initialize_db() +def set_restarting_env_var(): + if iswindows: + ctime = plugins['winutil'][0].get_process_times(None)[0] + os.environ['CALIBRE_RESTARTING_FROM_GUI'] = str(ctime) + else: + os.environ['CALIBRE_RESTARTING_FROM_GUI'] = str(os.getpid()) + + def run_in_debug_mode(): from calibre.debug import run_calibre_debug import tempfile, subprocess fd, logpath = tempfile.mkstemp('.txt') os.close(fd) - os.environ['CALIBRE_RESTARTING_FROM_GUI'] = environ_item('1') + set_restarting_env_var() run_calibre_debug( '--gui-debug', logpath, stdout=lopen(logpath, 'wb'), stderr=subprocess.STDOUT, stdin=lopen(os.devnull, 'rb')) @@ -403,8 +411,8 @@ def run_gui(opts, args, listener, app, gui_debug=None): run_calibre_debug('-c', 'import sys, os, time; time.sleep(3); os.execlp("open", "open", sys.argv[-1])', app) else: import subprocess - os.environ['CALIBRE_RESTARTING_FROM_GUI'] = environ_item('1') - if iswindows and hasattr(winutil, 'prepare_for_restart'): + set_restarting_env_var() + if iswindows: winutil.prepare_for_restart() if hasattr(sys, 'run_local'): cmd = [sys.run_local] @@ -514,9 +522,31 @@ def create_listener(): return Listener(address=gui_socket_address()) +def wait_for_parent_to_die(ppid, max_wait=10): + ppid = int(ppid) + if iswindows: + get_process_times = plugins['winutil'][0].get_process_times + + def parent_done(): + try: + ctime = get_process_times(os.getppid())[0] + except Exception: + return True + return ctime > ppid + + else: + def parent_done(): + return os.getppid() != ppid + + st = time.monotonic() + while not parent_done() and time.monotonic() - st < max_wait: + time.sleep(0.1) + + def main(args=sys.argv): - if os.environ.pop('CALIBRE_RESTARTING_FROM_GUI', None) == environ_item('1'): - time.sleep(2) # give the parent process time to cleanup and close + ppid = os.environ.pop('CALIBRE_RESTARTING_FROM_GUI', None) + if ppid is not None: + wait_for_parent_to_die(ppid) if iswindows and 'CALIBRE_REPAIR_CORRUPTED_DB' in os.environ: windows_repair() return 0