From 297a8b7d6cb9df764b346147a6eb79d47774080c Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@Germany>
Date: Mon, 7 Jun 2010 13:51:14 +0200
Subject: [PATCH] ENH: move fileMonitor stat vs. inotify to internal class

- avoids potential mismatches between header and courtesy binaries
---
 src/Allwmake                       |   2 +-
 src/OSspecific/POSIX/Allwmake      |  21 ++++
 src/OSspecific/POSIX/Make/options  |   4 +-
 src/OSspecific/POSIX/fileMonitor.C | 170 ++++++++++++++++++-----------
 src/OSspecific/POSIX/fileMonitor.H |  39 +++----
 5 files changed, 147 insertions(+), 89 deletions(-)
 create mode 100755 src/OSspecific/POSIX/Allwmake

diff --git a/src/Allwmake b/src/Allwmake
index 4da8d4f7192..e1589a40467 100755
--- a/src/Allwmake
+++ b/src/Allwmake
@@ -17,7 +17,7 @@ wmakeLnInclude OpenFOAM
 wmakeLnInclude OSspecific/$WM_OSTYPE
 Pstream/Allwmake
 
-wmake libo  OSspecific/$WM_OSTYPE
+OSspecific/$WM_OSTYPE/Allwmake
 wmake libso OpenFOAM
 
 wmake libso lagrangian/basic
diff --git a/src/OSspecific/POSIX/Allwmake b/src/OSspecific/POSIX/Allwmake
new file mode 100755
index 00000000000..7819ce885bf
--- /dev/null
+++ b/src/OSspecific/POSIX/Allwmake
@@ -0,0 +1,21 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # run from this directory
+
+#
+# use <sys/inotify.h> if available (Linux)
+# unless otherwise specified (with FOAM_USE_STAT)
+#
+# eg,  ./Allwmake FOAM_USE_STAT
+#
+if [ -f /usr/include/sys/inotify.h -a "${1%USE_STAT}" = "$1" ]
+then
+    unset FOAM_FILE_MONITOR
+else
+    export FOAM_FILE_MONITOR="-DFOAM_USE_STAT"
+fi
+
+
+# make (non-shared) object
+wmake libo
+
+# ----------------------------------------------------------------- end-of-file
diff --git a/src/OSspecific/POSIX/Make/options b/src/OSspecific/POSIX/Make/options
index b7e9d7211b0..be643469df3 100644
--- a/src/OSspecific/POSIX/Make/options
+++ b/src/OSspecific/POSIX/Make/options
@@ -1,3 +1 @@
-#ifdef SunOS64
-EXE_INC = -DFOAM_USE_STAT
-#endif
+EXE_INC = $(FOAM_FILE_MONITOR)
diff --git a/src/OSspecific/POSIX/fileMonitor.C b/src/OSspecific/POSIX/fileMonitor.C
index f7f0246c986..a812dec9429 100644
--- a/src/OSspecific/POSIX/fileMonitor.C
+++ b/src/OSspecific/POSIX/fileMonitor.C
@@ -37,7 +37,6 @@ Class
 #   include "regIOobject.H"     // for fileModificationSkew symbol
 #else
 #   include <sys/inotify.h>
-#   include <stropts.h>
 #   include <sys/ioctl.h>
 #endif
 
@@ -49,8 +48,8 @@ template<>
 const char* Foam::NamedEnum<Foam::fileMonitor::fileState, 3>::names[] =
 {
     "unmodified",
-    "deleted",
-    "modified"
+    "modified",
+    "deleted"
 };
 const Foam::NamedEnum<Foam::fileMonitor::fileState, 3>
     Foam::fileMonitor::fileStateNames_;
@@ -58,7 +57,7 @@ const Foam::NamedEnum<Foam::fileMonitor::fileState, 3>
 
 namespace Foam
 {
-    // Reduction operator for PackedList of fileState
+    //- Reduction operator for PackedList of fileState
     class reduceFileStates
     {
         public:
@@ -89,7 +88,7 @@ namespace Foam
         }
     };
 
-    // Combine operator for PackedList of fileState
+    //- Combine operator for PackedList of fileState
     class combineReduceFileStates
     {
         public:
@@ -98,22 +97,101 @@ namespace Foam
             x = reduceFileStates()(x, y);
         }
     };
