diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-08-25 12:43:34 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2016-08-25 22:29:47 +0300 |
commit | f1b64a3ade5b5659f7ddf417c3fdfb4db133aa75 (patch) | |
tree | fda58c3e3116501b816cbc32a74d32978c4910d2 | |
parent | 33d60a8ce049c623cd4885a49e0a0a80ab11bc74 (diff) | |
download | direvent-f1b64a3ade5b5659f7ddf417c3fdfb4db133aa75.tar.gz direvent-f1b64a3ade5b5659f7ddf417c3fdfb4db133aa75.tar.bz2 |
Fix new functionality on BSD hosts. Some minor fixes.
* src/direvent.c (main): Call watchpoint_gc in the main loop.
* src/direvent.h (watchpoint) <isdir>: New member.
(deliver_ev_create,subwatcher_create): Change signature.
* src/ev_kqueue.c (sysev_add_watch): Always monitor NOTE_DELETE.
(process_event): Special handling for file deletion.
* src/handler.c (handler_list_remove): Return the number of elements
remaining in the list.
* src/hashtab.c (hashtab_remove): Ignore unexisting entries
* src/progman.c (close_fds): Determine the highest used fd by
dup'ing standard input.
* src/watcher.c (watchpoint_install): Always increase refcnt.
(watchpoint_gc_list): New variable.
(watchpoint_gc): Iterate over watchpoint_gc_list deleting
elements from it.
(watchpoint_suspend): Install sentinels only for top-level
watchpoints that were removed.
(sentinel_handler_run): Deliver the create event.
(watchpoint_install_sentinel): Monitor generic create event.
(convert_watcher): Remove.
(subwatcher_create): Remove the isdir parameter.
(watch_subdirs): Exit early if the watchpoint is not a
directory.
(deliver_ev_create): Change signature. Take both directory
and file name as arguments. All uses changes.
* tests/conv.at: Clear expected stderr.
* tests/sent.at: Fix race condition.
-rw-r--r-- | src/direvent.c | 1 | ||||
-rw-r--r-- | src/direvent.h | 9 | ||||
-rw-r--r-- | src/ev_kqueue.c | 21 | ||||
-rw-r--r-- | src/handler.c | 6 | ||||
-rw-r--r-- | src/hashtab.c | 4 | ||||
-rw-r--r-- | src/progman.c | 2 | ||||
-rw-r--r-- | src/watcher.c | 109 | ||||
-rw-r--r-- | tests/conv.at | 2 | ||||
-rw-r--r-- | tests/sent.at | 5 |
9 files changed, 65 insertions, 94 deletions
diff --git a/src/direvent.c b/src/direvent.c index e1775f9..703026c 100644 --- a/src/direvent.c +++ b/src/direvent.c @@ -538,6 +538,7 @@ main(int argc, char **argv) while (!stop && sysev_select() == 0) { process_timeouts(); process_cleanup(0); + watchpoint_gc(); } shutdown_watchers(); diff --git a/src/direvent.h b/src/direvent.h index 416d833..2bb25dc 100644 --- a/src/direvent.h +++ b/src/direvent.h @@ -104,6 +104,7 @@ struct watchpoint { struct watchpoint *parent; /* Points to the parent watcher. NULL for top-level watchers */ char *dirname; /* Pathname being watched */ + int isdir; /* Is it directory */ handler_list_t handler_list; /* List of handlers */ int depth; /* Recursion depth */ char *split_p; /* Points to the deleted directory @@ -265,9 +266,10 @@ char *split_pathname(struct watchpoint *dp, char **dirname); void unsplit_pathname(struct watchpoint *dp); void ev_log(int flags, struct watchpoint *dp); -void deliver_ev_create(struct watchpoint *dp, const char *name); +void deliver_ev_create(struct watchpoint *dp, + const char *dirname, const char *filename); int subwatcher_create(struct watchpoint *parent, const char *dirname, - int isdir, int notify); + int notify); struct handler *handler_itr_first(struct watchpoint *dp, handler_iterator_t *itr); @@ -285,8 +287,7 @@ handler_list_t handler_list_copy(handler_list_t); void handler_list_unref(handler_list_t hlist); void handler_list_append(handler_list_t hlist, struct handler *hp); -void handler_list_remove(handler_list_t hlist, - struct handler *hp); +size_t handler_list_remove(handler_list_t hlist, struct handler *hp); size_t handler_list_size(handler_list_t hlist); struct process *process_lookup(pid_t pid); diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index a002182..14772d8 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -86,7 +86,7 @@ sysev_add_watch(struct watchpoint *wpt, event_mask mask) } wpt->file_mode = st.st_mode; wpt->file_ctime = st.st_ctime; - sysmask = mask.sys_mask; + sysmask = mask.sys_mask | NOTE_DELETE; if (S_ISDIR(st.st_mode) && mask.gen_mask & GENEV_CREATE) sysmask |= NOTE_WRITE; EV_SET(chtab + chcnt, wd, EVFILT_VNODE, @@ -132,7 +132,6 @@ check_created(struct watchpoint *dp) { DIR *dir; struct dirent *ent; - struct handler *h; dir = opendir(dp->dirname); if (!dir) { @@ -172,9 +171,8 @@ check_created(struct watchpoint *dp) a watcher for it. */ } else if (st.st_ctime > dp->file_ctime || !watchpoint_lookup(pathname)) { - deliver_ev_create(dp, ent->d_name); - subwatcher_create(dp, pathname, - S_ISDIR(st.st_mode), 1); + deliver_ev_create(dp, dp->dirname, ent->d_name); + subwatcher_create(dp, pathname, 1); dp->file_ctime = st.st_ctime; } free(pathname); @@ -186,9 +184,6 @@ static void process_event(struct kevent *ep) { struct watchpoint *dp = ep->udata; - struct handler *h; - handler_iterator_t itr; - event_mask m; char *filename, *dirname; if (!dp) { @@ -198,9 +193,10 @@ process_event(struct kevent *ep) ev_log(ep->fflags, dp); - if (S_ISDIR(dp->file_mode)) { + if (S_ISDIR(dp->file_mode) + && !(ep->fflags & (NOTE_DELETE|NOTE_RENAME))) { /* Check if new files have appeared. */ - if (ep->fflags & NOTE_WRITE) + if (ep->fflags & NOTE_WRITE) check_created(dp); return; } @@ -218,7 +214,6 @@ process_event(struct kevent *ep) } } - int sysev_select() { @@ -228,7 +223,7 @@ sysev_select() n = kevent(kq, chtab, chcnt, evtab, chcnt, NULL); if (n == -1) { if (errno == EINTR) { - if (signo == SIGCHLD || signo == SIGALRM) + if (signo == 0 || signo == SIGCHLD || signo == SIGALRM) return 0; diag(LOG_NOTICE, "got signal %d", signo); } @@ -238,7 +233,7 @@ sysev_select() for (i = 0; i < n; i++) process_event(&evtab[i]); - + return 0; } diff --git a/src/handler.c b/src/handler.c index f016829..a4b07d7 100644 --- a/src/handler.c +++ b/src/handler.c @@ -204,7 +204,7 @@ handler_list_append(handler_list_t hlist, struct handler *hp) grecs_list_append(hlist->list, hp); } -void +size_t handler_list_remove(handler_list_t hlist, struct handler *hp) { struct grecs_list_entry *ep; @@ -225,8 +225,6 @@ handler_list_remove(handler_list_t hlist, struct handler *hp) } grecs_list_remove_entry(hlist->list, ep); - if (grecs_list_size(hlist->list) == 0) - /* Remove watchers that don't have handlers */ - watchpoint_gc(); + return grecs_list_size(hlist->list); } diff --git a/src/hashtab.c b/src/hashtab.c index f7eaf18..e9f0295 100644 --- a/src/hashtab.c +++ b/src/hashtab.c @@ -237,11 +237,7 @@ hashtab_remove(struct hashtab *st, void *elt) } if (!entry) -#if 0 return ENOENT; -#else - abort(); -#endif if (st->itr_level) { if (hashent_list_append(&st->list_del, entry)) diff --git a/src/progman.c b/src/progman.c index 10b014a..b96933b 100644 --- a/src/progman.c +++ b/src/progman.c @@ -293,7 +293,7 @@ close_fds(bigfd_set fdset) { int i; - for (i = sysconf(_SC_OPEN_MAX) - 1; i >= 0; i--) { + for (i = dup(0); i >= 0; i--) { if (fdset && BIGFD_ISSET(i, fdset)) continue; close(i); diff --git a/src/watcher.c b/src/watcher.c index 9b6c633..c964022 100644 --- a/src/watcher.c +++ b/src/watcher.c @@ -80,7 +80,7 @@ struct hashtab *nametab; struct watchpoint * watchpoint_install(const char *path, int *pnew) { - struct watchpoint *wpt, wpkey; + struct watchpoint wpkey; struct wpref key; struct wpref *ent; int install = 1; @@ -99,15 +99,16 @@ watchpoint_install(const char *path, int *pnew) key.wpt = &wpkey; ent = hashtab_lookup_or_install(nametab, &key, &install); if (install) { - wpt = ecalloc(1, sizeof(*wpt)); + struct watchpoint *wpt = ecalloc(1, sizeof(*wpt)); wpt->dirname = estrdup(path); wpt->wd = -1; wpt->handler_list = handler_list_create(); - wpt->refcnt++; + wpt->refcnt = 0; ent->wpt = wpt; } if (!ent) abort(); /* FIXME */ + watchpoint_ref(ent->wpt); if (pnew) *pnew = install; return ent->wpt; @@ -128,21 +129,22 @@ watchpoint_install_ptr(struct watchpoint *wpt) return wpt; } -static int -wpref_gc(struct hashent *ent, void *data) +static void +wpref_destroy(void *data) { - struct wpref *wpref = (struct wpref *) ent; - struct watchpoint *wpt = wpref->wpt; - - if (handler_list_size(wpt->handler_list) == 0) - watchpoint_destroy(wpt); - return 0; + struct watchpoint *wpt = data; + watchpoint_destroy(wpt); } +static grecs_list_ptr_t watchpoint_gc_list; + void watchpoint_gc(void) { - hashtab_foreach(nametab, wpref_gc, NULL); + if (watchpoint_gc_list) { + grecs_list_free(watchpoint_gc_list); + watchpoint_gc_list = NULL; + } } struct watchpoint * @@ -183,11 +185,11 @@ watchpoint_destroy(struct watchpoint *wpt) watchpoint_remove(wpt->dirname); } -// FIXME: Perhaps the check for count is not needed after all void watchpoint_suspend(struct watchpoint *wpt) { - watchpoint_install_sentinel(wpt);//FIXME: error checking + if (!wpt->parent) /* A top-level watchpoint */ + watchpoint_install_sentinel(wpt);//FIXME: error checking watchpoint_destroy(wpt); if (hashtab_count(nametab) == 0) { diag(LOG_CRIT, _("no watchers left; exiting now")); @@ -195,42 +197,6 @@ watchpoint_suspend(struct watchpoint *wpt) } } -static int -convert_watcher(struct watchpoint *wpt) -{ - char *dirname; - char *filename; - char *new_dirname; - struct handler *hp; - handler_iterator_t itr; - - filename = split_pathname(wpt, &dirname); - - for_each_handler(wpt, itr, hp) { - if (!filpatlist_is_empty(hp->fnames) - && filpatlist_match(hp->fnames, filename) == 0) { - unsplit_pathname(wpt); - diag(LOG_ERR, - _("can't convert file watcher %s to directory watcher"), - wpt->dirname); - return 1; - } - } - - for_each_handler(wpt, itr, hp) - filpatlist_add_exact(&hp->fnames, filename); - - new_dirname = estrdup(dirname); - unsplit_pathname(wpt); - diag(LOG_NOTICE, - _("file watcher %s converted to directory watcher %s"), - wpt->dirname, new_dirname); - - free(wpt->dirname); - wpt->dirname = new_dirname; - return 0; -} - struct sentinel { struct handler *hp; struct watchpoint *watchpoint; @@ -241,10 +207,19 @@ sentinel_handler_run(struct watchpoint *wp, event_mask *event, const char *dirname, const char *file, void *data) { struct sentinel *sentinel = data; + struct watchpoint *wpt = sentinel->watchpoint; - watchpoint_init(sentinel->watchpoint); - watchpoint_install_ptr(sentinel->watchpoint); - handler_list_remove(wp->handler_list, sentinel->hp); + watchpoint_init(wpt); + watchpoint_install_ptr(wpt); + deliver_ev_create(wpt, dirname, file); + + if (handler_list_remove(wp->handler_list, sentinel->hp) == 0) { + if (!watchpoint_gc_list) { + watchpoint_gc_list = grecs_list_create(); + watchpoint_gc_list->free_entry = wpref_destroy; + } + grecs_list_append(watchpoint_gc_list, wp); + } return 0; } @@ -269,7 +244,7 @@ watchpoint_install_sentinel(struct watchpoint *wpt) filename = split_pathname(wpt, &dirname); sent = watchpoint_install(dirname, NULL); - getevt("CREATE", &ev_mask); + getevt("create", &ev_mask); hp = handler_alloc(ev_mask); hp->run = sentinel_handler_run; hp->free = sentinel_handler_free; @@ -307,9 +282,9 @@ watchpoint_init(struct watchpoint *wpt) wpt->dirname, strerror(errno)); return 1; } - } else if (!S_ISDIR(st.st_mode)) { - convert_watcher(wpt); } + + wpt->isdir = S_ISDIR(st.st_mode); for_each_handler(wpt, itr, hp) { mask.sys_mask |= hp->ev_mask.sys_mask; @@ -332,7 +307,7 @@ static int watch_subdirs(struct watchpoint *parent, int notify); int subwatcher_create(struct watchpoint *parent, const char *dirname, - int isdir, int notify) + int notify) { struct watchpoint *wpt; int inst; @@ -356,12 +331,12 @@ subwatcher_create(struct watchpoint *parent, const char *dirname, return -1; } - return 1 + (isdir ? watch_subdirs(wpt, notify) : 0); + return 1 + watch_subdirs(wpt, notify); } /* Deliver GENEV_CREATE event */ void -deliver_ev_create(struct watchpoint *wp, const char *name) +deliver_ev_create(struct watchpoint *wp, const char *dirname, const char *name) { event_mask m = { GENEV_CREATE, 0 }; struct handler *hp; @@ -369,7 +344,7 @@ deliver_ev_create(struct watchpoint *wp, const char *name) for_each_handler(wp, itr, hp) { if (handler_matches_event(hp, gen, GENEV_CREATE, name)) - hp->run(wp, &m, wp->dirname, name, hp->data); + hp->run(wp, &m, dirname, name, hp->data); } } @@ -410,8 +385,8 @@ check_new_watcher(const char *dir, const char *name) dir, name, strerror(errno)); rc = -1; } else if (S_ISDIR(st.st_mode)) { - deliver_ev_create(parent, name); - rc = subwatcher_create(parent, fname, 1, 1); + deliver_ev_create(parent, parent->dirname, name); + rc = subwatcher_create(parent, fname, 1); } else rc = 0; free(fname); @@ -438,9 +413,13 @@ watch_subdirs(struct watchpoint *parent, int notify) { DIR *dir; struct dirent *ent; - int filemask = sysev_filemask(parent); + int filemask; int total = 0; + if (!parent->isdir) + return 0; + + filemask = sysev_filemask(parent); if (parent->depth) filemask |= S_IFDIR; if (!filemask) @@ -475,10 +454,10 @@ watch_subdirs(struct watchpoint *parent, int notify) } else if (watchpoint_pattern_match(parent, ent->d_name) == 0) { if (notify) - deliver_ev_create(parent, ent->d_name); + deliver_ev_create(parent, parent->dirname, + ent->d_name); if (st.st_mode & filemask) { int rc = subwatcher_create(parent, dirname, - S_ISDIR(st.st_mode), notify); if (rc > 0) total += rc; diff --git a/tests/conv.at b/tests/conv.at index d46f7f6..a9e87f2 100644 --- a/tests/conv.at +++ b/tests/conv.at @@ -52,8 +52,6 @@ DIREVENT_FILE=file DIREVENT_GENEV_CODE=2 DIREVENT_GENEV_NAME=write # End -], -[direvent: [[NOTICE]] file watcher $cwd/file converted to directory watcher $cwd ]) AT_CLEANUP diff --git a/tests/sent.at b/tests/sent.at index 1d8e152..7ad5a61 100644 --- a/tests/sent.at +++ b/tests/sent.at @@ -31,8 +31,11 @@ watcher { command "$TESTDIR/envdump -s -i DIREVENT_FILE=:DIREVENT_GENEV_ -a -f $outfile -k\$self_test_pid"; } ], -[mkdir $cwd/dir +[sleep 1 +mkdir $cwd/dir +sleep 1 mkdir $cwd/dir/sub +sleep 1 echo "bar" > $cwd/dir/sub/bar echo "foo" > $cwd/dir/sub/foo ], |