Ticket #193: dnotify.2.patch

File dnotify.2.patch, 28.3 KB (added by billy@…, 22 years ago)

gets libfam to use the Linux kernel dnotify mechanism.

  • fam-2.6.7/acconfig.h

    old new  
    1717/*  Define if the system has imon and IMONIOC_ ioctl flags.  */
    1818#undef HAVE_IMON
    1919
     20/*  Define if the system has the dnotify fcntl and it's gonna be used.  */
     21#undef USE_DNOTIFY
     22
    2023/*  Define if the system has the struct revokdi and the IMONIOC_REVOKDI
    2124**  ioctl flag.  (IRIX 5.3 doesn't.)
    2225*/
  • fam-2.6.7/configure.in

    old new  
    9699dnl AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h syslog.h unistd.h)
    97100
    98101dnl
     102dnl  Test for the linux dnotify fcntl
     103dnl
     104AC_MSG_CHECKING([for dnotify fcntl support])
     105fam_save_cppflags="$CPPFLAGS"
     106CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
     107AC_TRY_COMPILE([
     108#define _GNU_SOURCE 
     109#include <fcntl.h>
     110#include <unistd.h>
     111],
     112[ int fd = 1;
     113  fcntl (fd, F_NOTIFY, (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB)|DN_MULTISHOT);
     114], have_dnotify=yes, have_dnotify=no)
     115use_dnotify=false
     116CPPFLAGS="$pango_save_cppflags"
     117AC_MSG_RESULT($have_dnotify)
     118
     119dnl
    99120dnl  See if imon is available; if so, is it IRIX or Linux?
    100121dnl
    101122if test `uname` = 'IRIX' || test `uname` = 'IRIX64'; then
     
    118139if test "$have_imon" != "yes"; then
    119140    have_imon=no
    120141    AC_DEFINE(HAVE_IMON, 0)
     142    if test "$have_dnotify" = "yes"; then
     143        AC_DEFINE(USE_DNOTIFY)
     144        use_dnotify=true
     145    fi
    121146    IMON_FUNCS=IMonNone
    122147fi
     148AM_CONDITIONAL(USE_DNOTIFY, $use_dnotify)
    123149AC_SUBST(IMON_FUNCS)
    124150echo "Using imon support module $IMON_FUNCS"
    125151
     152
    126153AC_CHECK_HEADER(sys/statvfs.h, [AC_DEFINE(HAVE_STATVFS, 1) have_statvfs="yes"], [AC_DEFINE(HAVE_STATVFS, 0) have_statvfs="no"])
    127154AC_CHECK_HEADER(sys/syssgi.h,  AC_DEFINE(HAVE_SYSSGI,  1), AC_DEFINE(HAVE_SYSSGI,  0))
    128155AC_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))
     
    572599dnl
    573600dnl  fam is a good deal less interesting without imon.
    574601dnl
    575 if test "$have_imon" != 'yes'; then
     602if test "$have_imon" != 'yes' -a "$have_dnotify" != 'yes'; then
    576603    cat << EOF
    577604
    578605  ******************************************************************
  • fam-2.6.7/fam/DNotify.c++

    old new  
     1//  Copyright (C) 2001 Red Hat, Inc.  All Rights Reserved.
     2//  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
     3// 
     4//  This program is free software; you can redistribute it and/or modify it
     5//  under the terms of version 2 of the GNU General Public License as
     6//  published by the Free Software Foundation.
     7//
     8//  This program is distributed in the hope that it would be useful, but
     9//  WITHOUT ANY WARRANTY; without even the implied warranty of
     10//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
     11//  license provided herein, whether implied or otherwise, is limited to
     12//  this program in accordance with the express provisions of the GNU
     13//  General Public License.  Patent licenses, if any, provided herein do not
     14//  apply to combinations of this program with other product or programs, or
     15//  any other product whatsoever.  This program is distributed without any
     16//  warranty that the program is delivered free of the rightful claim of any
     17//  third person by way of infringement or the like.  See the GNU General
     18//  Public License for more details.
     19//
     20//  You should have received a copy of the GNU General Public License along
     21//  with this program; if not, write the Free Software Foundation, Inc., 59
     22//  Temple Place - Suite 330, Boston MA 02111-1307, USA.
     23
     24#define _GNU_SOURCE 
     25#include <fcntl.h>
     26
     27#include <string.h>
     28#include <signal.h>
     29#include <stdio.h>
     30#include <unistd.h>
     31#include <sys/types.h>
     32#include <sys/stat.h>
     33#include <libgen.h>
     34
     35#include "DNotify.h"
     36
     37#include "Interest.h"
     38#include "Log.h"
     39#include "Scheduler.h"
     40#include "alloc.h"
     41
     42
     43int DNotify::pipe_write_fd = -2;
     44int DNotify::pipe_read_fd = -2;
     45volatile sig_atomic_t DNotify::queue_overflowed = 0;
     46volatile sig_atomic_t DNotify::queue_changed = 0;
     47int DNotify::change_queue[QUEUESIZE];
     48volatile int DNotify::queue_head = 0; // Only modified by read handler
     49volatile int DNotify::queue_tail = 0; // Only modified by signal handler
     50DNotify::EventHandler DNotify::ehandler;
     51
     52DNotify::DirWatch *DNotify::dir_hash[DIR_HASHSIZE];
     53DNotify::FileWatch *DNotify::file_hash[FILE_HASHSIZE];
     54
     55struct DNotify::FileWatch
     56{
     57    DirWatch *dir_watch;
     58    dev_t file_dev;
     59    ino_t file_ino;
     60    FileWatch *next; // The DirWatch.watches list
     61    FileWatch *hash_link;
     62};
     63
     64struct DNotify::DirWatch
     65{
     66    int fd;
     67    dev_t dir_dev;
     68    ino_t dir_ino;
     69   
     70    DirWatch *hash_link;
     71    FileWatch *watches;
     72};
     73
     74struct DNotify::ChangeEventData
     75{
     76    dev_t file_dev;
     77    ino_t file_ino;
     78};   
     79
     80DNotify::DNotify(EventHandler h)
     81{
     82    assert(ehandler == NULL);
     83    ehandler = h;
     84}
     85
     86DNotify::~DNotify()
     87{
     88    if (pipe_read_fd >= 0)
     89    {
     90        //  Tell the scheduler.
     91
     92        (void) Scheduler::remove_read_handler(pipe_read_fd);
     93
     94        //  Close the pipe.
     95
     96        if (close(pipe_read_fd) < 0)
     97            Log::perror("can't pipe read end");
     98        else
     99            Log::debug("closed pipe read end");
     100       
     101        if (close(pipe_write_fd) < 0)
     102            Log::perror("can't pipe write end");
     103        else
     104            Log::debug("closed pipe write end");
     105        pipe_read_fd = -1;
     106    }
     107    ehandler = NULL;
     108}
     109
     110void
     111DNotify::overflow_signal_handler(int sig, siginfo_t *si, void *data)
     112{
     113  char c = 'x';
     114
     115  {
     116    char *str = "*************** overflow sigqueue ***********************\n";
     117    write (STDERR_FILENO, str, strlen(str));
     118  }
     119
     120  if (!queue_overflowed)
     121  {
     122      queue_overflowed = 1;
     123      // Trigger the read handler
     124      write(pipe_write_fd, &c, 1);
     125  }
     126}
     127
     128void
     129DNotify::signal_handler(int sig, siginfo_t *si, void *data)
     130{
     131  int left;
     132  char c = 'x';
     133
     134  if (queue_head <= queue_tail)
     135    left = (QUEUESIZE + queue_head) - queue_tail;
     136  else
     137    left = queue_head - queue_tail;
     138 
     139  // Must leave at least one item unused to see difference
     140  // Betweeen empty and full
     141  if (left <= 1)
     142  {
     143      queue_overflowed = 1;
     144      {
     145        char *str = "*************** overflow famqueue ****************\n";
     146        write (STDERR_FILENO, str, strlen(str));
     147      }
     148  }
     149  else
     150  {
     151      change_queue[queue_tail] = si->si_fd;
     152      queue_tail = (queue_tail + 1) % QUEUESIZE;
     153  }
     154 
     155  if (!queue_changed)
     156  {
     157      queue_changed = 1;
     158      // Trigger the read handler
     159      write(pipe_write_fd, &c, 1);
     160  }
     161}
     162
     163bool
     164DNotify::is_active()
     165{
     166    if (pipe_read_fd == -2)
     167    {
     168        int filedes[2];
     169        int res;
     170       
     171        res = pipe (filedes);
     172        if (res >= 0)
     173        {   Log::debug("opened pipe");
     174            pipe_read_fd = filedes[0];
     175            pipe_write_fd = filedes[1];
     176
     177            // Setup signal handler:
     178            struct sigaction act;
     179           
     180            act.sa_sigaction = signal_handler;
     181            sigemptyset(&act.sa_mask);
     182            act.sa_flags = SA_SIGINFO;
     183            sigaction(SIGRTMIN, &act, NULL);
     184
     185            // When the RT queue overflows we get a SIGIO
     186            act.sa_sigaction = overflow_signal_handler;
     187            sigemptyset(&act.sa_mask);
     188            sigaction(SIGIO, &act, NULL);
     189
     190            (void) Scheduler::install_read_handler(pipe_read_fd, read_handler, NULL);
     191        }
     192    }
     193    return pipe_read_fd >= 0;
     194}
     195
     196DNotify::DirWatch *
     197DNotify::lookup_dirwatch (int fd)
     198{
     199  DirWatch **p;
     200  DirWatch *w;
     201
     202  p = dir_hashchain (fd);
     203
     204  while (*p)
     205    {
     206      w = *p;
     207
     208      if (w->fd == fd)
     209        return w;
     210
     211      p = &w->hash_link;
     212    }
     213 
     214  return *p;
     215}
     216
     217// This colud be made faster by using another hash table.
     218// But it's not that bad, since it is only used by express/revoke
     219DNotify::DirWatch *
     220DNotify::lookup_dirwatch (dev_t dir_dev, ino_t dir_ino)
     221{
     222  DirWatch *p;
     223  int i;
     224
     225  for (i=0;i<DIR_HASHSIZE;i++)
     226    {
     227      p = dir_hash[i];
     228     
     229      while (p)
     230        {
     231          if (p->dir_dev == dir_dev && p->dir_ino == dir_ino)
     232            return p;
     233         
     234          p = p->hash_link;
     235        }
     236    }
     237 
     238  return NULL;
     239}
     240
     241DNotify::FileWatch *
     242DNotify::lookup_filewatch (dev_t dev, ino_t ino)
     243{
     244  FileWatch **p;
     245  FileWatch *w;
     246
     247  p = file_hashchain (dev, ino);
     248
     249  while (*p)
     250    {
     251      w = *p;
     252
     253      if (w->file_dev == dev && w->file_ino == ino)
     254        return w;
     255
     256      p = &w->hash_link;
     257    }
     258 
     259  return *p;
     260}
     261
     262// Make sure w is not already in the hash table before calling
     263// this function.
     264void
     265DNotify::hash_dirwatch(DirWatch *w)
     266{
     267  DirWatch **p;
     268  p = dir_hashchain (w->fd);
     269  w->hash_link = *p;
     270  *p = w;
     271}
     272
     273// Make sure w is not already in the hash table before calling
     274// this function.
     275void
     276DNotify::hash_filewatch(FileWatch *w)
     277{
     278  FileWatch **p;
     279  p = file_hashchain (w->file_dev, w->file_ino);
     280  w->hash_link = *p;
     281  *p = w;
     282}
     283
     284void
     285DNotify::unhash_dirwatch(DirWatch *w)
     286{
     287  DirWatch **p;
     288 
     289  p = dir_hashchain (w->fd);
     290 
     291  while (*p)
     292    {
     293      if (*p == w)
     294        {
     295          *p = w->hash_link;
     296          break;
     297        }
     298      p = &(*p)->hash_link;
     299    }
     300  w->hash_link = NULL;
     301}
     302
     303void
     304DNotify::unhash_filewatch(FileWatch *w)
     305{
     306  FileWatch **p;
     307 
     308  p = file_hashchain (w->file_dev, w->file_ino);
     309 
     310  while (*p)
     311    {
     312      if (*p == w)
     313        {
     314          *p = w->hash_link;
     315          break;
     316        }
     317      p = &(*p)->hash_link;
     318    }
     319  w->hash_link = NULL;
     320}
     321
     322DNotify::Status
     323DNotify::watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino)
     324{
     325  struct stat stat;
     326  dev_t dir_dev;
     327  ino_t dir_ino;
     328  DirWatch *dwatch;
     329  FileWatch **p;
     330  FileWatch *fw;
     331   
     332  if (lstat (notify_dir, &stat) == -1)
     333      return BAD;
     334 
     335  dwatch = lookup_dirwatch(stat.st_dev, stat.st_ino);
     336  if (!dwatch)
     337    {
     338      Log::debug ("New DirWatch for %s (%x %x)\n",
     339                  notify_dir, (int)stat.st_dev, (int)stat.st_ino);
     340      dwatch = new DirWatch;
     341      dwatch->watches = NULL;
     342      dwatch->hash_link = NULL;
     343      dwatch->dir_dev = stat.st_dev;
     344      dwatch->dir_ino = stat.st_ino;
     345     
     346      dwatch->fd = open(notify_dir, O_RDONLY);
     347      fcntl (dwatch->fd, F_SETSIG, SIGRTMIN);
     348      fcntl (dwatch->fd, F_NOTIFY,
     349             (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB) | DN_MULTISHOT);
     350      hash_dirwatch (dwatch);
     351    }
     352
     353  for (p=&dwatch->watches; *p; p=&(*p)->next)
     354    {
     355      fw = *p;
     356      if (fw->file_dev == file_dev && fw->file_ino == file_ino)
     357        return OK;
     358    }
     359 
     360  // No old FileWatch, need to add one:
     361  Log::debug("New FileWatch for %x %x\n", (int)file_dev, (int)file_ino);
     362  *p = new FileWatch;
     363  fw = *p;
     364  fw->next = NULL;
     365  fw->file_dev = file_dev;
     366  fw->file_ino = file_ino;
     367  fw->dir_watch = dwatch;
     368  hash_filewatch(fw);
     369  return OK;
     370}
     371
     372char *
     373dirname_dup (const char *name)
     374{
     375  char *copy = strdup(name);
     376  char *res = dirname(copy);
     377  res = strdup(res);
     378  free (copy);
     379  return res;
     380}
     381
     382DNotify::Status
     383DNotify::express(const char *name, struct stat *status)
     384{
     385    struct stat stat;
     386    char *notify_dir;
     387    int res;
     388    Status s;
     389    dev_t dev;
     390    ino_t ino;
     391
     392    Log::debug("express() name: %s\n", name);
     393
     394    if (!is_active())
     395        return BAD;
     396
     397    if (::lstat (name, &stat) == -1)
     398      return BAD;
     399
     400    dev = stat.st_dev;
     401    ino = stat.st_ino;
     402   
     403    if ((stat.st_mode & S_IFMT) != S_IFDIR)
     404        notify_dir = dirname_dup (name);
     405    else
     406        notify_dir = (char *)name;
     407
     408    s = watch_dir (notify_dir, dev, ino);
     409    if (notify_dir != name)
     410        free (notify_dir);
     411    if (s)
     412      return s;
     413
     414    // Check for a race condition; if someone removed or changed the
     415    // file at the same time that we are expressing interest in it,
     416    // revoke the interest so we don't get notifications about changes
     417    // to a recycled inode that we don't otherwise care about.
     418    //
     419    struct stat st;
     420    if (status == NULL) {
     421        status = &st;
     422    }
     423    if (::lstat(name, status) == -1) {
     424        Log::perror("stat on \"%s\" failed", name);
     425        revoke(name, stat.st_dev, stat.st_ino);
     426        return BAD;
     427    }
     428    if (status->st_dev != stat.st_dev
     429        || status->st_ino != stat.st_ino) {
     430        Log::error("File \"%s\" changed between express and stat",
     431                   name);
     432        revoke(name, stat.st_dev, stat.st_ino);
     433        return BAD;
     434    }   
     435
     436    Log::debug("told dnotify to monitor \"%s\" = dev %d/%d, ino %d", name,
     437               major(status->st_dev), minor(status->st_dev),
     438               status->st_ino);
     439    return OK;
     440}
     441
     442DNotify::Status
     443DNotify::revoke(const char *name, dev_t dev, ino_t ino)
     444{
     445    FileWatch *fwatch;
     446    DirWatch *dwatch;
     447   
     448    Log::debug("revoke() name: %s, dev: %x, ino: %x\n", name, dev, ino);
     449
     450    if (!is_active())
     451        return BAD;
     452
     453    // Lookup FileWatch by dev:ino, and its DirWatch.
     454    fwatch = lookup_filewatch (dev, ino);
     455    if (fwatch == NULL)
     456        return BAD;
     457   
     458    dwatch = fwatch->dir_watch;
     459   
     460    // delete FileWatch, if last FileWatch: close fd, delete DirWatch
     461    Log::debug ("Destroying FileWatch for (%x %x)\n",
     462                (int)fwatch->file_dev, (int)fwatch->file_ino);
     463    FileWatch **p;
     464    for (p=&dwatch->watches; *p; p=&(*p)->next)
     465    {
     466      if (*p == fwatch)
     467        {
     468          *p = (*p)->next;
     469          break;
     470        }
     471    }
     472    unhash_filewatch(fwatch);
     473    delete fwatch;
     474    if (dwatch->watches == NULL)
     475      {
     476        Log::debug ("Destroying DirWatch for (%x %x)\n",
     477                    (int)dwatch->dir_dev, (int)dwatch->dir_ino);
     478        close(dwatch->fd);
     479        unhash_dirwatch(dwatch);
     480        delete dwatch;
     481      }
     482 
     483    return OK;
     484}
     485
     486
     487void
     488DNotify::all_watches_changed(void)
     489{
     490  int i;
     491  FileWatch *fw;
     492
     493  for (i=0; i<FILE_HASHSIZE; i++)
     494  {
     495      fw = file_hash[i];
     496      while (fw)
     497      {
     498          (*ehandler)(fw->file_dev, fw->file_ino, CHANGE);
     499
     500          fw = fw->hash_link;
     501      }
     502  }
     503}
     504
     505
     506void
     507DNotify::read_handler(int fd, void *)
     508{
     509    static char readbuf[5000];
     510    DirWatch *dw;
     511    FileWatch *fw;
     512    int snap_queue_tail;
     513    int last_fd;
     514
     515    int rc = read(fd, readbuf, sizeof readbuf);
     516    queue_changed = 0;
     517    if (rc < 0)
     518        Log::perror("pipe read");
     519    else if (queue_overflowed)
     520    {
     521          // There is a *slight* race condition here. Between reading
     522          // the queue_overflow flag and resetting it. But it doesn't
     523          // matter, since I'm gonna handle the overflow after reseting
     524          // anyway.
     525          queue_overflowed = false;
     526
     527          // We're soon gonna check all watches anyway, so
     528          // get rid of the current queue
     529          queue_head = queue_tail;
     530         
     531          all_watches_changed ();
     532    }
     533    else
     534    {
     535        // Don't read events that happen later than
     536        // the initial read. (Otherwise skipping fd's
     537        // might miss some changes).
     538        snap_queue_tail = queue_tail;
     539        last_fd = -1;
     540        while (queue_head != snap_queue_tail)
     541        {
     542            fd = change_queue[queue_head];
     543            queue_head = (queue_head + 1) % QUEUESIZE;
     544
     545            // Skip multiple changes to the same fd
     546            if (fd != last_fd)
     547            {
     548                dw = lookup_dirwatch (fd);
     549                if (dw)
     550                {
     551                    int n_watches, i;
     552                    ChangeEventData *data;
     553                   
     554                    Log::debug("dnotify said dev %d/%d, ino %ld changed",
     555                               major(dw->dir_dev), minor(dw->dir_dev), dw->dir_ino);
     556                   
     557                    n_watches = 0;
     558                    for (fw=dw->watches; fw; fw=fw->next)
     559                        n_watches++;
     560                   
     561                    data = new ChangeEventData[n_watches];
     562
     563                    i = 0;
     564                    for (fw=dw->watches; fw; fw=fw->next)
     565                    {
     566                        data[i].file_dev = fw->file_dev;
     567                        data[i].file_ino = fw->file_ino;
     568                        i++;
     569                    }
     570
     571                    for (i = 0; i < n_watches; i++)
     572                    {
     573                        (*ehandler)(data[i].file_dev, data[i].file_ino, CHANGE);
     574                    }
     575                   
     576                    delete[] data;
     577                }
     578            }
     579            last_fd = fd;
     580        }
     581    }
     582}
     583
  • fam-2.6.7/fam/DNotify.h

    old new  
     1//  Copyright (C) 2001 Red Hat, Inc.  All Rights Reserved.
     2//  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
     3//
     4//  This program is free software; you can redistribute it and/or modify it
     5//  under the terms of version 2 of the GNU General Public License as
     6//  published by the Free Software Foundation.
     7//
     8//  This program is distributed in the hope that it would be useful, but
     9//  WITHOUT ANY WARRANTY; without even the implied warranty of
     10//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
     11//  license provided herein, whether implied or otherwise, is limited to
     12//  this program in accordance with the express provisions of the GNU
     13//  General Public License.  Patent licenses, if any, provided herein do not
     14//  apply to combinations of this program with other product or programs, or
     15//  any other product whatsoever.  This program is distributed without any
     16//  warranty that the program is delivered free of the rightful claim of any
     17//  third person by way of infringement or the like.  See the GNU General
     18//  Public License for more details.
     19//
     20//  You should have received a copy of the GNU General Public License along
     21//  with this program; if not, write the Free Software Foundation, Inc., 59
     22//  Temple Place - Suite 330, Boston MA 02111-1307, USA.
     23
     24#ifndef DNotify_included
     25#define DNotify_included
     26
     27#include "config.h"
     28#include "Monitor.h"
     29#include <signal.h>
     30
     31//  DNotify is an object encapsulating the dnotify linux fcntl.
     32//  It "emulates" the IMon interface.
     33//  There can only be one instantiation of the DNotify object.
     34//
     35//  The user of this object uses express() and revoke() to
     36//  express/revoke interest in a file.  There is also
     37//  a callback, the EventHandler.  When an dnotify event comes in,
     38//  the EventHandler is called.
     39//
     40//  The user of the DNotify object is the Interest class.
     41
     42class DNotify : public Monitor {
     43public:
     44    DNotify(EventHandler h);
     45    ~DNotify();
     46
     47    static bool is_active();
     48
     49    virtual Status express(const char *name, struct stat *stat_return);
     50    virtual Status revoke(const char *name, dev_t dev, ino_t ino);
     51
     52private:
     53    struct FileWatch;
     54    struct DirWatch;
     55    struct ChangeEventData;
     56 
     57    //  Class Variables
     58    enum { QUEUESIZE = 1024 };
     59    static int pipe_write_fd;
     60    static int pipe_read_fd;
     61    static int change_queue[QUEUESIZE];
     62    static volatile sig_atomic_t DNotify::queue_overflowed;
     63    static volatile sig_atomic_t DNotify::queue_changed;
     64    static volatile int queue_head; // Only modified by read handler
     65    static volatile int queue_tail; // Only modified by signal handler
     66    static EventHandler ehandler;
     67    static void overflow_signal_handler(int sig, siginfo_t *si, void *data);
     68    static void signal_handler(int sig, siginfo_t *si, void *data);
     69    static void read_handler(int fd, void *closure);
     70 
     71    enum { DIR_HASHSIZE = 257 };
     72    static DirWatch *dir_hash[DIR_HASHSIZE];
     73    enum { FILE_HASHSIZE = 257 };
     74    static FileWatch *file_hash[FILE_HASHSIZE];
     75
     76    static DirWatch **dir_hashchain(int fd)
     77                          { return &dir_hash[(unsigned) (fd) % DIR_HASHSIZE]; }
     78    static FileWatch **file_hashchain(dev_t d, ino_t i)
     79                          { return &file_hash[(unsigned) (d+i) % FILE_HASHSIZE]; }
     80
     81    static DirWatch *lookup_dirwatch (int fd);
     82    static DirWatch *lookup_dirwatch (dev_t dir_dev, ino_t dir_ino);
     83    static FileWatch *lookup_filewatch (dev_t file_dev, ino_t file_ino);
     84    static void hash_dirwatch(DirWatch *w);
     85    static void hash_filewatch(FileWatch *w);
     86    static void unhash_dirwatch(DirWatch *w);
     87    static void unhash_filewatch(FileWatch *w);
     88    static Status watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino);
     89
     90    static void all_watches_changed(void);
     91   
     92    DNotify(const DNotify&);                    // Do not copy
     93    DNotify & operator = (const DNotify&);      //  or assign.
     94};
     95
     96#endif /* !IMon_included */
     97
     98
  • fam-2.6.7/fam/IMon.h

    old new  
    2424#define IMon_included
    2525
    2626#include "config.h"
    27 #include <sys/stat.h>
    28 #include <sys/types.h>
    29 
    30 #include "Boolean.h"
     27#include "Monitor.h"
    3128
    3229struct stat;
    3330
     
    4138//
    4239//  The user of the IMon object is the Interest class.
    4340
    44 class IMon {
     41class IMon : public Monitor {
    4542
    4643public:
    47 
    48     enum Status { OK = 0, BAD = -1 };
    49     enum Event { EXEC, EXIT, CHANGE };
    50 
    51     typedef void (*EventHandler)(dev_t, ino_t, int event);
    52 
    5344    IMon(EventHandler h);
    5445    ~IMon();
    5546
    5647    static bool is_active();
    5748
    58     Status express(const char *name, struct stat *stat_return);
    59     Status revoke(const char *name, dev_t dev, ino_t ino);
     49    virtual Status express(const char *name, struct stat *stat_return);
     50    virtual Status revoke(const char *name, dev_t dev, ino_t ino);
    6051
    6152private:
    62 
    6353    //  Class Variables
    6454
    6555    static int imonfd;
  • fam-2.6.7/fam/Interest.c++

    old new  
    4141#include "Event.h"
    4242#include "FileSystem.h"
    4343#include "IMon.h"
     44#include "DNotify.h"
    4445#include "Log.h"
    4546#include "Pollster.h"
    4647#include "timeval.h"
    4748
    4849Interest *Interest::hashtable[];
    49 IMon      Interest::imon(imon_handler);
     50
     51#ifdef USE_DNOTIFY
     52static DNotify dnotify(Interest::monitor_handler);
     53Monitor * Interest::monitor = &dnotify;
     54#else
     55static IMon imon(Interest::monitor_handler);
     56Monitor * Interest::monitor = &imon;
     57#endif
     58
    5059bool      Interest::xtab_verification = true;
    5160
    5261Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev)
     
    5867      myhost(host),
    5968      mypath_exported_to_host(ev == NO_VERIFY_EXPORTED)
    6069{
    61     memset(&old_stat, 0, sizeof(old_stat)); 
    62     IMon::Status s = IMon::BAD;
    63 
    64     s = imon.express(name, &old_stat);
    65     if (s != IMon::OK)
     70    memset(&old_stat, 0, sizeof(old_stat));
     71   
     72    Monitor::Status s = Monitor::BAD;
     73    s = monitor->express(name, &old_stat);
     74    if (s != Monitor::OK)
    6675    {   int rc = lstat(name, &old_stat);
    6776        if (rc < 0)
    6877        {   Log::info("can't lstat %s", name);
     
    99108    }
    100109#endif
    101110
    102     if (exported_to_host()) fs->ll_monitor(this, s == IMon::OK);
     111    if (exported_to_host()) fs->ll_monitor(this, s == Monitor::OK);
    103112}
    104113
    105114Interest::~Interest()
     
    127136                pp = &p->hashlink;      // move to next element
    128137            }
    129138        if (!found_same)
    130             (void) imon.revoke(name(), dev, ino);
     139          (void) monitor->revoke(name(), dev, ino);
    131140    }
    132141}
    133142
     
    146155
    147156        // Express interest.
    148157        IMon::Status s = IMon::BAD;
    149         s = imon.express(name(), NULL);
     158        s = monitor->express(name(), NULL);
    150159        if (s != IMon::OK) {
    151160            return true;
    152161        }
     
    247256}
    248257
    249258void
    250 Interest::imon_handler(dev_t device, ino_t inumber, int event)
     259Interest::monitor_handler(dev_t device, ino_t inumber, int event)
    251260{
    252261    assert(device || inumber);
    253262
    254263    for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next)
    255264    {   next = p->hashlink;
    256265        if (p->ino == inumber && p->dev == device)
    257         {   if (event == IMon::EXEC)
     266          {   if (event == Monitor::EXEC)
    258267            {   p->cur_exec_state = EXECUTING;
    259268                (void) p->report_exec_state();
    260269            }
    261             else if (event == IMon::EXIT)
     270            else if (event == Monitor::EXIT)
    262271            {   p->cur_exec_state = NOT_EXECUTING;
    263272                (void) p->report_exec_state();
    264273            }
    265274            else
    266             {   assert(event == IMon::CHANGE);
     275            {   assert(event == Monitor::CHANGE);
    267276                p->scan();
    268277            }
    269278        }
  • fam-2.6.7/fam/Interest.h

    old new  
    3232
    3333class Event;
    3434class FileSystem;
    35 class IMon;
     35class Monitor;
    3636struct stat;
    3737
    3838//  Interest -- abstract base class for filesystem entities of interest.
     
    7474
    7575    //  Public Class Method
    7676
    77     static void imon_handler(dev_t, ino_t, int event);
     77    static void monitor_handler(dev_t, ino_t, int event);
    7878
    7979    static void enable_xtab_verification(bool enable);
    8080
     
    121121
    122122    //  Class Variables
    123123
    124     static IMon imon;
     124    static Monitor *monitor;
    125125    static Interest *hashtable[HASHSIZE];
    126126    static bool xtab_verification;
    127127
  • fam-2.6.7/fam/Makefile.am

    old new  
    33bin_PROGRAMS = fam
    44sysconf_DATA = fam.conf
    55
     6if USE_DNOTIFY
     7DNOTIFY_FILES = DNotify.c++
     8else
     9DNOTIFY_FILES =
     10endif
     11
    612fam_SOURCES = \
    713  Activity.c++ \
    814  Activity.h \
     
    2026  Directory.h \
    2127  DirectoryScanner.c++ \
    2228  DirectoryScanner.h \
     29  DNotify.h \
    2330  Event.c++ \
    2431  Event.h \
    2532  File.c++ \
     
    4855  NFSFileSystem.h \
    4956  NetConnection.c++ \
    5057  NetConnection.h \
     58  Monitor.h \
    5159  Pollster.c++ \
    5260  Pollster.h \
    5361  Request.h \
     
    7280  main.c++ \
    7381  timeval.c++ \
    7482  timeval.h \
    75   @IMON_FUNCS@.c++
     83  @IMON_FUNCS@.c++ \
     84  $(DNOTIFY_FILES)
    7685
    77 EXTRA_fam_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++
     86EXTRA_fam_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ DNotify.c++
    7887
    7988fam_LDADD = -lrpcsvc $(top_srcdir)/support/libsupport.a
    8089
  • fam-2.6.7/fam/Monitor.h

    old new  
     1//  Copyright (C) 2001 Red Hat, Inc.  All Rights Reserved.
     2//  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
     3// 
     4//  This program is free software; you can redistribute it and/or modify it
     5//  under the terms of version 2 of the GNU General Public License as
     6//  published by the Free Software Foundation.
     7//
     8//  This program is distributed in the hope that it would be useful, but
     9//  WITHOUT ANY WARRANTY; without even the implied warranty of
     10//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
     11//  license provided herein, whether implied or otherwise, is limited to
     12//  this program in accordance with the express provisions of the GNU
     13//  General Public License.  Patent licenses, if any, provided herein do not
     14//  apply to combinations of this program with other product or programs, or
     15//  any other product whatsoever.  This program is distributed without any
     16//  warranty that the program is delivered free of the rightful claim of any
     17//  third person by way of infringement or the like.  See the GNU General
     18//  Public License for more details.
     19//
     20//  You should have received a copy of the GNU General Public License along
     21//  with this program; if not, write the Free Software Foundation, Inc., 59
     22//  Temple Place - Suite 330, Boston MA 02111-1307, USA.
     23
     24#ifndef Monitor_included
     25#define Monitor_included
     26
     27#include "config.h"
     28#include <sys/stat.h>
     29#include <sys/types.h>
     30
     31struct stat;
     32
     33//  Monitor is an abstract baseclass for differend file monitoring
     34//  systems. The original system used was IMon, and the Montor API
     35//  is heavily influenced by that.
     36//  There can only be one instantiation of the Monitor object.
     37//
     38//  The user of this object uses express() and revoke() to
     39//  express/revoke interest in a file to imon.  There is also
     40//  a callback, the EventHandler.  When an event comes in,
     41//  the EventHandler is called.
     42//
     43//  The main implementers of the Monitor class is IMon and DNotify
     44
     45class Monitor {
     46public:
     47
     48    enum Status { OK = 0, BAD = -1 };
     49    enum Event { EXEC, EXIT, CHANGE };
     50
     51    typedef void (*EventHandler)(dev_t, ino_t, int event);
     52
     53    virtual Status express(const char *name, struct stat *stat_return) = 0;
     54    virtual Status revoke(const char *name, dev_t dev, ino_t ino) = 0;
     55};
     56
     57#endif /* !Monitor_included */
  • fam-2.6.7/include/BTree.h

    old new  
    271271    n += that->n + 1;
    272272    link[n] = that->link[that->n];
    273273    that->n = 0;
    274     that->link[0] = NULL;
     274    that->link[0] = 0;
    275275}
    276276
    277277///////////////////////////////////////////////////////////////////////////////
     
    280280
    281281template <class K, class V>
    282282BTree<K, V>::BTree()
    283     : root(NULL), npairs(0)
     283    : root(0), npairs(0)
    284284{
    285285    assert(!(fanout % 2));
    286286}
     
    407407BTree<Key, Value>::Closure
    408408BTree<Key, Value>::insert(Node *p, const Key& key, const Value& value)
    409409{
    410     if (!p) return Closure(key, value, NULL);
     410    if (!p) return Closure(key, value, 0);
    411411    //  If you're running Purify on a client linking with libfam, and it says
    412412    //  that line is causing a 3-byte UMR for BTree<int, bool>::insert() in
    413413    //  FAMNextEvent() ("Reading 8 bytes from 0x... on the stack (3 bytes at
     
    475475    case UNDER:
    476476        if (root->n == 0)
    477477        {   Node *nr = root->link[0];
    478             root->link[0] = NULL;       // don't delete subtree
     478            root->link[0] = 0;  // don't delete subtree
    479479            delete root;
    480480            root = nr;
    481481        }
     
    507507    Node *cp = p->link[i];
    508508    assert(cp);
    509509   
    510     Node *rp = i < p->n ? p->link[i + 1] : NULL;
    511     Node *lp = i > 0    ? p->link[i - 1] : NULL;
     510    Node *rp = i < p->n ? p->link[i + 1] : 0;
     511    Node *lp = i > 0    ? p->link[i - 1] : 0;
    512512    assert(!rp || rp->n >= fanout / 2);
    513513    assert(!lp || lp->n >= fanout / 2);
    514514