diff options
| author | Danilo M. <danix@danix.xyz> | 2026-06-29 11:07:41 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-06-29 11:07:41 +0200 |
| commit | 12528dccd3a1c7043fb14343c0830345f5015fbf (patch) | |
| tree | adeacec67742f333fc79dfed1fd5c021efe898a7 | |
| parent | abe41b57d39e6fd2d88a1e5e20c921b96d54b65b (diff) | |
| download | breaktimer-12528dccd3a1c7043fb14343c0830345f5015fbf.tar.gz breaktimer-12528dccd3a1c7043fb14343c0830345f5015fbf.zip | |
Fix duplicate daemon spawn on login via atomic PID claim
Replace the check-then-write singleton guard in run_loop with an atomic
noclobber PID-file claim. The old guard read the PID file then wrote it
in two steps; two starts racing (e.g. a fast double-login) could both
read a stale PID and spawn duplicate daemons. With noclobber only the
first writer creates the file; the loser aborts, and a stale PID from a
previous session is taken over rather than duplicated.
Also document install (~/bin copy) and autostart in CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| -rw-r--r-- | CLAUDE.md | 17 | ||||
| -rwxr-xr-x | breaktimer.sh | 19 |
2 files changed, 29 insertions, 7 deletions
@@ -6,6 +6,23 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co `breaktimer` is a Bash break-reminder daemon for a Linux/Wayland desktop (dunst + pipewire + Waybar). No build, no package manager, no tests — it's a single shell script plus Waybar integration files. Comments and notification strings are in Italian; keep that convention when editing. +## Install + +The runtime copy lives at `~/bin/breaktimer.sh` (a plain copy, not a symlink). After editing the repo, install and reload: + +```bash +cp breaktimer.sh ~/bin/breaktimer.sh +~/bin/breaktimer.sh restart +``` + +Autostart is a Hyprland exec in `~/.config/hypr/sections/autostart.lua`: + +```lua +hl.exec_cmd("/home/danix/bin/breaktimer.sh start") +``` + +`start` is idempotent: an atomic `noclobber` PID-file claim in `run_loop` means a second `start` (or a fast double-login) can't spawn a duplicate daemon — the loser aborts. A stale PID file from a previous session is taken over, not duplicated. + ## Running ```bash diff --git a/breaktimer.sh b/breaktimer.sh index 4ce5a42..9a9c5fa 100755 --- a/breaktimer.sh +++ b/breaktimer.sh @@ -107,15 +107,20 @@ notify_back() { # ---------- Loop principale ---------- run_loop() { - # singleton: rifiuta se un altro daemon vivo possiede gia' il PID file. - # Evita due loop che si calpestano gli stessi file di stato. + # singleton: rivendica il PID file in modo atomico con noclobber. + # check-then-write avrebbe una finestra di race: due loop avviati insieme + # (es. doppio login) leggono entrambi un PID file stantio e partono. Con + # noclobber solo il primo crea il file; il secondo fallisce e poi decide. local owner - owner="$(cat "$PID_FILE" 2>/dev/null)" - if [ -n "$owner" ] && [ "$owner" != "$$" ] && kill -0 "$owner" 2>/dev/null; then - echo "breaktimer: gia' in esecuzione (PID $owner), run annullato" >&2 - exit 1 + if ! ( set -o noclobber; echo "$$" > "$PID_FILE" ) 2>/dev/null; then + owner="$(cat "$PID_FILE" 2>/dev/null)" + if [ -n "$owner" ] && [ "$owner" != "$$" ] && kill -0 "$owner" 2>/dev/null; then + echo "breaktimer: gia' in esecuzione (PID $owner), run annullato" >&2 + exit 1 + fi + # PID file stantio (owner morto): rivendicalo. + echo "$$" > "$PID_FILE" fi - echo "$$" > "$PID_FILE" echo "running" > "$STATE_FILE" echo "working" > "$PHASE_FILE" local count=0 |
