libresman

diff src/filewatch_linux.c @ 22:174ddb6bf92a

separated platform-specific filewatch code
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 12 Feb 2014 22:32:30 +0200
parents
children f8e5a1491275
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/filewatch_linux.c	Wed Feb 12 22:32:30 2014 +0200
     1.3 @@ -0,0 +1,113 @@
     1.4 +/* file modification monitoring with inotify */
     1.5 +#ifdef __linux__
     1.6 +#include <stdio.h>
     1.7 +#include <assert.h>
     1.8 +#include <unistd.h>
     1.9 +#include <fcntl.h>
    1.10 +#include <sys/inotify.h>
    1.11 +#include "filewatch.h"
    1.12 +#include "resman.h"
    1.13 +#include "resman_impl.h"
    1.14 +
    1.15 +static void reload_modified(struct rbnode *node, void *cls);
    1.16 +
    1.17 +int resman_init_file_monitor(struct resman *rman)
    1.18 +{
    1.19 +	int fd;
    1.20 +
    1.21 +	if((fd = inotify_init()) == -1) {
    1.22 +		return -1;
    1.23 +	}
    1.24 +	/* set non-blocking flag, to allow polling by reading */
    1.25 +	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
    1.26 +	rman->inotify_fd = fd;
    1.27 +
    1.28 +	/* create the fd->resource map */
    1.29 +	rman->nresmap = rb_create(RB_KEY_INT);
    1.30 +	/* create the modified set */
    1.31 +	rman->modset = rb_create(RB_KEY_INT);
    1.32 +	return 0;
    1.33 +}
    1.34 +
    1.35 +void resman_destroy_file_monitor(struct resman *rman)
    1.36 +{
    1.37 +	rb_free(rman->nresmap);
    1.38 +	rb_free(rman->modset);
    1.39 +
    1.40 +	if(rman->inotify_fd >= 0) {
    1.41 +		close(rman->inotify_fd);
    1.42 +		rman->inotify_fd = -1;
    1.43 +	}
    1.44 +}
    1.45 +
    1.46 +int resman_start_watch(struct resman *rman, struct resource *res)
    1.47 +{
    1.48 +	int fd;
    1.49 +
    1.50 +	if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) {
    1.51 +		return -1;
    1.52 +	}
    1.53 +	printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd);
    1.54 +	rb_inserti(rman->nresmap, fd, res);
    1.55 +
    1.56 +	res->nfd = fd;
    1.57 +	return 0;
    1.58 +}
    1.59 +
    1.60 +void resman_stop_watch(struct resman *rman, struct resource *res)
    1.61 +{
    1.62 +	if(res->nfd > 0) {
    1.63 +		rb_deletei(rman->nresmap, res->nfd);
    1.64 +		inotify_rm_watch(rman->inotify_fd, res->nfd);
    1.65 +	}
    1.66 +}
    1.67 +
    1.68 +void resman_check_watch(struct resman *rman)
    1.69 +{
    1.70 +	char buf[512];
    1.71 +	struct inotify_event *ev;
    1.72 +	int sz, evsize;
    1.73 +
    1.74 +	while((sz = read(rman->inotify_fd, buf, sizeof buf)) > 0) {
    1.75 +		ev = (struct inotify_event*)buf;
    1.76 +		while(sz > 0) {
    1.77 +			if(ev->mask & IN_MODIFY) {
    1.78 +				/* add the file descriptor to the modified set */
    1.79 +				rb_inserti(rman->modset, ev->wd, 0);
    1.80 +			}
    1.81 +
    1.82 +			evsize = sizeof *ev + ev->len;
    1.83 +			sz -= evsize;
    1.84 +			ev += evsize;
    1.85 +		}
    1.86 +	}
    1.87 +
    1.88 +	/* for each item in the modified set, start a new job to reload it */
    1.89 +	rb_foreach(rman->modset, reload_modified, rman);
    1.90 +	rb_clear(rman->modset);
    1.91 +}
    1.92 +
    1.93 +/* this is called for each item in the modified set (see above) */
    1.94 +static void reload_modified(struct rbnode *node, void *cls)
    1.95 +{
    1.96 +	int watch_fd;
    1.97 +	struct resource *res;
    1.98 +	struct resman *rman = cls;
    1.99 +
   1.100 +	watch_fd = rb_node_keyi(node);
   1.101 +
   1.102 +	if(!(res = rb_findi(rman->nresmap, watch_fd))) {
   1.103 +		fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n",
   1.104 +				__FUNCTION__, watch_fd);
   1.105 +		return;
   1.106 +	}
   1.107 +	assert(watch_fd == res->nfd);
   1.108 +
   1.109 +	printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node));
   1.110 +
   1.111 +	tpool_add_work(rman->tpool, res);
   1.112 +}
   1.113 +
   1.114 +#else
   1.115 +int resman_filewatch_linux_silence_empty_file_warning;
   1.116 +#endif	/* __linux__ */