From 2c62542e0b0438f2ce1a0ba20768eacf09fdb54f Mon Sep 17 00:00:00 2001 From: HuntedByTheIRS Date: Fri, 3 Jul 2026 10:35:36 -0400 Subject: [PATCH] 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) --- parser/parser.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/parser/parser.c b/parser/parser.c index 5b45121..00bcfd4 100644 --- a/parser/parser.c +++ b/parser/parser.c @@ -996,11 +996,13 @@ watch_dispatch(int fd, uint32_t mask, void *data) /* * Some editors (vim, nano) delete-and-recreate files on save, - * which removes our watch (which is a pain in the ass. - * Hence, re-add it defensively. It's good for the soul) + * which replaces the inode and invalidates the existing watch. + * 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, IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE);