libresman

annotate 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
rev   line source
nuclear@22 1 /* file modification monitoring with inotify */
nuclear@22 2 #ifdef __linux__
nuclear@22 3 #include <stdio.h>
nuclear@22 4 #include <assert.h>
nuclear@22 5 #include <unistd.h>
nuclear@22 6 #include <fcntl.h>
nuclear@22 7 #include <sys/inotify.h>
nuclear@22 8 #include "filewatch.h"
nuclear@22 9 #include "resman.h"
nuclear@22 10 #include "resman_impl.h"
nuclear@22 11
nuclear@22 12 static void reload_modified(struct rbnode *node, void *cls);
nuclear@22 13
nuclear@22 14 int resman_init_file_monitor(struct resman *rman)
nuclear@22 15 {
nuclear@22 16 int fd;
nuclear@22 17
nuclear@22 18 if((fd = inotify_init()) == -1) {
nuclear@22 19 return -1;
nuclear@22 20 }
nuclear@22 21 /* set non-blocking flag, to allow polling by reading */
nuclear@22 22 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
nuclear@22 23 rman->inotify_fd = fd;
nuclear@22 24
nuclear@22 25 /* create the fd->resource map */
nuclear@22 26 rman->nresmap = rb_create(RB_KEY_INT);
nuclear@22 27 /* create the modified set */
nuclear@22 28 rman->modset = rb_create(RB_KEY_INT);
nuclear@22 29 return 0;
nuclear@22 30 }
nuclear@22 31
nuclear@22 32 void resman_destroy_file_monitor(struct resman *rman)
nuclear@22 33 {
nuclear@22 34 rb_free(rman->nresmap);
nuclear@22 35 rb_free(rman->modset);
nuclear@22 36
nuclear@22 37 if(rman->inotify_fd >= 0) {
nuclear@22 38 close(rman->inotify_fd);
nuclear@22 39 rman->inotify_fd = -1;
nuclear@22 40 }
nuclear@22 41 }
nuclear@22 42
nuclear@22 43 int resman_start_watch(struct resman *rman, struct resource *res)
nuclear@22 44 {
nuclear@22 45 int fd;
nuclear@22 46
nuclear@22 47 if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) {
nuclear@22 48 return -1;
nuclear@22 49 }
nuclear@22 50 printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd);
nuclear@22 51 rb_inserti(rman->nresmap, fd, res);
nuclear@22 52
nuclear@22 53 res->nfd = fd;
nuclear@22 54 return 0;
nuclear@22 55 }
nuclear@22 56
nuclear@22 57 void resman_stop_watch(struct resman *rman, struct resource *res)
nuclear@22 58 {
nuclear@22 59 if(res->nfd > 0) {
nuclear@22 60 rb_deletei(rman->nresmap, res->nfd);
nuclear@22 61 inotify_rm_watch(rman->inotify_fd, res->nfd);
nuclear@22 62 }
nuclear@22 63 }
nuclear@22 64
nuclear@22 65 void resman_check_watch(struct resman *rman)
nuclear@22 66 {
nuclear@22 67 char buf[512];
nuclear@22 68 struct inotify_event *ev;
nuclear@22 69 int sz, evsize;
nuclear@22 70
nuclear@22 71 while((sz = read(rman->inotify_fd, buf, sizeof buf)) > 0) {
nuclear@22 72 ev = (struct inotify_event*)buf;
nuclear@22 73 while(sz > 0) {
nuclear@22 74 if(ev->mask & IN_MODIFY) {
nuclear@22 75 /* add the file descriptor to the modified set */
nuclear@22 76 rb_inserti(rman->modset, ev->wd, 0);
nuclear@22 77 }
nuclear@22 78
nuclear@22 79 evsize = sizeof *ev + ev->len;
nuclear@22 80 sz -= evsize;
nuclear@22 81 ev += evsize;
nuclear@22 82 }
nuclear@22 83 }
nuclear@22 84
nuclear@22 85 /* for each item in the modified set, start a new job to reload it */
nuclear@22 86 rb_foreach(rman->modset, reload_modified, rman);
nuclear@22 87 rb_clear(rman->modset);
nuclear@22 88 }
nuclear@22 89
nuclear@22 90 /* this is called for each item in the modified set (see above) */
nuclear@22 91 static void reload_modified(struct rbnode *node, void *cls)
nuclear@22 92 {
nuclear@22 93 int watch_fd;
nuclear@22 94 struct resource *res;
nuclear@22 95 struct resman *rman = cls;
nuclear@22 96
nuclear@22 97 watch_fd = rb_node_keyi(node);
nuclear@22 98
nuclear@22 99 if(!(res = rb_findi(rman->nresmap, watch_fd))) {
nuclear@22 100 fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n",
nuclear@22 101 __FUNCTION__, watch_fd);
nuclear@22 102 return;
nuclear@22 103 }
nuclear@22 104 assert(watch_fd == res->nfd);
nuclear@22 105
nuclear@22 106 printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node));
nuclear@22 107
nuclear@22 108 tpool_add_work(rman->tpool, res);
nuclear@22 109 }
nuclear@22 110
nuclear@22 111 #else
nuclear@22 112 int resman_filewatch_linux_silence_empty_file_warning;
nuclear@22 113 #endif /* __linux__ */