libresman

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