+
+
+
+    //! @cond internalClass
+    //- Internal tracking via stat(3p) or inotify(7)
+    class fileMonitorWatcher
+    {
+    public:
+
+#ifdef FOAM_USE_STAT
+        //- From watch descriptor to modified time
+        HashTable<label, time_t> lastMod;
+
+        //- initialize HashTable size
+        inline fileMonitorWatcher(const label sz = 20)
+        :
+            lastMod(sz)
+        {}
+
+        inline label addWatch(const fileName& fName)
+        {
+            const label watchFd = lastMod.size();
+            lastMod.insert(watchFd, lastModified(fName));
+            return watchFd;
+        }
+
+        inline bool removeWatch(const label watchFd)
+        {
+            return lastMod.erase(watchFd);
+        }
+
+#else
+        //- File descriptor for the inotify instance
+        int fd;
+
+        //- Pre-allocated structure containing file descriptors
+        fd_set fdSet;
+
+        //- initialize inotify
+        inline fileMonitorWatcher(const label dummy = 0)
+        :
+            fd(inotify_init())
+        {
+            // Add notify descriptor to select fd_set
+            FD_ZERO(&fdSet);
+            FD_SET(fd, &fdSet);
+        }
+
+        //- test if file descriptor is set
+        inline bool isSet() const
+        {
+            return FD_ISSET(fd, &fdSet);
+        }
+
+        //- reset file descriptor
+        inline void reset()
+        {
+            FD_SET(fd, &fdSet);
+        }
+
+        inline label addWatch(const fileName& fName)
+        {
+            return inotify_add_watch
+            (
+                fd,
+                fName.c_str(),
+                // IN_ALL_EVENTS
+                IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MODIFY
+            );
+        }
+
+        inline bool removeWatch(const label watchFd)
+        {
+            return inotify_rm_watch(fd, int(watchFd)) == 0;
+        }
+#endif
+
+    };
+    //! @endcond
 }
 
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-#ifdef FOAM_USE_STAT
 void Foam::fileMonitor::checkFiles() const
 {
+#ifdef FOAM_USE_STAT
     for
     (
-        HashTable<label, time_t>::iterator iter = lastModified_.begin();
-        iter != lastModified_.end();
+        HashTable<label, time_t>::iterator iter = watcher_->lastMod.begin();
+        iter != watcher_->lastMod.end();
         ++iter
     )
     {
-        label watchFd = iter.key();
+        const label watchFd = iter.key();
         const fileName& fName = watchFile_[watchFd];
         time_t newTime = lastModified(fName);
 
@@ -135,21 +213,18 @@ void Foam::fileMonitor::checkFiles() const
             }
         }
     }
-}
 #else
-void Foam::fileMonitor::checkFiles() const
-{
     while (true)
     {
         struct timeval zeroTimeout = {0, 0};
 
         int ready = select
         (
-            inotifyFd_+1,       // num filedescriptors in watchSet_
-            &watchSet_,         // watchSet_ with only inotifyFd
-            NULL,
-            NULL,
-            &zeroTimeout
+            watcher_->fd+1,        // num filedescriptors in fdSet
+            &(watcher_->fdSet),    // fdSet with only inotifyFd
+            NULL,                  // No writefds
+            NULL,                  // No errorfds
+            &zeroTimeout           // eNo timeout
         );
 
         if (ready < 0)
@@ -158,14 +233,14 @@ void Foam::fileMonitor::checkFiles() const
                 << "Problem in issuing select."
                 << abort(FatalError);
         }
-        else if (FD_ISSET(inotifyFd_, &watchSet_))
+        else if (watcher_->isSet())
         {
             struct inotify_event inotifyEvent;
 
             // Read first event
             ssize_t nBytes = read
             (
-                inotifyFd_,
+                watcher_->fd,
                 &inotifyEvent,
                 sizeof(inotifyEvent)
             );
@@ -178,9 +253,9 @@ void Foam::fileMonitor::checkFiles() const
                     << abort(FatalError);
             }
 
-            //Pout<< "mask:" << inotifyEvent.mask << endl;
-            //Pout<< "watchFd:" << inotifyEvent.wd << endl;
-            //Pout<< "watchName:" << watchFile_[inotifyEvent.wd] << endl;
+            // Pout<< "mask:" << inotifyEvent.mask << nl
+            //     << "watchFd:" << inotifyEvent.wd << nl
+            //     << "watchName:" << watchFile_[inotifyEvent.wd] << endl;
 
             switch (inotifyEvent.mask)
             {
@@ -204,51 +279,37 @@ void Foam::fileMonitor::checkFiles() const
         }
         else
         {
-            // No data. Reset watchSet_
-            FD_SET(inotifyFd_, &watchSet_);
+            // No data - reset
+            watcher_->reset();
             return;
         }
     }
-}
 #endif
+}
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-// Null constructor
-#ifdef FOAM_USE_STAT
 
 Foam::fileMonitor::fileMonitor()
 :
     state_(20),
     watchFile_(20),
-    lastModified_(20)
+    watcher_(new fileMonitorWatcher(20))
 {}
 
-#else
-
-Foam::fileMonitor::fileMonitor()
-:
-    state_(20),
-    watchFile_(20),
-    inotifyFd_(inotify_init())
-{
-    //- Add notify descriptor to select set
-    FD_ZERO(&watchSet_);
-    FD_SET(inotifyFd_, &watchSet_);
-}
-
-#endif
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::fileMonitor::~fileMonitor()
 {
-    // Remove any remaining files
+    // Remove watch on any remaining files
     List<label> watchFds(state_.toc());
     forAll(watchFds, i)
     {
         removeWatch(watchFds[i]);
     }
+
+    delete watcher_;
 }
 
 
