diff --git a/magicbus/plugins/opsys.py b/magicbus/plugins/opsys.py index 9d9c5b5f..d4a9625a 100644 --- a/magicbus/plugins/opsys.py +++ b/magicbus/plugins/opsys.py @@ -270,8 +270,22 @@ def wait(self, timeout=None, poll_interval=0.1): def join(self, timeout=None, poll_interval=0.1): """Return when the PID file does not exist, or the timeout expires.""" + try: + initial_stat = os.stat(self.pidfile) + except OSError: # file does not exist + return + + initial_creation_time = initial_stat.st_ctime + starttime = time.time() while timeout is None or time.time() - starttime <= timeout: - if not os.path.exists(self.pidfile): - return + try: + pid_stat = os.stat(self.pidfile) + except OSError: + return # file does not exist + + pid_creation_time = pid_stat.st_ctime + if pid_creation_time > initial_creation_time: + return # file has been replaced + time.sleep(poll_interval) diff --git a/magicbus/test/test_opsys.py b/magicbus/test/test_opsys.py index dfe6b4f0..1e7981a2 100644 --- a/magicbus/test/test_opsys.py +++ b/magicbus/test/test_opsys.py @@ -32,17 +32,6 @@ def do_GET(self): service = WebService(handler_class=Handler) -@pytest.mark.xfail( - sys.version_info[0] > 2, reason=""" - Hangs under Python 3 because it loops too fast causing a race - condition in `magicbus.plugins.opsys.PIDFile.join()`. - - Refs: - * https://github.com/cherrypy/magicbus/issues/7 - * https://github.com/cherrypy/magicbus/pull/8 - """, - run=False, -) @pytest.mark.skipif(os.name != 'posix', reason='not on POSIX') def test_daemonize(): # Spawn the process and wait, when this returns, the original process diff --git a/magicbus/test/test_signals.py b/magicbus/test/test_signals.py index 086d9c50..b5fd0f66 100644 --- a/magicbus/test/test_signals.py +++ b/magicbus/test/test_signals.py @@ -98,6 +98,7 @@ def test_SIGHUP_daemonized(pidfile, daemon_process_pid, kill, SIGHUP, SIGTERM): kill(daemon_process_pid, SIGHUP) # Give the server some time to restart + pidfile.join() time.sleep(1) for _ in range(6): new_pid = pidfile.wait(5)