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@23
|
47 if(res->nfd > 0) {
|
nuclear@23
|
48 return 0; /* already started a watch for this resource */
|
nuclear@23
|
49 }
|
nuclear@23
|
50
|
nuclear@22
|
51 if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) {
|
nuclear@22
|
52 return -1;
|
nuclear@22
|
53 }
|
nuclear@22
|
54 printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd);
|
nuclear@22
|
55 rb_inserti(rman->nresmap, fd, res);
|
nuclear@22
|
56
|
nuclear@22
|
57 res->nfd = fd;
|
nuclear@22
|
58 return 0;
|
nuclear@22
|
59 }
|
nuclear@22
|
60
|
nuclear@22
|
61 void resman_stop_watch(struct resman *rman, struct resource *res)
|
nuclear@22
|
62 {
|
nuclear@22
|
63 if(res->nfd > 0) {
|
nuclear@22
|
64 rb_deletei(rman->nresmap, res->nfd);
|
nuclear@22
|
65 inotify_rm_watch(rman->inotify_fd, res->nfd);
|
nuclear@22
|
66 }
|
nuclear@22
|
67 }
|
nuclear@22
|
68
|
nuclear@22
|
69 void resman_check_watch(struct resman *rman)
|
nuclear@22
|
70 {
|
nuclear@22
|
71 char buf[512];
|
nuclear@22
|
72 struct inotify_event *ev;
|
nuclear@22
|
73 int sz, evsize;
|
nuclear@22
|
74
|
nuclear@22
|
75 while((sz = read(rman->inotify_fd, buf, sizeof buf)) > 0) {
|
nuclear@22
|
76 ev = (struct inotify_event*)buf;
|
nuclear@22
|
77 while(sz > 0) {
|
nuclear@22
|
78 if(ev->mask & IN_MODIFY) {
|
nuclear@22
|
79 /* add the file descriptor to the modified set */
|
nuclear@22
|
80 rb_inserti(rman->modset, ev->wd, 0);
|
nuclear@22
|
81 }
|
nuclear@22
|
82
|
nuclear@22
|
83 evsize = sizeof *ev + ev->len;
|
nuclear@22
|
84 sz -= evsize;
|
nuclear@22
|
85 ev += evsize;
|
nuclear@22
|
86 }
|
nuclear@22
|
87 }
|
nuclear@22
|
88
|
nuclear@22
|
89 /* for each item in the modified set, start a new job to reload it */
|
nuclear@22
|
90 rb_foreach(rman->modset, reload_modified, rman);
|
nuclear@22
|
91 rb_clear(rman->modset);
|
nuclear@22
|
92 }
|
nuclear@22
|
93
|
nuclear@22
|
94 /* this is called for each item in the modified set (see above) */
|
nuclear@22
|
95 static void reload_modified(struct rbnode *node, void *cls)
|
nuclear@22
|
96 {
|
nuclear@22
|
97 int watch_fd;
|
nuclear@22
|
98 struct resource *res;
|
nuclear@22
|
99 struct resman *rman = cls;
|
nuclear@22
|
100
|
nuclear@22
|
101 watch_fd = rb_node_keyi(node);
|
nuclear@22
|
102
|
nuclear@22
|
103 if(!(res = rb_findi(rman->nresmap, watch_fd))) {
|
nuclear@22
|
104 fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n",
|
nuclear@22
|
105 __FUNCTION__, watch_fd);
|
nuclear@22
|
106 return;
|
nuclear@22
|
107 }
|
nuclear@22
|
108 assert(watch_fd == res->nfd);
|
nuclear@22
|
109
|
nuclear@22
|
110 printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node));
|
nuclear@22
|
111
|
nuclear@22
|
112 tpool_add_work(rman->tpool, res);
|
nuclear@22
|
113 }
|
nuclear@22
|
114
|
nuclear@22
|
115 #else
|
nuclear@22
|
116 int resman_filewatch_linux_silence_empty_file_warning;
|
nuclear@22
|
117 #endif /* __linux__ */
|