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