fix: remove inotify_rm_watch that caused infinite config-reload loop

inotify_rm_watch() generates IN_IGNORED events into the inotify
queue, which immediately triggers another watch_dispatch() call,
which calls inotify_rm_watch() again, generating another IN_IGNORED
ad infinitum. This pegs the CPU and makes input laggy on every
config reload.

Fix by removing inotify_rm_watch() entirely. inotify_add_watch()
alone handles both cases:
- Same inode: modifies the existing watch (no event generated)
- New inode (delete-and-recreate): creates a new watch; old watch
  on the unlinked inode generates a single IN_IGNORED (one-shot,
  not a loop)
This commit is contained in:
2026-07-03 10:35:36 -04:00
parent e117ff3e8d
commit 2c62542e0b
+5 -3
View File
@@ -996,11 +996,13 @@ watch_dispatch(int fd, uint32_t mask, void *data)
/* /*
* Some editors (vim, nano) delete-and-recreate files on save, * Some editors (vim, nano) delete-and-recreate files on save,
* which removes our watch (which is a pain in the ass. * which replaces the inode and invalidates the existing watch.
* Hence, re-add it defensively. It's good for the soul) * inotify_add_watch() on the path creates a new watch on the
* new inode (or is a no-op on the same inode). We do NOT call
* inotify_rm_watch() first — that would generate IN_IGNORED
* events into our own queue, causing an infinite reload loop.
*/ */
inotify_rm_watch(ws->inotify_fd, ws->watch_fd);
ws->watch_fd = inotify_add_watch(ws->inotify_fd, ws->path, ws->watch_fd = inotify_add_watch(ws->inotify_fd, ws->path,
IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE); IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE);