Contents of /trunk/fam/patches/fam-2.7.0-dnotify.patch
Parent Directory | Revision Log
Revision 144 -
(show 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 | --- 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 */ |