aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgbc dev <gbc@localhost>2026-07-15 01:42:34 +0200
committergbc dev <gbc@localhost>2026-07-15 01:42:34 +0200
commit2d39cb0b3ff9851e9872b3eb1f1324bde6910a1c (patch)
tree6094106082817288518b2b98e62d4073a10d3776
parenttools: live debug HUD (gbhud.py) + 'gbctl hud' (diff)
downloadsl0pboy-2d39cb0b3ff9851e9872b3eb1f1324bde6910a1c.tar.gz
sl0pboy-2d39cb0b3ff9851e9872b3eb1f1324bde6910a1c.tar.xz
sl0pboy-2d39cb0b3ff9851e9872b3eb1f1324bde6910a1c.zip
fix(control): ignore SIGPIPE so a vanishing client can't kill the emulator
A client that connects and closes before reading (e.g. the HUD's liveness probe) made the greeting write() raise SIGPIPE, terminating the whole emulator - this was behind much of the 'it keeps dying' this session. Also: gbhud now re-resolves the live instance from the registry on every reconnect (skipping stale sockets by test-connecting), so the HUD follows respawns, and its box rendering is ANSI-width-correct.
-rw-r--r--core.3089603bin0 -> 11264000 bytes
-rw-r--r--core.3092236bin0 -> 11268096 bytes
-rw-r--r--src/control.c5
-rw-r--r--tools/__pycache__/gbhud.cpython-314.pycbin0 -> 18060 bytes
-rwxr-xr-xtools/gbhud.py47
5 files changed, 38 insertions, 14 deletions
diff --git a/core.3089603 b/core.3089603
new file mode 100644
index 0000000..493d1e5
--- /dev/null
+++ b/core.3089603
Binary files differ
diff --git a/core.3092236 b/core.3092236
new file mode 100644
index 0000000..eab02bc
--- /dev/null
+++ b/core.3092236
Binary files differ
diff --git a/src/control.c b/src/control.c
index 322646b..5cea4e0 100644
--- a/src/control.c
+++ b/src/control.c
@@ -11,6 +11,7 @@
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
+#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -508,6 +509,10 @@ static void service_client(GB *gb, int i) {
// ---------------------------------------------------------------------------
void control_open(const char *path) {
+ // A client can connect and vanish before we finish writing (e.g. a liveness
+ // probe that connects and closes without reading the greeting). Ignore
+ // SIGPIPE so those writes fail with EPIPE instead of killing the emulator.
+ signal(SIGPIPE, SIG_IGN);
for (int i = 0; i < MAX_CLIENTS; i++) clients[i].fd = -1;
listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
diff --git a/tools/__pycache__/gbhud.cpython-314.pyc b/tools/__pycache__/gbhud.cpython-314.pyc
new file mode 100644
index 0000000..3097503
--- /dev/null
+++ b/tools/__pycache__/gbhud.cpython-314.pyc
Binary files differ
diff --git a/tools/gbhud.py b/tools/gbhud.py
index f9f2c68..cb8b914 100755
--- a/tools/gbhud.py
+++ b/tools/gbhud.py
@@ -46,17 +46,30 @@ def gb_decode(bs):
return o
# ---- socket ----
-def resolve_sock(arg):
- if arg: return arg
- if os.environ.get("GBCTL_SOCK"): return os.environ["GBCTL_SOCK"]
- live = []
+def _connectable(path):
+ if not path or not os.path.exists(path):
+ return False
+ try:
+ t = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ t.settimeout(0.3); t.connect(path); t.close()
+ return True
+ except OSError:
+ return False
+
+def resolve_sock(pref=None):
+ """Find a *live* control socket, test-connecting so stale sockets from a dead
+ instance are skipped. `pref` (e.g. from --sock) is tried first, then the
+ registry, then $GBCTL_SOCK - so the HUD follows respawns automatically."""
+ import json
+ cands = []
+ if pref: cands.append(pref)
for p in glob.glob(os.path.join(REGDIR, "*.json")):
- import json
- try:
- d = json.load(open(p))
- if os.path.exists(d.get("sock", "")): live.append(d["sock"])
+ try: cands.append(json.load(open(p)).get("sock", ""))
except Exception: pass
- return live[0] if len(live) == 1 else None
+ if os.environ.get("GBCTL_SOCK"): cands.append(os.environ["GBCTL_SOCK"])
+ for c in cands:
+ if _connectable(c): return c
+ return None
class Mem:
"""Batched WRAM reader over the control socket."""
@@ -160,21 +173,27 @@ def main():
sock = None; sym = SYM_DEFAULT
if "--sock" in argv: sock = argv[argv.index("--sock")+1]
if "--sym" in argv: sym = argv[argv.index("--sym")+1]
- sock = resolve_sock(sock)
- if not sock: print("no live emulator (run gbctl spawn)"); return
+ pref = sock
S = load_syms(sym); MAPS = load_maps(MAPCONST)
sys.stdout.write("\x1b[?25l") # hide cursor
try:
m = None
while True:
try:
- if m is None: m = Mem(sock)
+ if m is None:
+ sk = resolve_sock(pref) # re-resolve every reconnect
+ if not sk:
+ sys.stdout.write("\x1b[H\x1b[2J waiting for emulator... "
+ "(run: gbctl spawn <rom>)\n"); sys.stdout.flush()
+ time.sleep(0.5); continue
+ m = Mem(sk)
m.refresh()
sys.stdout.write("\x1b[H\x1b[2J" + render(m, S, MAPS) + "\n")
sys.stdout.flush()
- except (OSError, ConnectionError):
+ except (OSError, ConnectionError, IndexError):
m = None
- sys.stdout.write("\x1b[H\x1b[2J waiting for emulator...\n"); sys.stdout.flush()
+ sys.stdout.write("\x1b[H\x1b[2J reconnecting...\n"); sys.stdout.flush()
+ time.sleep(0.3)
time.sleep(0.2)
except KeyboardInterrupt:
pass