fix(systemd): give the receiver service its own VT instead of tty1
The receiver service never started on the Pi: systemd blocks before exec in acquire_terminal(), waiting for a controlling terminal that the console session or getty on tty1 already owns. Symptoms: the status shows the main PID as "(screencast)" with Tasks:1 and ~40ms CPU, a silent journal, and no mDNS announcement — the binary never ran. Reproduced locally with a transient unit (the desktop's Wayland session owns tty1) and diagnosed by gdb-attaching the stuck process. The service now owns a dedicated free VT (tty7) so acquisition is immediate, with a tolerant ExecStartPre chvt to make the screencast the on-screen console at boot. tty1 keeps the console login; Ctrl+Alt+F1/Ctrl+Alt+F7 switch between them. The previous advice to enable Console Autologin actively caused the hang and is removed from the unit, RUNBOOK, and install script notes. Validated locally: the same properties via systemd-run give a running receiver with all ~15 threads alive that announces itself and is found by --discover; verified unit passes systemd-analyze verify; graceful stop withdraws mDNS.
This commit is contained in:
+12
-3
@@ -34,9 +34,18 @@ loopback; current phase is Phase 7.
|
|||||||
- **systemd autostart**: `systemd/screencast-receiver.service` is a
|
- **systemd autostart**: `systemd/screencast-receiver.service` is a
|
||||||
template (`__SC_RECEIVER_BIN__`/`__SC_RECEIVER_USER__`); the install
|
template (`__SC_RECEIVER_BIN__`/`__SC_RECEIVER_USER__`); the install
|
||||||
script substitutes and enables it (opt out: `SC_RECEIVER_SERVICE=0`),
|
script substitutes and enables it (opt out: `SC_RECEIVER_SERVICE=0`),
|
||||||
adding the run user to video/render/input for headless KMSDRM. The unit
|
adding the run user to video/render/input for headless KMSDRM.
|
||||||
gets a controlling tty (StandardInput=tty, tty1) because SDL's KMSDRM
|
- **systemd tty trap (hit on the real Pi, reproduced locally)**: with
|
||||||
backend needs one for VT handling.
|
StandardInput=tty + TTYPath=tty1, the service NEVER started — systemd
|
||||||
|
blocks PRE-EXEC in acquire_terminal() waiting for a tty that the console
|
||||||
|
session/getty already owns. Symptoms: status shows the main PID as
|
||||||
|
"(screencast)" with Tasks:1 and ~40ms CPU, silent journal, no mDNS.
|
||||||
|
Diagnosed by gdb-attaching the stuck process (acquire_terminal backtrace)
|
||||||
|
after reproducing with a local transient unit. Fix: the service owns a
|
||||||
|
dedicated free VT (tty7) + tolerant `ExecStartPre=-/usr/bin/chvt 7`;
|
||||||
|
tty1 keeps the console. Also: `systemctl status` Tasks counts THREADS
|
||||||
|
(a healthy receiver shows ~15), and "Console Autologin" advice was
|
||||||
|
WRONG (it made the hang deterministic) — removed from all docs.
|
||||||
- **Fullscreen headless rendering**: under the KMSDRM video driver (no
|
- **Fullscreen headless rendering**: under the KMSDRM video driver (no
|
||||||
window manager) the renderer goes fullscreen automatically; --fullscreen
|
window manager) the renderer goes fullscreen automatically; --fullscreen
|
||||||
forces it on desktops. Aspect is preserved via
|
forces it on desktops. Aspect is preserved via
|
||||||
|
|||||||
+6
-2
@@ -96,9 +96,13 @@ The receiver does not need X11, Wayland, or any window manager: SDL3's
|
|||||||
KMSDRM backend renders straight to the kernel display pipeline. This is
|
KMSDRM backend renders straight to the kernel display pipeline. This is
|
||||||
the recommended setup for small boards (Raspberry Pi OS **Lite**):
|
the recommended setup for small boards (Raspberry Pi OS **Lite**):
|
||||||
|
|
||||||
1. `sudo raspi-config` → System Options → Boot → **Console Autologin**.
|
1. No desktop may be enabled — a running compositor holds the DRM master
|
||||||
2. No desktop may be enabled — a running compositor holds the DRM master
|
|
||||||
and the receiver cannot take it (the two modes are mutually exclusive).
|
and the receiver cannot take it (the two modes are mutually exclusive).
|
||||||
|
No console autologin is needed either.
|
||||||
|
2. The service renders on its **own VT (tty7)** and switches to it at
|
||||||
|
boot: `Ctrl+Alt+F1` returns to the console login, `Ctrl+Alt+F7` back
|
||||||
|
to the screencast. (A service must not target tty1: acquiring a tty
|
||||||
|
that the console session or getty owns blocks the start forever.)
|
||||||
3. Disable console blanking: append `consoleblank=0` to
|
3. Disable console blanking: append `consoleblank=0` to
|
||||||
`/boot/firmware/cmdline.txt` and reboot.
|
`/boot/firmware/cmdline.txt` and reboot.
|
||||||
|
|
||||||
|
|||||||
@@ -184,8 +184,10 @@ The receiver is installed and starts automatically at boot.
|
|||||||
Notes for small boards (e.g. Pi Zero 2 W):
|
Notes for small boards (e.g. Pi Zero 2 W):
|
||||||
- No window manager is required: the receiver renders directly to the
|
- No window manager is required: the receiver renders directly to the
|
||||||
kernel display pipeline (SDL KMSDRM). Use Raspberry Pi OS Lite with
|
kernel display pipeline (SDL KMSDRM). Use Raspberry Pi OS Lite with
|
||||||
Console Autologin (raspi-config) and no desktop enabled — a running
|
NO desktop enabled — a running compositor would own the display and
|
||||||
compositor would own the display and the receiver could not start.
|
the receiver could not start. No console autologin is needed either.
|
||||||
|
- The service owns tty7 and switches to it at boot (Ctrl+Alt+F1 returns
|
||||||
|
to the console login, Ctrl+Alt+F7 to the screencast).
|
||||||
- Disable console blanking so the picture never goes dark: add
|
- Disable console blanking so the picture never goes dark: add
|
||||||
consoleblank=0 to /boot/firmware/cmdline.txt and reboot.
|
consoleblank=0 to /boot/firmware/cmdline.txt and reboot.
|
||||||
- Decoding is software H.264; expect smooth playback for small streams
|
- Decoding is software H.264; expect smooth playback for small streams
|
||||||
|
|||||||
@@ -26,12 +26,16 @@ StartLimitBurst=10
|
|||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=__SC_RECEIVER_USER__
|
User=__SC_RECEIVER_USER__
|
||||||
|
# SDL's KMSDRM backend wants a tty. The service gets its OWN virtual
|
||||||
|
# terminal: systemd must acquire the controlling terminal before exec, and
|
||||||
|
# acquiring one that another session owns (tty1: getty, console autologin,
|
||||||
|
# or a desktop) blocks the start FOREVER in a pre-exec placeholder process
|
||||||
|
# (systemctl status shows the main PID as "(screencast)"). tty7 is free on
|
||||||
|
# stock systems; tty1 keeps the console login.
|
||||||
|
ExecStartPre=-/usr/bin/chvt 7
|
||||||
ExecStart=__SC_RECEIVER_BIN__ --receive
|
ExecStart=__SC_RECEIVER_BIN__ --receive
|
||||||
# SDL's KMSDRM backend (headless console) expects a controlling terminal
|
|
||||||
# for its VT handling; system services have none by default. Harmless in
|
|
||||||
# desktop mode, where the process never touches the tty.
|
|
||||||
StandardInput=tty
|
StandardInput=tty
|
||||||
TTYPath=/dev/tty1
|
TTYPath=/dev/tty7
|
||||||
# SIGTERM (systemctl stop) shuts the receiver down gracefully, which
|
# SIGTERM (systemctl stop) shuts the receiver down gracefully, which
|
||||||
# withdraws its mDNS announcement. Never SIGKILL it; the systemd default
|
# withdraws its mDNS announcement. Never SIGKILL it; the systemd default
|
||||||
# KillMode escalates only after the graceful timeout.
|
# KillMode escalates only after the graceful timeout.
|
||||||
@@ -54,6 +58,8 @@ WantedBy=multi-user.target
|
|||||||
# to the kernel via KMSDRM):
|
# to the kernel via KMSDRM):
|
||||||
# * Raspberry Pi OS Lite, no desktop enabled (a running compositor would
|
# * Raspberry Pi OS Lite, no desktop enabled (a running compositor would
|
||||||
# hold the DRM master and the receiver could not take it)
|
# hold the DRM master and the receiver could not take it)
|
||||||
# * raspi-config → System Options → Boot → Console Autologin
|
# * no console autologin needed: the service owns tty7 and switches to it
|
||||||
|
# at boot; Ctrl+Alt+F1 returns to the console login, Ctrl+Alt+F7 to the
|
||||||
|
# screencast
|
||||||
# * disable console blanking: add consoleblank=0 to
|
# * disable console blanking: add consoleblank=0 to
|
||||||
# /boot/firmware/cmdline.txt
|
# /boot/firmware/cmdline.txt
|
||||||
Reference in New Issue
Block a user