mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-26 10:02:01 +01:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b6b05a175 | ||
|
|
67b9151513 |
No files matched your search
+20
-3
@@ -426,10 +426,27 @@ class OneServer(unittest.TestCase):
|
||||
|
||||
# Stopped as the app stops it: by closing stdin (the only way on Windows,
|
||||
# where terminate() is a hard kill) and, elsewhere, by SIGTERM too.
|
||||
for stop in ["stdin"] + (["sigterm"] if os.name != "nt" else []):
|
||||
for stop in ["stdin"] + (["sigterm", "stdin+late-sigterm"] if os.name != "nt" else []):
|
||||
with self.subTest(stop=stop):
|
||||
left_by_dead = [staged(tmp, "frame-vr-", dead.pid), staged(index_dir, ".download-", dead.pid)]
|
||||
proc = subprocess.Popen([sys.executable, str(ROOT / "ui" / "server.py"), "--port", "0", "--exit-on-eof"],
|
||||
command = [sys.executable, str(ROOT / "ui" / "server.py"), "--port", "0", "--exit-on-eof"]
|
||||
if stop == "stdin+late-sigterm":
|
||||
# Deliver the app's second stop mechanism exactly as cleanup
|
||||
# replaces the signal handler: the race observed on a real Mac.
|
||||
wrapper = (
|
||||
"import os, runpy, signal, sys; from pathlib import Path\n"
|
||||
"original = signal.signal\n"
|
||||
"def install(sig, handler):\n"
|
||||
" if sig == signal.SIGTERM and handler == signal.SIG_IGN:\n"
|
||||
" os.kill(os.getpid(), signal.SIGTERM)\n"
|
||||
" return original(sig, handler)\n"
|
||||
"signal.signal = install\n"
|
||||
"sys.argv = sys.argv[1:]\n"
|
||||
"sys.path.insert(0, str(Path(sys.argv[0]).parent))\n"
|
||||
"runpy.run_path(sys.argv[0], run_name='__main__')\n"
|
||||
)
|
||||
command = [sys.executable, "-c", wrapper, *command[1:]]
|
||||
proc = subprocess.Popen(command,
|
||||
env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT, text=True)
|
||||
try:
|
||||
@@ -437,7 +454,7 @@ class OneServer(unittest.TestCase):
|
||||
self.assertEqual([d for d in left_by_dead if d.exists()], [])
|
||||
in_flight = [staged(tmp, "frame-vr-", proc.pid), staged(tmp, "frame-agent-", proc.pid),
|
||||
staged(index_dir, ".download-", proc.pid)]
|
||||
if stop == "stdin":
|
||||
if stop.startswith("stdin"):
|
||||
proc.stdin.close()
|
||||
else:
|
||||
proc.terminate()
|
||||
|
||||
+7
-4
@@ -4172,8 +4172,12 @@ def main():
|
||||
LINK.start()
|
||||
if not PRIVATE: # one worker per user, in the app's server
|
||||
threading.Thread(target=autosync.run, args=(_stop_sync,), daemon=True).start()
|
||||
def request_shutdown(*_):
|
||||
# shutdown() must run outside the serve_forever thread. Do not raise
|
||||
# from SIGTERM: the app can send it after stdin EOF has begun cleanup.
|
||||
threading.Thread(target=httpd.shutdown, daemon=True).start()
|
||||
if not frame_host.WINDOWS:
|
||||
signal.signal(signal.SIGTERM, lambda *_: (_ for _ in ()).throw(KeyboardInterrupt))
|
||||
signal.signal(signal.SIGTERM, request_shutdown)
|
||||
if args.exit_on_eof:
|
||||
def watch_stdin():
|
||||
# os.read, not sys.stdin.buffer.read: a buffered read holds stdin's lock,
|
||||
@@ -4181,7 +4185,7 @@ def main():
|
||||
# when it can't take that lock back from this thread.
|
||||
while os.read(0, 4096):
|
||||
pass
|
||||
threading.Thread(target=httpd.shutdown, daemon=True).start()
|
||||
request_shutdown()
|
||||
threading.Thread(target=watch_stdin, daemon=True).start()
|
||||
try:
|
||||
# The real port, which --port 0 leaves to the system (the iPhone app reads it from here).
|
||||
@@ -4190,8 +4194,7 @@ def main():
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
# The app both closes stdin and sends SIGTERM on quit; a second signal
|
||||
# mid-cleanup would abort it and leave the SSH master running.
|
||||
# Cleanup is already underway; later stop signals need no more workers.
|
||||
if not frame_host.WINDOWS:
|
||||
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
||||
_power.shutdown()
|
||||
|
||||
Reference in new issue
Block a user