Following this discussion, here is the patch I came to write. This apply against libev-3.9 vanilla.
Feel free to include it, or not, in the libev distribution. >From the local testing I've made (although some more is needed), this is working fine and fixes various problem that I reported. -- Yoann Vandoorselaere | Directeur Technique/CTO | PreludeIDS Technologies Tel: +33 (0)1 40 24 65 10 Fax: +33 (0)1 40 24 65 28 http://www.prelude-ids.com
>From d06b75c8e6da44d00846e84febfe7a371e9583fe Mon Sep 17 00:00:00 2001 From: Yoann Vandoorselaere <[email protected]> Date: Wed, 27 Jan 2010 15:37:19 +0100 Subject: [PATCH] - Loop through the whole buffer that we read() from Inotify. Previously, only the first inotify_event entry was used, and propagated as much time as there was entry in the buffer. Further entry in the buffer were ignored. This lead to bug where important event were not propagated. - Do not call infy_wd() in case we're getting IN_IGNORED. This flags indicate that the Inotify WD was deleted, either explicitly (inotify_rm_watch), or automatically (unmount, deletion). In any of theses case, we already have handled the deletion event ourselve. Avoid an useless wd table scan. - Rather than removing the watch, and adding it again on every notification, only do it when necessary. Handle rename and create explicitly. Avoid a lot of inotify_add_watch() and inotify_rm_watch call. This additionally fixes a race were the currently read inotify_event buffer in infy_cb() got others events that we didn't propagate yet, and the WD is changed from the stat_timer_cb() function. Other events would then never propagate since infy_wd() wouldn't find the corresponding WD. --- ev.c | 37 ++++++++++++++++++++++++------------- 1 files changed, 24 insertions(+), 13 deletions(-) diff --git a/ev.c b/ev.c index ccd202b..94b2264 100644 --- a/ev.c +++ b/ev.c @@ -2957,11 +2957,27 @@ infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev) if (w->wd == wd || wd == -1) { - if (ev->mask & (IN_IGNORED | IN_UNMOUNT | IN_DELETE_SELF)) + if ( ev->mask & IN_CREATE ) + { + char *ptr = strrchr(w->path, '/'); + if ( ptr && strcmp(ptr + 1, ev->name) == 0 ) + { + /* remove the existing directory watcher, and create a watcher for the file */ + infy_del(EV_A_ w); + infy_add(EV_A_ w); + } + } + else if (ev->mask & (IN_UNMOUNT | IN_DELETE_SELF)) { wlist_del (&fs_hash [slot & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w); w->wd = -1; - infy_add (EV_A_ w); /* re-add, no matter what */ + infy_add(EV_A_ w); + } + else if (ev->mask & IN_MOVE_SELF ) + { + /* make sure we continue monitoring the old filename */ + infy_del(EV_A_ w); + infy_add(EV_A_ w); } stat_timer_cb (EV_A_ &w->timer, 0); @@ -2974,12 +2990,16 @@ static void infy_cb (EV_P_ ev_io *w, int revents) { char buf [EV_INOTIFY_BUFSIZE]; - struct inotify_event *ev = (struct inotify_event *)buf; int ofs; + struct inotify_event *ev; int len = read (fs_fd, buf, sizeof (buf)); for (ofs = 0; ofs < len; ofs += sizeof (struct inotify_event) + ev->len) - infy_wd (EV_A_ ev->wd, ev->wd, ev); + { + ev = (struct inotify_event *) (buf + ofs); + if ( !(ev->mask & IN_IGNORED) ) + infy_wd (EV_A_ ev->wd, ev->wd, ev); + } } inline_size void @@ -3128,15 +3148,6 @@ stat_timer_cb (EV_P_ ev_timer *w_, int revents) /* to ensure that prev is always different to attr */ w->prev = prev; - #if EV_USE_INOTIFY - if (fs_fd >= 0) - { - infy_del (EV_A_ w); - infy_add (EV_A_ w); - ev_stat_stat (EV_A_ w); /* avoid race... */ - } - #endif - ev_feed_event (EV_A_ w, EV_STAT); } } -- 1.6.6
_______________________________________________ libev mailing list [email protected] http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev
