Annotation of /trunk/fam/patches/fam-2.7.0-dnotify.patch
Parent Directory | Revision Log
Revision 144 -
(hide annotations)
(download)
Tue May 8 20:06:05 2007 UTC (17 years, 4 months ago) by niro
File size: 26419 byte(s)
Tue May 8 20:06:05 2007 UTC (17 years, 4 months ago) by niro
File size: 26419 byte(s)
-import
1 | niro | 144 | --- fam-2.7.0/src/DNotify.c++ 2004-01-30 00:00:00.000000000 +0100 |
2 | +++ fam-2.7.0.dnotify/src/DNotify.c++ 2004-01-30 00:00:00.000000000 +0100 | ||
3 | @@ -0,0 +1,582 @@ | ||
4 | +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved. | ||
5 | +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. | ||
6 | +// | ||
7 | +// This program is free software; you can redistribute it and/or modify it | ||
8 | +// under the terms of version 2 of the GNU General Public License as | ||
9 | +// published by the Free Software Foundation. | ||
10 | +// | ||
11 | +// This program is distributed in the hope that it would be useful, but | ||
12 | +// WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any | ||
14 | +// license provided herein, whether implied or otherwise, is limited to | ||
15 | +// this program in accordance with the express provisions of the GNU | ||
16 | +// General Public License. Patent licenses, if any, provided herein do not | ||
17 | +// apply to combinations of this program with other product or programs, or | ||
18 | +// any other product whatsoever. This program is distributed without any | ||
19 | +// warranty that the program is delivered free of the rightful claim of any | ||
20 | +// third person by way of infringement or the like. See the GNU General | ||
21 | +// Public License for more details. | ||
22 | +// | ||
23 | +// You should have received a copy of the GNU General Public License along | ||
24 | +// with this program; if not, write the Free Software Foundation, Inc., 59 | ||
25 | +// Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
26 | + | ||
27 | +#define _GNU_SOURCE | ||
28 | +#include <fcntl.h> | ||
29 | + | ||
30 | +#include <string.h> | ||
31 | +#include <signal.h> | ||
32 | +#include <stdio.h> | ||
33 | +#include <unistd.h> | ||
34 | +#include <sys/types.h> | ||
35 | +#include <sys/stat.h> | ||
36 | +#include <libgen.h> | ||
37 | + | ||
38 | +#include "DNotify.h" | ||
39 | + | ||
40 | +#include "Interest.h" | ||
41 | +#include "Log.h" | ||
42 | +#include "Scheduler.h" | ||
43 | +#include <memory> | ||
44 | + | ||
45 | + | ||
46 | +int DNotify::pipe_write_fd = -2; | ||
47 | +int DNotify::pipe_read_fd = -2; | ||
48 | +volatile sig_atomic_t DNotify::queue_overflowed = 0; | ||
49 | +volatile sig_atomic_t DNotify::queue_changed = 0; | ||
50 | +int DNotify::change_queue[QUEUESIZE]; | ||
51 | +volatile int DNotify::queue_head = 0; // Only modified by read handler | ||
52 | +volatile int DNotify::queue_tail = 0; // Only modified by signal handler | ||
53 | +DNotify::EventHandler DNotify::ehandler; | ||
54 | + | ||
55 | +DNotify::DirWatch *DNotify::dir_hash[DIR_HASHSIZE]; | ||
56 | +DNotify::FileWatch *DNotify::file_hash[FILE_HASHSIZE]; | ||
57 | + | ||
58 | +struct DNotify::FileWatch | ||
59 | +{ | ||
60 | + DirWatch *dir_watch; | ||
61 | + dev_t file_dev; | ||
62 | + ino_t file_ino; | ||
63 | + FileWatch *next; // The DirWatch.watches list | ||
64 | + FileWatch *hash_link; | ||
65 | +}; | ||
66 | + | ||
67 | +struct DNotify::DirWatch | ||
68 | +{ | ||
69 | + int fd; | ||
70 | + dev_t dir_dev; | ||
71 | + ino_t dir_ino; | ||
72 | + | ||
73 | + DirWatch *hash_link; | ||
74 | + FileWatch *watches; | ||
75 | +}; | ||
76 | + | ||
77 | +struct DNotify::ChangeEventData | ||
78 | +{ | ||
79 | + dev_t file_dev; | ||
80 | + ino_t file_ino; | ||
81 | +}; | ||
82 | + | ||
83 | +DNotify::DNotify(EventHandler h) | ||
84 | +{ | ||
85 | + assert(ehandler == NULL); | ||
86 | + ehandler = h; | ||
87 | +} | ||
88 | + | ||
89 | +DNotify::~DNotify() | ||
90 | +{ | ||
91 | + if (pipe_read_fd >= 0) | ||
92 | + { | ||
93 | + // Tell the scheduler. | ||
94 | + | ||
95 | + (void) Scheduler::remove_read_handler(pipe_read_fd); | ||
96 | + | ||
97 | + // Close the pipe. | ||
98 | + | ||
99 | + if (close(pipe_read_fd) < 0) | ||
100 | + Log::perror("can't pipe read end"); | ||
101 | + else | ||
102 | + Log::debug("closed pipe read end"); | ||
103 | + | ||
104 | + if (close(pipe_write_fd) < 0) | ||
105 | + Log::perror("can't pipe write end"); | ||
106 | + else | ||
107 | + Log::debug("closed pipe write end"); | ||
108 | + pipe_read_fd = -1; | ||
109 | + } | ||
110 | + ehandler = NULL; | ||
111 | +} | ||
112 | + | ||
113 | +void | ||
114 | +DNotify::overflow_signal_handler(int sig, siginfo_t *si, void *data) | ||
115 | +{ | ||
116 | + char c = 'x'; | ||
117 | + | ||
118 | + { | ||
119 | + char *str = "*************** overflow sigqueue ***********************\n"; | ||
120 | + write (STDERR_FILENO, str, strlen(str)); | ||
121 | + } | ||
122 | + | ||
123 | + if (!queue_overflowed) | ||
124 | + { | ||
125 | + queue_overflowed = 1; | ||
126 | + // Trigger the read handler | ||
127 | + write(pipe_write_fd, &c, 1); | ||
128 | + } | ||
129 | +} | ||
130 | + | ||
131 | +void | ||
132 | +DNotify::signal_handler(int sig, siginfo_t *si, void *data) | ||
133 | +{ | ||
134 | + int left; | ||
135 | + char c = 'x'; | ||
136 | + | ||
137 | + if (queue_head <= queue_tail) | ||
138 | + left = (QUEUESIZE + queue_head) - queue_tail; | ||
139 | + else | ||
140 | + left = queue_head - queue_tail; | ||
141 | + | ||
142 | + // Must leave at least one item unused to see difference | ||
143 | + // Betweeen empty and full | ||
144 | + if (left <= 1) | ||
145 | + { | ||
146 | + queue_overflowed = 1; | ||
147 | + { | ||
148 | + char *str = "*************** overflow famqueue ****************\n"; | ||
149 | + write (STDERR_FILENO, str, strlen(str)); | ||
150 | + } | ||
151 | + } | ||
152 | + else | ||
153 | + { | ||
154 | + change_queue[queue_tail] = si->si_fd; | ||
155 | + queue_tail = (queue_tail + 1) % QUEUESIZE; | ||
156 | + } | ||
157 | + | ||
158 | + if (!queue_changed) | ||
159 | + { | ||
160 | + queue_changed = 1; | ||
161 | + // Trigger the read handler | ||
162 | + write(pipe_write_fd, &c, 1); | ||
163 | + } | ||
164 | +} | ||
165 | + | ||
166 | +bool | ||
167 | +DNotify::is_active() | ||
168 | +{ | ||
169 | + if (pipe_read_fd == -2) | ||
170 | + { | ||
171 | + int filedes[2]; | ||
172 | + int res; | ||
173 | + | ||
174 | + res = pipe (filedes); | ||
175 | + if (res >= 0) | ||
176 | + { Log::debug("opened pipe"); | ||
177 | + pipe_read_fd = filedes[0]; | ||
178 | + pipe_write_fd = filedes[1]; | ||
179 | + | ||
180 | + // Setup signal handler: | ||
181 | + struct sigaction act; | ||
182 | + | ||
183 | + act.sa_sigaction = signal_handler; | ||
184 | + sigemptyset(&act.sa_mask); | ||
185 | + act.sa_flags = SA_SIGINFO; | ||
186 | + sigaction(SIGRTMIN, &act, NULL); | ||
187 | + | ||
188 | + // When the RT queue overflows we get a SIGIO | ||
189 | + act.sa_sigaction = overflow_signal_handler; | ||
190 | + sigemptyset(&act.sa_mask); | ||
191 | + sigaction(SIGIO, &act, NULL); | ||
192 | + | ||
193 | + (void) Scheduler::install_read_handler(pipe_read_fd, read_handler, NULL); | ||
194 | + } | ||
195 | + } | ||
196 | + return pipe_read_fd >= 0; | ||
197 | +} | ||
198 | + | ||
199 | +DNotify::DirWatch * | ||
200 | +DNotify::lookup_dirwatch (int fd) | ||
201 | +{ | ||
202 | + DirWatch **p; | ||
203 | + DirWatch *w; | ||
204 | + | ||
205 | + p = dir_hashchain (fd); | ||
206 | + | ||
207 | + while (*p) | ||
208 | + { | ||
209 | + w = *p; | ||
210 | + | ||
211 | + if (w->fd == fd) | ||
212 | + return w; | ||
213 | + | ||
214 | + p = &w->hash_link; | ||
215 | + } | ||
216 | + | ||
217 | + return *p; | ||
218 | +} | ||
219 | + | ||
220 | +// This colud be made faster by using another hash table. | ||
221 | +// But it's not that bad, since it is only used by express/revoke | ||
222 | +DNotify::DirWatch * | ||
223 | +DNotify::lookup_dirwatch (dev_t dir_dev, ino_t dir_ino) | ||
224 | +{ | ||
225 | + DirWatch *p; | ||
226 | + int i; | ||
227 | + | ||
228 | + for (i=0;i<DIR_HASHSIZE;i++) | ||
229 | + { | ||
230 | + p = dir_hash[i]; | ||
231 | + | ||
232 | + while (p) | ||
233 | + { | ||
234 | + if (p->dir_dev == dir_dev && p->dir_ino == dir_ino) | ||
235 | + return p; | ||
236 | + | ||
237 | + p = p->hash_link; | ||
238 | + } | ||
239 | + } | ||
240 | + | ||
241 | + return NULL; | ||
242 | +} | ||
243 | + | ||
244 | +DNotify::FileWatch * | ||
245 | +DNotify::lookup_filewatch (dev_t dev, ino_t ino) | ||
246 | +{ | ||
247 | + FileWatch **p; | ||
248 | + FileWatch *w; | ||
249 | + | ||
250 | + p = file_hashchain (dev, ino); | ||
251 | + | ||
252 | + while (*p) | ||
253 | + { | ||
254 | + w = *p; | ||
255 | + | ||
256 | + if (w->file_dev == dev && w->file_ino == ino) | ||
257 | + return w; | ||
258 | + | ||
259 | + p = &w->hash_link; | ||
260 | + } | ||
261 | + | ||
262 | + return *p; | ||
263 | +} | ||
264 | + | ||
265 | +// Make sure w is not already in the hash table before calling | ||
266 | +// this function. | ||
267 | +void | ||
268 | +DNotify::hash_dirwatch(DirWatch *w) | ||
269 | +{ | ||
270 | + DirWatch **p; | ||
271 | + p = dir_hashchain (w->fd); | ||
272 | + w->hash_link = *p; | ||
273 | + *p = w; | ||
274 | +} | ||
275 | + | ||
276 | +// Make sure w is not already in the hash table before calling | ||
277 | +// this function. | ||
278 | +void | ||
279 | +DNotify::hash_filewatch(FileWatch *w) | ||
280 | +{ | ||
281 | + FileWatch **p; | ||
282 | + p = file_hashchain (w->file_dev, w->file_ino); | ||
283 | + w->hash_link = *p; | ||
284 | + *p = w; | ||
285 | +} | ||
286 | + | ||
287 | +void | ||
288 | +DNotify::unhash_dirwatch(DirWatch *w) | ||
289 | +{ | ||
290 | + DirWatch **p; | ||
291 | + | ||
292 | + p = dir_hashchain (w->fd); | ||
293 | + | ||
294 | + while (*p) | ||
295 | + { | ||
296 | + if (*p == w) | ||
297 | + { | ||
298 | + *p = w->hash_link; | ||
299 | + break; | ||
300 | + } | ||
301 | + p = &(*p)->hash_link; | ||
302 | + } | ||
303 | + w->hash_link = NULL; | ||
304 | +} | ||
305 | + | ||
306 | +void | ||
307 | +DNotify::unhash_filewatch(FileWatch *w) | ||
308 | +{ | ||
309 | + FileWatch **p; | ||
310 | + | ||
311 | + p = file_hashchain (w->file_dev, w->file_ino); | ||
312 | + | ||
313 | + while (*p) | ||
314 | + { | ||
315 | + if (*p == w) | ||
316 | + { | ||
317 | + *p = w->hash_link; | ||
318 | + break; | ||
319 | + } | ||
320 | + p = &(*p)->hash_link; | ||
321 | + } | ||
322 | + w->hash_link = NULL; | ||
323 | +} | ||
324 | + | ||
325 | +DNotify::Status | ||
326 | +DNotify::watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino) | ||
327 | +{ | ||
328 | + struct stat stat; | ||
329 | + dev_t dir_dev; | ||
330 | + ino_t dir_ino; | ||
331 | + DirWatch *dwatch; | ||
332 | + FileWatch *fw; | ||
333 | + | ||
334 | + if (lstat (notify_dir, &stat) == -1) | ||
335 | + return BAD; | ||
336 | + | ||
337 | + dwatch = lookup_dirwatch(stat.st_dev, stat.st_ino); | ||
338 | + if (!dwatch) | ||
339 | + { | ||
340 | + Log::debug ("New DirWatch for %s (%x %x)\n", | ||
341 | + notify_dir, (int)stat.st_dev, (int)stat.st_ino); | ||
342 | + dwatch = new DirWatch; | ||
343 | + dwatch->watches = NULL; | ||
344 | + dwatch->hash_link = NULL; | ||
345 | + dwatch->dir_dev = stat.st_dev; | ||
346 | + dwatch->dir_ino = stat.st_ino; | ||
347 | + | ||
348 | + dwatch->fd = open(notify_dir, O_RDONLY); | ||
349 | + fcntl (dwatch->fd, F_SETSIG, SIGRTMIN); | ||
350 | + if (fcntl (dwatch->fd, F_NOTIFY, | ||
351 | + (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB) | ||
352 | + | DN_MULTISHOT) == -1) { | ||
353 | + return BAD; | ||
354 | + } | ||
355 | + hash_dirwatch (dwatch); | ||
356 | + } | ||
357 | + | ||
358 | + fw = lookup_filewatch (file_dev, file_ino); | ||
359 | + if (fw && fw->dir_watch == dwatch) | ||
360 | + return OK; | ||
361 | + | ||
362 | + // No old FileWatch, need to add one: | ||
363 | + Log::debug("New FileWatch for %x %x\n", (int)file_dev, (int)file_ino); | ||
364 | + fw = new FileWatch; | ||
365 | + fw->next = dwatch->watches; | ||
366 | + dwatch->watches = fw; | ||
367 | + fw->file_dev = file_dev; | ||
368 | + fw->file_ino = file_ino; | ||
369 | + fw->dir_watch = dwatch; | ||
370 | + hash_filewatch(fw); | ||
371 | + return OK; | ||
372 | +} | ||
373 | + | ||
374 | +char * | ||
375 | +dirname_dup (const char *name) | ||
376 | +{ | ||
377 | + char *copy = strdup(name); | ||
378 | + char *res = dirname(copy); | ||
379 | + res = strdup(res); | ||
380 | + free (copy); | ||
381 | + return res; | ||
382 | +} | ||
383 | + | ||
384 | +DNotify::Status | ||
385 | +DNotify::express(const char *name, struct stat *status) | ||
386 | +{ | ||
387 | + struct stat stat; | ||
388 | + char *notify_dir; | ||
389 | + int res; | ||
390 | + Status s; | ||
391 | + dev_t dev; | ||
392 | + ino_t ino; | ||
393 | + | ||
394 | + Log::debug("express() name: %s\n", name); | ||
395 | + | ||
396 | + if (!is_active()) | ||
397 | + return BAD; | ||
398 | + | ||
399 | + if (::lstat (name, &stat) == -1) | ||
400 | + return BAD; | ||
401 | + | ||
402 | + dev = stat.st_dev; | ||
403 | + ino = stat.st_ino; | ||
404 | + | ||
405 | + if ((stat.st_mode & S_IFMT) != S_IFDIR) | ||
406 | + notify_dir = dirname_dup (name); | ||
407 | + else | ||
408 | + notify_dir = (char *)name; | ||
409 | + | ||
410 | + s = watch_dir (notify_dir, dev, ino); | ||
411 | + if (notify_dir != name) | ||
412 | + free (notify_dir); | ||
413 | + if (s) | ||
414 | + return s; | ||
415 | + | ||
416 | + // Check for a race condition; if someone removed or changed the | ||
417 | + // file at the same time that we are expressing interest in it, | ||
418 | + // revoke the interest so we don't get notifications about changes | ||
419 | + // to a recycled inode that we don't otherwise care about. | ||
420 | + // | ||
421 | + struct stat st; | ||
422 | + if (status == NULL) { | ||
423 | + status = &st; | ||
424 | + } | ||
425 | + if (::lstat(name, status) == -1) { | ||
426 | + Log::perror("stat on \"%s\" failed", name); | ||
427 | + revoke(name, stat.st_dev, stat.st_ino); | ||
428 | + return BAD; | ||
429 | + } | ||
430 | + if (status->st_dev != stat.st_dev | ||
431 | + || status->st_ino != stat.st_ino) { | ||
432 | + Log::error("File \"%s\" changed between express and stat", | ||
433 | + name); | ||
434 | + revoke(name, stat.st_dev, stat.st_ino); | ||
435 | + return BAD; | ||
436 | + } | ||
437 | + | ||
438 | + Log::debug("told dnotify to monitor \"%s\" = dev %d/%d, ino %d", name, | ||
439 | + major(status->st_dev), minor(status->st_dev), | ||
440 | + status->st_ino); | ||
441 | + return OK; | ||
442 | +} | ||
443 | + | ||
444 | +DNotify::Status | ||
445 | +DNotify::revoke(const char *name, dev_t dev, ino_t ino) | ||
446 | +{ | ||
447 | + FileWatch *fwatch; | ||
448 | + DirWatch *dwatch; | ||
449 | + | ||
450 | + Log::debug("revoke() name: %s, dev: %x, ino: %x\n", name, dev, ino); | ||
451 | + | ||
452 | + if (!is_active()) | ||
453 | + return BAD; | ||
454 | + | ||
455 | + // Lookup FileWatch by dev:ino, and its DirWatch. | ||
456 | + fwatch = lookup_filewatch (dev, ino); | ||
457 | + if (fwatch == NULL) | ||
458 | + return BAD; | ||
459 | + | ||
460 | + dwatch = fwatch->dir_watch; | ||
461 | + | ||
462 | + // delete FileWatch, if last FileWatch: close fd, delete DirWatch | ||
463 | + Log::debug ("Destroying FileWatch for (%x %x)\n", | ||
464 | + (int)fwatch->file_dev, (int)fwatch->file_ino); | ||
465 | + FileWatch **p; | ||
466 | + for (p=&dwatch->watches; *p; p=&(*p)->next) | ||
467 | + { | ||
468 | + if (*p == fwatch) | ||
469 | + { | ||
470 | + *p = (*p)->next; | ||
471 | + break; | ||
472 | + } | ||
473 | + } | ||
474 | + unhash_filewatch(fwatch); | ||
475 | + delete fwatch; | ||
476 | + if (dwatch->watches == NULL) | ||
477 | + { | ||
478 | + Log::debug ("Destroying DirWatch for (%x %x)\n", | ||
479 | + (int)dwatch->dir_dev, (int)dwatch->dir_ino); | ||
480 | + close(dwatch->fd); | ||
481 | + unhash_dirwatch(dwatch); | ||
482 | + delete dwatch; | ||
483 | + } | ||
484 | + | ||
485 | + return OK; | ||
486 | +} | ||
487 | + | ||
488 | + | ||
489 | +void | ||
490 | +DNotify::all_watches_changed(void) | ||
491 | +{ | ||
492 | + int i; | ||
493 | + FileWatch *fw; | ||
494 | + | ||
495 | + for (i=0; i<FILE_HASHSIZE; i++) | ||
496 | + { | ||
497 | + fw = file_hash[i]; | ||
498 | + while (fw) | ||
499 | + { | ||
500 | + (*ehandler)(fw->file_dev, fw->file_ino, CHANGE); | ||
501 | + | ||
502 | + fw = fw->hash_link; | ||
503 | + } | ||
504 | + } | ||
505 | +} | ||
506 | + | ||
507 | + | ||
508 | +void | ||
509 | +DNotify::read_handler(int fd, void *) | ||
510 | +{ | ||
511 | + static char readbuf[5000]; | ||
512 | + DirWatch *dw; | ||
513 | + FileWatch *fw; | ||
514 | + int snap_queue_tail; | ||
515 | + int last_fd; | ||
516 | + | ||
517 | + int rc = read(fd, readbuf, sizeof readbuf); | ||
518 | + queue_changed = 0; | ||
519 | + if (rc < 0) | ||
520 | + Log::perror("pipe read"); | ||
521 | + else if (queue_overflowed) | ||
522 | + { | ||
523 | + // There is a *slight* race condition here. Between reading | ||
524 | + // the queue_overflow flag and resetting it. But it doesn't | ||
525 | + // matter, since I'm gonna handle the overflow after reseting | ||
526 | + // anyway. | ||
527 | + queue_overflowed = false; | ||
528 | + | ||
529 | + // We're soon gonna check all watches anyway, so | ||
530 | + // get rid of the current queue | ||
531 | + queue_head = queue_tail; | ||
532 | + | ||
533 | + all_watches_changed (); | ||
534 | + } | ||
535 | + else | ||
536 | + { | ||
537 | + // Don't read events that happen later than | ||
538 | + // the initial read. (Otherwise skipping fd's | ||
539 | + // might miss some changes). | ||
540 | + snap_queue_tail = queue_tail; | ||
541 | + last_fd = -1; | ||
542 | + while (queue_head != snap_queue_tail) | ||
543 | + { | ||
544 | + fd = change_queue[queue_head]; | ||
545 | + queue_head = (queue_head + 1) % QUEUESIZE; | ||
546 | + | ||
547 | + // Skip multiple changes to the same fd | ||
548 | + if (fd != last_fd) | ||
549 | + { | ||
550 | + dw = lookup_dirwatch (fd); | ||
551 | + if (dw) | ||
552 | + { | ||
553 | + int n_watches, i; | ||
554 | + ChangeEventData *data; | ||
555 | + | ||
556 | + Log::debug("dnotify said dev %d/%d, ino %ld changed", | ||
557 | + major(dw->dir_dev), minor(dw->dir_dev), dw->dir_ino); | ||
558 | + | ||
559 | + n_watches = 0; | ||
560 | + for (fw=dw->watches; fw; fw=fw->next) | ||
561 | + n_watches++; | ||
562 | + | ||
563 | + data = new ChangeEventData[n_watches]; | ||
564 | + | ||
565 | + i = 0; | ||
566 | + for (fw=dw->watches; fw; fw=fw->next) | ||
567 | + { | ||
568 | + data[i].file_dev = fw->file_dev; | ||
569 | + data[i].file_ino = fw->file_ino; | ||
570 | + i++; | ||
571 | + } | ||
572 | + | ||
573 | + for (i = 0; i < n_watches; i++) | ||
574 | + { | ||
575 | + (*ehandler)(data[i].file_dev, data[i].file_ino, CHANGE); | ||
576 | + } | ||
577 | + | ||
578 | + delete[] data; | ||
579 | + } | ||
580 | + } | ||
581 | + last_fd = fd; | ||
582 | + } | ||
583 | + } | ||
584 | +} | ||
585 | + | ||
586 | --- fam-2.7.0/src/DNotify.h 2004-01-30 00:00:00.000000000 +0100 | ||
587 | +++ fam-2.7.0.dnotify/src/DNotify.h 2004-01-30 00:00:00.000000000 +0100 | ||
588 | @@ -0,0 +1,98 @@ | ||
589 | +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved. | ||
590 | +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. | ||
591 | +// | ||
592 | +// This program is free software; you can redistribute it and/or modify it | ||
593 | +// under the terms of version 2 of the GNU General Public License as | ||
594 | +// published by the Free Software Foundation. | ||
595 | +// | ||
596 | +// This program is distributed in the hope that it would be useful, but | ||
597 | +// WITHOUT ANY WARRANTY; without even the implied warranty of | ||
598 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any | ||
599 | +// license provided herein, whether implied or otherwise, is limited to | ||
600 | +// this program in accordance with the express provisions of the GNU | ||
601 | +// General Public License. Patent licenses, if any, provided herein do not | ||
602 | +// apply to combinations of this program with other product or programs, or | ||
603 | +// any other product whatsoever. This program is distributed without any | ||
604 | +// warranty that the program is delivered free of the rightful claim of any | ||
605 | +// third person by way of infringement or the like. See the GNU General | ||
606 | +// Public License for more details. | ||
607 | +// | ||
608 | +// You should have received a copy of the GNU General Public License along | ||
609 | +// with this program; if not, write the Free Software Foundation, Inc., 59 | ||
610 | +// Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
611 | + | ||
612 | +#ifndef DNotify_included | ||
613 | +#define DNotify_included | ||
614 | + | ||
615 | +#include "config.h" | ||
616 | +#include "Monitor.h" | ||
617 | +#include <signal.h> | ||
618 | + | ||
619 | +// DNotify is an object encapsulating the dnotify linux fcntl. | ||
620 | +// It "emulates" the IMon interface. | ||
621 | +// There can only be one instantiation of the DNotify object. | ||
622 | +// | ||
623 | +// The user of this object uses express() and revoke() to | ||
624 | +// express/revoke interest in a file. There is also | ||
625 | +// a callback, the EventHandler. When an dnotify event comes in, | ||
626 | +// the EventHandler is called. | ||
627 | +// | ||
628 | +// The user of the DNotify object is the Interest class. | ||
629 | + | ||
630 | +class DNotify : public Monitor { | ||
631 | +public: | ||
632 | + DNotify(EventHandler h); | ||
633 | + ~DNotify(); | ||
634 | + | ||
635 | + static bool is_active(); | ||
636 | + | ||
637 | + virtual Status express(const char *name, struct stat *stat_return); | ||
638 | + virtual Status revoke(const char *name, dev_t dev, ino_t ino); | ||
639 | + | ||
640 | +private: | ||
641 | + struct FileWatch; | ||
642 | + struct DirWatch; | ||
643 | + struct ChangeEventData; | ||
644 | + | ||
645 | + // Class Variables | ||
646 | + enum { QUEUESIZE = 1024 }; | ||
647 | + static int pipe_write_fd; | ||
648 | + static int pipe_read_fd; | ||
649 | + static int change_queue[QUEUESIZE]; | ||
650 | + static volatile sig_atomic_t DNotify::queue_overflowed; | ||
651 | + static volatile sig_atomic_t DNotify::queue_changed; | ||
652 | + static volatile int queue_head; // Only modified by read handler | ||
653 | + static volatile int queue_tail; // Only modified by signal handler | ||
654 | + static EventHandler ehandler; | ||
655 | + static void overflow_signal_handler(int sig, siginfo_t *si, void *data); | ||
656 | + static void signal_handler(int sig, siginfo_t *si, void *data); | ||
657 | + static void read_handler(int fd, void *closure); | ||
658 | + | ||
659 | + enum { DIR_HASHSIZE = 367 }; | ||
660 | + static DirWatch *dir_hash[DIR_HASHSIZE]; | ||
661 | + enum { FILE_HASHSIZE = 823 }; | ||
662 | + static FileWatch *file_hash[FILE_HASHSIZE]; | ||
663 | + | ||
664 | + static DirWatch **dir_hashchain(int fd) | ||
665 | + { return &dir_hash[(unsigned) (fd) % DIR_HASHSIZE]; } | ||
666 | + static FileWatch **file_hashchain(dev_t d, ino_t i) | ||
667 | + { return &file_hash[(unsigned) (d+i) % FILE_HASHSIZE]; } | ||
668 | + | ||
669 | + static DirWatch *lookup_dirwatch (int fd); | ||
670 | + static DirWatch *lookup_dirwatch (dev_t dir_dev, ino_t dir_ino); | ||
671 | + static FileWatch *lookup_filewatch (dev_t file_dev, ino_t file_ino); | ||
672 | + static void hash_dirwatch(DirWatch *w); | ||
673 | + static void hash_filewatch(FileWatch *w); | ||
674 | + static void unhash_dirwatch(DirWatch *w); | ||
675 | + static void unhash_filewatch(FileWatch *w); | ||
676 | + static Status watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino); | ||
677 | + | ||
678 | + static void all_watches_changed(void); | ||
679 | + | ||
680 | + DNotify(const DNotify&); // Do not copy | ||
681 | + DNotify & operator = (const DNotify&); // or assign. | ||
682 | +}; | ||
683 | + | ||
684 | +#endif /* !IMon_included */ | ||
685 | + | ||
686 | + | ||
687 | --- fam-2.7.0/src/Interest.c++ 2004-01-30 00:00:00.000000000 +0100 | ||
688 | +++ fam-2.7.0.dnotify/src/Interest.c++ 2004-01-30 00:00:00.000000000 +0100 | ||
689 | @@ -42,12 +42,21 @@ | ||
690 | #include "Event.h" | ||
691 | #include "FileSystem.h" | ||
692 | #include "IMon.h" | ||
693 | +#include "DNotify.h" | ||
694 | #include "Log.h" | ||
695 | #include "Pollster.h" | ||
696 | #include "timeval.h" | ||
697 | |||
698 | Interest *Interest::hashtable[]; | ||
699 | -IMon Interest::imon(imon_handler); | ||
700 | + | ||
701 | +#ifdef USE_DNOTIFY | ||
702 | +static DNotify dnotify(Interest::monitor_handler); | ||
703 | +Monitor * Interest::monitor = &dnotify; | ||
704 | +#else | ||
705 | +static IMon imon(Interest::monitor_handler); | ||
706 | +Monitor * Interest::monitor = &imon; | ||
707 | +#endif | ||
708 | + | ||
709 | bool Interest::xtab_verification = true; | ||
710 | |||
711 | Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev) | ||
712 | @@ -60,10 +69,10 @@ | ||
713 | mypath_exported_to_host(ev == NO_VERIFY_EXPORTED) | ||
714 | { | ||
715 | memset(&old_stat, 0, sizeof(old_stat)); | ||
716 | - IMon::Status s = IMon::BAD; | ||
717 | |||
718 | - s = imon.express(name, &old_stat); | ||
719 | - if (s != IMon::OK) | ||
720 | + Monitor::Status s = Monitor::BAD; | ||
721 | + s = monitor->express(name, &old_stat); | ||
722 | + if (s != Monitor::OK) | ||
723 | { int rc = lstat(name, &old_stat); | ||
724 | if (rc < 0) | ||
725 | { Log::info("can't lstat %s", name); | ||
726 | @@ -100,7 +109,7 @@ | ||
727 | } | ||
728 | #endif | ||
729 | |||
730 | - if (exported_to_host()) fs->ll_monitor(this, s == IMon::OK); | ||
731 | + if (exported_to_host()) fs->ll_monitor(this, s == Monitor::OK); | ||
732 | } | ||
733 | |||
734 | Interest::~Interest() | ||
735 | @@ -128,7 +137,7 @@ | ||
736 | pp = &p->hashlink; // move to next element | ||
737 | } | ||
738 | if (!found_same) | ||
739 | - (void) imon.revoke(name(), dev, ino); | ||
740 | + (void) monitor->revoke(name(), dev, ino); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | @@ -147,7 +156,7 @@ | ||
745 | |||
746 | // Express interest. | ||
747 | IMon::Status s = IMon::BAD; | ||
748 | - s = imon.express(name(), NULL); | ||
749 | + s = monitor->express(name(), NULL); | ||
750 | if (s != IMon::OK) { | ||
751 | return true; | ||
752 | } | ||
753 | @@ -248,23 +257,23 @@ | ||
754 | } | ||
755 | |||
756 | void | ||
757 | -Interest::imon_handler(dev_t device, ino_t inumber, int event) | ||
758 | +Interest::monitor_handler(dev_t device, ino_t inumber, int event) | ||
759 | { | ||
760 | assert(device || inumber); | ||
761 | |||
762 | for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next) | ||
763 | { next = p->hashlink; | ||
764 | if (p->ino == inumber && p->dev == device) | ||
765 | - { if (event == IMon::EXEC) | ||
766 | + { if (event == Monitor::EXEC) | ||
767 | { p->cur_exec_state = EXECUTING; | ||
768 | (void) p->report_exec_state(); | ||
769 | } | ||
770 | - else if (event == IMon::EXIT) | ||
771 | + else if (event == Monitor::EXIT) | ||
772 | { p->cur_exec_state = NOT_EXECUTING; | ||
773 | (void) p->report_exec_state(); | ||
774 | } | ||
775 | else | ||
776 | - { assert(event == IMon::CHANGE); | ||
777 | + { assert(event == Monitor::CHANGE); | ||
778 | p->scan(); | ||
779 | } | ||
780 | } | ||
781 | --- fam-2.7.0/config.h.in 2003-01-20 01:40:15.000000000 +0100 | ||
782 | +++ fam-2.7.0.dnotify/config.h.in 2004-01-30 13:50:33.000000000 +0100 | ||
783 | @@ -180,3 +180,6 @@ | ||
784 | |||
785 | /* Define to `int' if <sys/types.h> doesn't define. */ | ||
786 | #undef uid_t | ||
787 | + | ||
788 | +/* Define to 1 if you have F_NOTIFY fcntl */ | ||
789 | +#undef USE_DNOTIFY | ||
790 | --- fam-2.7.0/configure.ac 2003-11-26 20:47:59.000000000 +0100 | ||
791 | +++ fam-2.7.0.dnotify/configure.ac 2004-01-30 13:50:33.000000000 +0100 | ||
792 | @@ -34,7 +34,26 @@ | ||
793 | AC_HEADER_DIRENT | ||
794 | AC_CHECK_HEADERS([fcntl.h limits.h linux/imon.h netinet/in.h rpc/rpc.h rpcsvc/mount.h stddef.h stdlib.h string.h syslog.h sys/imon.h sys/param.h sys/select.h sys/statvfs.h sys/syssgi.h sys/time.h sys/types.h sys/un.h unistd.h]) | ||
795 | |||
796 | -if test "$have_sys_imon_h"; then | ||
797 | +# Test for the linux dnotify fcntl | ||
798 | +AC_MSG_CHECKING([for dnotify fcntl support]) | ||
799 | +AC_TRY_COMPILE([ | ||
800 | +#define _GNU_SOURCE | ||
801 | +#include <fcntl.h> | ||
802 | +#include <unistd.h> | ||
803 | +], | ||
804 | +[ int fd = 1; | ||
805 | + fcntl (fd, F_NOTIFY, (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB) | ||
806 | + |DN_MULTISHOT); | ||
807 | +], have_dnotify=yes, have_dnotify=no) | ||
808 | + | ||
809 | +use_dnotify=false | ||
810 | +AC_MSG_RESULT($have_dnotify) | ||
811 | + | ||
812 | +if test "$have_dnotify"; then | ||
813 | + MONITOR_FUNCS=IMonNone | ||
814 | + AC_DEFINE([USE_DNOTIFY], [], [Use dnotify]) | ||
815 | + use_dnotify=true | ||
816 | +elif test "$have_sys_imon_h"; then | ||
817 | MONITOR_FUNCS=IMonIRIX | ||
818 | elif test "$have_linux_imon_h"; then | ||
819 | MONITOR_FUNCS=IMonLinux | ||
820 | @@ -42,6 +62,7 @@ | ||
821 | MONITOR_FUNCS=IMonNone | ||
822 | fi | ||
823 | AC_SUBST(MONITOR_FUNCS) | ||
824 | +AM_CONDITIONAL(USE_DNOTIFY, $use_dnotify) | ||
825 | |||
826 | # Checks for typedefs, structures, and compiler characteristics. | ||
827 | AC_HEADER_STDBOOL | ||
828 | --- fam-2.7.0/src/IMon.h 2004-01-30 00:00:00.000000000 +0200 | ||
829 | +++ fam-2.7.0.dnotify/src/IMon.h 2004-01-30 00:00:00.000000000 +0200 | ||
830 | @@ -24,10 +24,7 @@ | ||
831 | #define IMon_included | ||
832 | |||
833 | #include "config.h" | ||
834 | -#include <sys/stat.h> | ||
835 | -#include <sys/types.h> | ||
836 | - | ||
837 | -#include "Boolean.h" | ||
838 | +#include "Monitor.h" | ||
839 | |||
840 | struct stat; | ||
841 | |||
842 | @@ -41,25 +38,18 @@ | ||
843 | // | ||
844 | // The user of the IMon object is the Interest class. | ||
845 | |||
846 | -class IMon { | ||
847 | +class IMon : public Monitor { | ||
848 | |||
849 | public: | ||
850 | - | ||
851 | - enum Status { OK = 0, BAD = -1 }; | ||
852 | - enum Event { EXEC, EXIT, CHANGE }; | ||
853 | - | ||
854 | - typedef void (*EventHandler)(dev_t, ino_t, int event); | ||
855 | - | ||
856 | IMon(EventHandler h); | ||
857 | ~IMon(); | ||
858 | |||
859 | static bool is_active(); | ||
860 | |||
861 | - Status express(const char *name, struct stat *stat_return); | ||
862 | - Status revoke(const char *name, dev_t dev, ino_t ino); | ||
863 | + virtual Status express(const char *name, struct stat *stat_return); | ||
864 | + virtual Status revoke(const char *name, dev_t dev, ino_t ino); | ||
865 | |||
866 | private: | ||
867 | - | ||
868 | // Class Variables | ||
869 | |||
870 | static int imonfd; | ||
871 | --- fam-2.7.0/src/Interest.h 2004-01-30 00:00:00.000000000 +0200 | ||
872 | +++ fam-2.7.0.dnotify/src/Interest.h 2004-01-30 00:00:00.000000000 +0200 | ||
873 | @@ -32,7 +32,7 @@ | ||
874 | |||
875 | class Event; | ||
876 | class FileSystem; | ||
877 | -class IMon; | ||
878 | +class Monitor; | ||
879 | struct stat; | ||
880 | |||
881 | // Interest -- abstract base class for filesystem entities of interest. | ||
882 | @@ -74,7 +74,7 @@ | ||
883 | |||
884 | // Public Class Method | ||
885 | |||
886 | - static void imon_handler(dev_t, ino_t, int event); | ||
887 | + static void monitor_handler(dev_t, ino_t, int event); | ||
888 | |||
889 | static void enable_xtab_verification(bool enable); | ||
890 | |||
891 | @@ -121,7 +121,7 @@ | ||
892 | |||
893 | // Class Variables | ||
894 | |||
895 | - static IMon imon; | ||
896 | + static Monitor *monitor; | ||
897 | static Interest *hashtable[HASHSIZE]; | ||
898 | static bool xtab_verification; | ||
899 | |||
900 | --- fam-2.7.0/src/Makefile.am 2003-01-19 13:00:17.000000000 +0100 | ||
901 | +++ fam-2.7.0.dnotify/src/Makefile.am 2004-01-30 13:50:38.000000000 +0100 | ||
902 | @@ -71,7 +71,11 @@ | ||
903 | main.c++ \ | ||
904 | timeval.c++ \ | ||
905 | timeval.h \ | ||
906 | - @MONITOR_FUNCS@.c++ | ||
907 | + Monitor.h \ | ||
908 | + DNotify.h \ | ||
909 | + DNotify.c++ \ | ||
910 | + @MONITOR_FUNCS@.c++ | ||
911 | |||
912 | -EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ | ||
913 | +EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ DNotify.c++ \ | ||
914 | + DNotify.h Monitor.h | ||
915 | |||
916 | --- fam-2.7.0/src/Monitor.h 2004-01-30 00:00:00.000000000 +0200 | ||
917 | +++ fam-2.7.0.dnotify/src/Monitor.h 2004-01-30 00:00:00.000000000 +0200 | ||
918 | @@ -0,0 +1,57 @@ | ||
919 | +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved. | ||
920 | +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. | ||
921 | +// | ||
922 | +// This program is free software; you can redistribute it and/or modify it | ||
923 | +// under the terms of version 2 of the GNU General Public License as | ||
924 | +// published by the Free Software Foundation. | ||
925 | +// | ||
926 | +// This program is distributed in the hope that it would be useful, but | ||
927 | +// WITHOUT ANY WARRANTY; without even the implied warranty of | ||
928 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any | ||
929 | +// license provided herein, whether implied or otherwise, is limited to | ||
930 | +// this program in accordance with the express provisions of the GNU | ||
931 | +// General Public License. Patent licenses, if any, provided herein do not | ||
932 | +// apply to combinations of this program with other product or programs, or | ||
933 | +// any other product whatsoever. This program is distributed without any | ||
934 | +// warranty that the program is delivered free of the rightful claim of any | ||
935 | +// third person by way of infringement or the like. See the GNU General | ||
936 | +// Public License for more details. | ||
937 | +// | ||
938 | +// You should have received a copy of the GNU General Public License along | ||
939 | +// with this program; if not, write the Free Software Foundation, Inc., 59 | ||
940 | +// Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
941 | + | ||
942 | +#ifndef Monitor_included | ||
943 | +#define Monitor_included | ||
944 | + | ||
945 | +#include "config.h" | ||
946 | +#include <sys/stat.h> | ||
947 | +#include <sys/types.h> | ||
948 | + | ||
949 | +struct stat; | ||
950 | + | ||
951 | +// Monitor is an abstract baseclass for differend file monitoring | ||
952 | +// systems. The original system used was IMon, and the Montor API | ||
953 | +// is heavily influenced by that. | ||
954 | +// There can only be one instantiation of the Monitor object. | ||
955 | +// | ||
956 | +// The user of this object uses express() and revoke() to | ||
957 | +// express/revoke interest in a file to imon. There is also | ||
958 | +// a callback, the EventHandler. When an event comes in, | ||
959 | +// the EventHandler is called. | ||
960 | +// | ||
961 | +// The main implementers of the Monitor class is IMon and DNotify | ||
962 | + | ||
963 | +class Monitor { | ||
964 | +public: | ||
965 | + | ||
966 | + enum Status { OK = 0, BAD = -1 }; | ||
967 | + enum Event { EXEC, EXIT, CHANGE }; | ||
968 | + | ||
969 | + typedef void (*EventHandler)(dev_t, ino_t, int event); | ||
970 | + | ||
971 | + virtual Status express(const char *name, struct stat *stat_return) = 0; | ||
972 | + virtual Status revoke(const char *name, dev_t dev, ino_t ino) = 0; | ||
973 | +}; | ||
974 | + | ||
975 | +#endif /* !Monitor_included */ |