From d9a42630830eef597021179924351bba3b959386 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 1 Jan 2018 13:08:12 +0100 Subject: [PATCH] Daemonising fixes - change forking exit order as systemd expects (wait until child is ready, then exit parent, then grandparent) - fix signal handler if prctl not installed - revert recent PID file changes --- src/bitmessagemain.py | 19 ++++++++++++++++++- src/helper_generic.py | 2 +- src/singleinstance.py | 18 +++++++++++++----- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 91032fe5..6f796939 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -342,13 +342,21 @@ class Main: sleep(1) def daemonize(self): + grandfatherPid = os.getpid() + parentPid = None try: if os.fork(): + # unlock + shared.thisapp.cleanup() + # wait until grandchild ready + while True: + sleep(1) os._exit(0) except AttributeError: # fork not implemented pass else: + parentPid = os.getpid() shared.thisapp.lock() # relock os.umask(0) try: @@ -358,12 +366,17 @@ class Main: pass try: if os.fork(): + # unlock + shared.thisapp.cleanup() + # wait until child ready + while True: + sleep(1) os._exit(0) except AttributeError: # fork not implemented pass else: - shared.thisapp.lock(True) # relock and write pid + shared.thisapp.lock() # relock shared.thisapp.lockPid = None # indicate we're the final child sys.stdout.flush() sys.stderr.flush() @@ -374,6 +387,10 @@ class Main: os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) + if parentPid: + # signal ready + os.kill(parentPid, signal.SIGTERM) + os.kill(grandfatherPid, signal.SIGTERM) def setSignalHandler(self): signal.signal(signal.SIGINT, helper_generic.signal_handler) diff --git a/src/helper_generic.py b/src/helper_generic.py index b750e519..4f7a1299 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -51,7 +51,7 @@ def signal_handler(signal, frame): raise SystemExit if "PoolWorker" in current_process().name: raise SystemExit - if current_thread().name != "PyBitmessage": + if current_thread().name not in ("PyBitmessage", "MainThread"): return logger.error("Got signal %i", signal) if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): diff --git a/src/singleinstance.py b/src/singleinstance.py index fdb5ee98..d7cc0ab3 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -36,7 +36,7 @@ class singleinstance: self.initialized = True atexit.register(self.cleanup) - def lock(self, writePid = False): + def lock(self): if self.lockPid is None: self.lockPid = os.getpid() if sys.platform == 'win32': @@ -68,16 +68,24 @@ class singleinstance: sys.exit(-1) else: pidLine = "%i\n" % self.lockPid - if writePid: - self.fp.truncate(0) - self.fp.write(pidLine) - self.fp.flush() + self.fp.truncate(0) + self.fp.write(pidLine) + self.fp.flush() def cleanup(self): if not self.initialized: return if self.daemon and self.lockPid == os.getpid(): # these are the two initial forks while daemonizing + try: + if sys.platform == 'win32': + if hasattr(self, 'fd'): + os.close(self.fd) + else: + fcntl.lockf(self.fp, fcntl.LOCK_UN) + except Exception, e: + pass + return print "Cleaning up lockfile" try: