From 9120e57926ddd8d2b744f89a423e3253534efb5c Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 24 May 2026 18:47:24 +0300 Subject: [PATCH] clipboard: clear stale serving PID; fix persistence restart Fixes #99 where persistence silently stops after the first entry because `SERVING_PID` was never reset in the parent after the child exited. Signed-off-by: NotAShelf Change-Id: Id41e16980c45e35be2a984e6f85b96e76a6a6964 --- src/clipboard/persist.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/clipboard/persist.rs b/src/clipboard/persist.rs index f5312a7..9ca9dc7 100644 --- a/src/clipboard/persist.rs +++ b/src/clipboard/persist.rs @@ -22,9 +22,25 @@ static SERVING_PID: AtomicI32 = AtomicI32::new(0); /// Get the current serving PID if any. Used by the watch loop to avoid /// duplicate persistence processes. +/// +/// Probes the stored PID with `kill(pid, 0)` to detect children that have +/// already exited (SIGCHLD is ignored so we never get reaped notifications). +/// A stale PID is cleared and `None` is returned. pub fn get_serving_pid() -> Option { let pid = SERVING_PID.load(Ordering::SeqCst); - if pid != 0 { Some(pid) } else { None } + if pid == 0 { + return None; + } + + // Signal 0 = existence check, no signal sent. Returns 0 if alive, + // -1 (ESRCH) if the PID is gone. + if unsafe { libc::kill(pid, 0) } == 0 { + Some(pid) + } else { + let _ = + SERVING_PID.compare_exchange(pid, 0, Ordering::SeqCst, Ordering::SeqCst); + None + } } /// Result type for persistence operations. @@ -157,6 +173,18 @@ unsafe fn fork_and_serve(prepared: PreparedCopy) -> PersistenceResult<()> { libc::signal(libc::SIGCHLD, libc::SIG_IGN); } + // Replace any prior serving child: a new clipboard entry supersedes the + // old offer (the compositor will invalidate it anyway the moment the new + // selection is taken). Without this, the old child lingers serving stale + // data until MAX_SERVE_REQUESTS or invalidation. + let prior = SERVING_PID.swap(0, Ordering::SeqCst); + if prior > 0 && unsafe { libc::kill(prior, 0) } == 0 { + unsafe { + libc::kill(prior, libc::SIGTERM); + } + log::debug!("terminated prior persistence child (pid: {prior})"); + } + match unsafe { libc::fork() } { 0 => { // Child process - clear serving PID