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