aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2016-08-25 12:43:34 +0300
committerSergey Poznyakoff <gray@gnu.org>2016-08-25 22:29:47 +0300
commitf1b64a3ade5b5659f7ddf417c3fdfb4db133aa75 (patch)
treefda58c3e3116501b816cbc32a74d32978c4910d2
parent33d60a8ce049c623cd4885a49e0a0a80ab11bc74 (diff)
downloaddirevent-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.c1
-rw-r--r--src/direvent.h9
-rw-r--r--src/ev_kqueue.c21
-rw-r--r--src/handler.c6
-rw-r--r--src/hashtab.c4
-rw-r--r--src/progman.c2
-rw-r--r--src/watcher.c109
-rw-r--r--tests/conv.at2
-rw-r--r--tests/sent.at5
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
],

Return to:

Send suggestions and report system problems to the System administrator.