@@ -257,18 +318,7 @@ Foam::fileMonitor::~fileMonitor()
 
 Foam::label Foam::fileMonitor::addWatch(const fileName& fName)
 {
-#ifdef FOAM_USE_STAT
-    label watchFd = lastModified_.size();
-    lastModified_.insert(watchFd, lastModified(fName));
-#else
-    label watchFd = inotify_add_watch
-    (
-        inotifyFd_,
-        fName.c_str(),
-        //IN_ALL_EVENTS
-        IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MODIFY
-    );
-#endif
+    const label watchFd = watcher_->addWatch(fName);
 
     if (debug)
     {
@@ -300,11 +350,7 @@ bool Foam::fileMonitor::removeWatch(const label watchFd)
 
     state_.erase(watchFd);
     watchFile_.erase(watchFd);
-#ifdef FOAM_USE_STAT
-    return lastModified_.erase(watchFd);
-#else
-    return inotify_rm_watch(inotifyFd_, int(watchFd)) == 0;
-#endif
+    return watcher_->removeWatch(watchFd);
 }
 
 
@@ -331,7 +377,7 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
         label i = 0;
         forAllConstIter(Map<fileState>, state_, iter)
         {
-            stats[i++] = (unsigned int)(iter());
+            stats[i++] = static_cast<unsigned int>(iter());
         }
         // Save local state for warning message below
         PackedList<2> thisProcStats(stats);
@@ -378,7 +424,7 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
 void Foam::fileMonitor::setUnmodified(const label watchFd)
 {
 #ifdef FOAM_USE_STAT
-    lastModified_[watchFd] = lastModified(watchFile_[watchFd]);
+    watcher_->lastMod[watchFd] = lastModified(watchFile_[watchFd]);
 #endif
 
     Map<fileState>::iterator iter = state_.find(watchFd);
diff --git a/src/OSspecific/POSIX/fileMonitor.H b/src/OSspecific/POSIX/fileMonitor.H
index b9922eb3e2a..fbb0c4e2d64 100644
--- a/src/OSspecific/POSIX/fileMonitor.H
+++ b/src/OSspecific/POSIX/fileMonitor.H
@@ -27,13 +27,13 @@ Class
 Description
     Checking for changes to files.
 
-!!!!!!!NOTE:
-    Default is to use inotify (Linux specific, since 2.6.13)
+Note
+    The default is to use inotify (Linux specific, since 2.6.13)
 
-    Compile with FOAM_USE_STAT to use the stat function call.
+    Compiling with FOAM_USE_STAT (or if /usr/include/sys/inotify.h
+    does not exist) uses the stat function call.
 
-
-    - works fine except for if file gets deleted and recreated
+    - works fine except when a file is deleted and recreated:
     it stops monitoring the file!
     (does work though if the file gets moved)
 
@@ -48,7 +48,6 @@ SourceFiles
 #include <sys/types.h>
 #include "Map.H"
 #include "NamedEnum.H"
-#include "labelList.H"
 #include "className.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -57,9 +56,10 @@ namespace Foam
 {
 
 class fileMonitor;
+class fileMonitorWatcher;
 
 /*---------------------------------------------------------------------------*\
-                           Class fileMonitor Declaration
+                         Class fileMonitor Declaration
 \*---------------------------------------------------------------------------*/
 
 class fileMonitor
@@ -73,8 +73,8 @@ public:
         enum fileState
         {
             UNMODIFIED = 0,
-            DELETED = 1,
-            MODIFIED = 2
+            MODIFIED = 1,
+            DELETED = 2,
         };
 
         static const NamedEnum<fileState, 3> fileStateNames_;
@@ -84,22 +84,16 @@ private:
 
         //- State for all watchFds
         mutable Map<fileState> state_;
-        
+
         //- From watch descriptor to filename
         HashTable<fileName, label> watchFile_;
 
-#ifdef FOAM_USE_STAT
+        //- Watch mechanism (stat or inotify)
+        mutable fileMonitorWatcher *watcher_;
 
-        //- From watch descriptor to modified time
-        mutable HashTable<label, time_t> lastModified_;
-#else
-        //- File descriptor for the inotify instance
-        int inotifyFd_;
 
-        //- Pre-allocated structure containing file descriptors
-        mutable fd_set watchSet_;
+    // Private Member Functions
 
-#endif
         //- Update state_ from any events.
         void checkFiles() const;
 
@@ -121,14 +115,13 @@ public:
         fileMonitor();
 
 
-    // Destructor
-
-        ~fileMonitor();
+    //- Destructor
+    ~fileMonitor();
 
 
     // Member Functions
 
-        //- Add file to watch. Returns watch descriptor
+        //- Add file to watch. Return watch descriptor
         label addWatch(const fileName&);
 
         //- Remove file to watch. Return true if successful
-- 
GitLab