nuclear@22: /* file modification monitoring with inotify */ nuclear@22: #ifdef __linux__ nuclear@22: #include nuclear@22: #include nuclear@22: #include nuclear@22: #include nuclear@22: #include nuclear@22: #include "filewatch.h" nuclear@22: #include "resman.h" nuclear@22: #include "resman_impl.h" nuclear@22: nuclear@22: static void reload_modified(struct rbnode *node, void *cls); nuclear@22: nuclear@22: int resman_init_file_monitor(struct resman *rman) nuclear@22: { nuclear@22: int fd; nuclear@22: nuclear@22: if((fd = inotify_init()) == -1) { nuclear@22: return -1; nuclear@22: } nuclear@22: /* set non-blocking flag, to allow polling by reading */ nuclear@22: fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); nuclear@22: rman->inotify_fd = fd; nuclear@22: nuclear@22: /* create the fd->resource map */ nuclear@22: rman->nresmap = rb_create(RB_KEY_INT); nuclear@22: /* create the modified set */ nuclear@22: rman->modset = rb_create(RB_KEY_INT); nuclear@22: return 0; nuclear@22: } nuclear@22: nuclear@22: void resman_destroy_file_monitor(struct resman *rman) nuclear@22: { nuclear@22: rb_free(rman->nresmap); nuclear@22: rb_free(rman->modset); nuclear@22: nuclear@22: if(rman->inotify_fd >= 0) { nuclear@22: close(rman->inotify_fd); nuclear@22: rman->inotify_fd = -1; nuclear@22: } nuclear@22: } nuclear@22: nuclear@22: int resman_start_watch(struct resman *rman, struct resource *res) nuclear@22: { nuclear@22: int fd; nuclear@22: nuclear@23: if(res->nfd > 0) { nuclear@23: return 0; /* already started a watch for this resource */ nuclear@23: } nuclear@23: nuclear@22: if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) { nuclear@22: return -1; nuclear@22: } nuclear@22: printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd); nuclear@22: rb_inserti(rman->nresmap, fd, res); nuclear@22: nuclear@22: res->nfd = fd; nuclear@22: return 0; nuclear@22: } nuclear@22: nuclear@22: void resman_stop_watch(struct resman *rman, struct resource *res) nuclear@22: { nuclear@22: if(res->nfd > 0) { nuclear@22: rb_deletei(rman->nresmap, res->nfd); nuclear@22: inotify_rm_watch(rman->inotify_fd, res->nfd); nuclear@22: } nuclear@22: } nuclear@22: nuclear@22: void resman_check_watch(struct resman *rman) nuclear@22: { nuclear@22: char buf[512]; nuclear@22: struct inotify_event *ev; nuclear@22: int sz, evsize; nuclear@22: nuclear@22: while((sz = read(rman->inotify_fd, buf, sizeof buf)) > 0) { nuclear@22: ev = (struct inotify_event*)buf; nuclear@22: while(sz > 0) { nuclear@22: if(ev->mask & IN_MODIFY) { nuclear@22: /* add the file descriptor to the modified set */ nuclear@22: rb_inserti(rman->modset, ev->wd, 0); nuclear@22: } nuclear@22: nuclear@22: evsize = sizeof *ev + ev->len; nuclear@22: sz -= evsize; nuclear@22: ev += evsize; nuclear@22: } nuclear@22: } nuclear@22: nuclear@22: /* for each item in the modified set, start a new job to reload it */ nuclear@22: rb_foreach(rman->modset, reload_modified, rman); nuclear@22: rb_clear(rman->modset); nuclear@22: } nuclear@22: nuclear@22: /* this is called for each item in the modified set (see above) */ nuclear@22: static void reload_modified(struct rbnode *node, void *cls) nuclear@22: { nuclear@22: int watch_fd; nuclear@22: struct resource *res; nuclear@22: struct resman *rman = cls; nuclear@22: nuclear@22: watch_fd = rb_node_keyi(node); nuclear@22: nuclear@22: if(!(res = rb_findi(rman->nresmap, watch_fd))) { nuclear@22: fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n", nuclear@22: __FUNCTION__, watch_fd); nuclear@22: return; nuclear@22: } nuclear@22: assert(watch_fd == res->nfd); nuclear@22: nuclear@22: printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node)); nuclear@22: nuclear@22: tpool_add_work(rman->tpool, res); nuclear@22: } nuclear@22: nuclear@22: #else nuclear@22: int resman_filewatch_linux_silence_empty_file_warning; nuclear@22: #endif /* __linux__ */