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__ */
|