Commit 1a6db8cd authored by mattijs's avatar mattijs
Browse files

ENH: fileMonitor : monitor directory, not file

Some editors (emacs) rename file at startup to the backup version. Hence
watching the original file tells one nothing.
parent a2fa56ec
......@@ -31,6 +31,7 @@ Class
#include "Pstream.H"
#include "PackedList.H"
#include "PstreamReduceOps.H"
#include "OSspecific.H"
#ifdef FOAM_USE_STAT
# include "OSspecific.H"
......@@ -112,50 +113,104 @@ namespace Foam
#ifdef FOAM_USE_STAT
//- From watch descriptor to modified time
HashTable<label, time_t> lastMod;
DynamicList<time_t> lastMod_;
//- initialize HashTable size
inline fileMonitorWatcher(const label sz = 20)
:
lastMod(sz)
lastMod_(sz)
{}
inline label addWatch(const fileName& fName)
inline bool addWatch(const label watchFd, const fileName& fName)
{
const label watchFd = lastMod.size();
lastMod.insert(watchFd, lastModified(fName));
return watchFd;
if (watchFd < lastMod_.size() && lastMod_[watchFd] != 0)
{
// Reuse of watchFd : should have lastMod set to 0.
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Problem adding watch " << watchFd
<< " to file " << fName
<< abort(FatalError);
}
lastMod_(watchFd) = lastModified(fName);
return true;
}
inline bool removeWatch(const label watchFd)
{
return lastMod.erase(watchFd);
lastMod_[watchFd] = 0;
return true;
}
#else
//- File descriptor for the inotify instance
int fd;
//- initialize inotify
inline fileMonitorWatcher(const label dummy = 0)
//- Current watchIDs and corresponding directory id
DynamicList<label> dirWatches_;
DynamicList<fileName> dirFiles_;
//- initialise inotify
inline fileMonitorWatcher(const label sz = 20)
:
fd(inotify_init())
fd(inotify_init()),
dirWatches_(sz),
dirFiles_(sz)
{}
inline label addWatch(const fileName& fName)
//- remove all watches
inline ~fileMonitorWatcher()
{
forAll(dirWatches_, i)
{
if (dirWatches_[i] >= 0)
{
if (inotify_rm_watch(fd, int(dirWatches_[i])))
{
WarningIn("fileMonitor::~fileMonitor()")
<< "Failed deleting directory watch "
<< dirWatches_[i] << endl;
}
}
}
}
inline bool addWatch(const label watchFd, const fileName& fName)
{
return inotify_add_watch
// Add/retrieve watch on directory containing file
label dirWatchID = inotify_add_watch
(
fd,
fName.c_str(),
// IN_ALL_EVENTS
IN_CLOSE_WRITE | IN_DELETE_SELF //| IN_MODIFY
fName.path().c_str(),
IN_CLOSE_WRITE
);
if (dirWatchID < 0)
{
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Failed adding watch " << watchFd
<< " to directory " << fName
<< exit(FatalError);
}
if (watchFd < dirWatches_.size() && dirWatches_[watchFd] != -1)
{
// Reuse of watchFd : should have dir watchID set to -1.
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Problem adding watch " << watchFd
<< " to file " << fName
<< abort(FatalError);
}
dirWatches_(watchFd) = dirWatchID;
dirFiles_(watchFd) = fName.name();
return true;
}
inline bool removeWatch(const label watchFd)
{
return inotify_rm_watch(fd, int(watchFd)) == 0;
dirWatches_[watchFd] = -1;
return true;
}
#endif
......@@ -169,32 +224,30 @@ namespace Foam
void Foam::fileMonitor::checkFiles() const
{
#ifdef FOAM_USE_STAT
for
(
HashTable<label, time_t>::iterator iter = watcher_->lastMod.begin();
iter != watcher_->lastMod.end();
++iter
)
forAll(watcher_->lastMod_, watchFd)
{
const label watchFd = iter.key();
const fileName& fName = watchFile_[watchFd];
time_t newTime = lastModified(fName);
time_t oldTime = watcher_->lastMod_[watchFd];
if (newTime == 0)
{
state_.set(watchFd, DELETED);
}
else
if (oldTime != 0)
{
time_t oldTime = iter();
if (newTime > (oldTime + regIOobject::fileModificationSkew))
const fileName& fName = watchFile_[watchFd];
time_t newTime = lastModified(fName);
if (newTime == 0)
{
iter() = newTime;
state_.set(watchFd, MODIFIED);
state_[watchFd] = DELETED;
}
else
{
state_.set(watchFd, UNMODIFIED);
if (newTime > (oldTime + regIOobject::fileModificationSkew))
{
watcher_->lastMod_[watchFd] = newTime;
state_[watchFd] = MODIFIED;
}
else
{
state_[watchFd] = UNMODIFIED;
}
}
}
}
......@@ -250,26 +303,30 @@ void Foam::fileMonitor::checkFiles() const
&buffer[i]
);
// Pout<< "mask:" << inotifyEvent->mask << nl
// << "watchFd:" << inotifyEvent->wd << nl
// << "watchName:" << watchFile_[inotifyEvent->wd] << endl;
//Pout<< "watchFd:" << inotifyEvent->wd << nl
// << "mask:" << inotifyEvent->mask << nl
// << endl;
//Pout<< "file:" << fileName(inotifyEvent->name) << endl;
//Pout<< "len:" << inotifyEvent->len << endl;
if (inotifyEvent->mask % IN_DELETE_SELF)
if ((inotifyEvent->mask & IN_CLOSE_WRITE) && inotifyEvent->len)
{
Map<fileState>::iterator iter =
state_.find(label(inotifyEvent->wd));
iter() = DELETED;
}
else if
(
//(inotifyEvent->mask % IN_MODIFY)
(inotifyEvent->mask % IN_CLOSE_WRITE)
)
{
Map<fileState>::iterator iter =
state_.find(label(inotifyEvent->wd));
iter() = MODIFIED;
// Search for file
forAll(watcher_->dirWatches_, i)
{
label id = watcher_->dirWatches_[i];
if
(
id == inotifyEvent->wd
&& inotifyEvent->name == watcher_->dirFiles_[i]
)
{
// Correct directory and name
state_[i] = MODIFIED;
}
}
}
i += EVENT_SIZE + inotifyEvent->len;
}
}
......@@ -289,6 +346,7 @@ Foam::fileMonitor::fileMonitor()
:
state_(20),
watchFile_(20),
freeWatchFds_(2),
watcher_(new fileMonitorWatcher(20))
{}
......@@ -296,24 +354,27 @@ Foam::fileMonitor::fileMonitor()
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::fileMonitor::~fileMonitor()
{
// Remove watch on any remaining files
List<label> watchFds(state_.toc());
forAll(watchFds, i)
{
removeWatch(watchFds[i]);
}
delete watcher_;
}
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::fileMonitor::addWatch(const fileName& fName)
{
const label watchFd = watcher_->addWatch(fName);
label watchFd;
label sz = freeWatchFds_.size();
if (sz)
{
watchFd = freeWatchFds_[sz-1];
freeWatchFds_.setSize(sz-1);
}
else
{
watchFd = state_.size();
}
watcher_->addWatch(watchFd, fName);
if (debug)
{
......@@ -328,8 +389,8 @@ Foam::label Foam::fileMonitor::addWatch(const fileName& fName)
}
else
{
state_.insert(watchFd, UNMODIFIED);
watchFile_.insert(watchFd, fName);
state_(watchFd) = UNMODIFIED;
watchFile_(watchFd) = fName;
}
return watchFd;
}
......@@ -343,8 +404,7 @@ bool Foam::fileMonitor::removeWatch(const label watchFd)
<< watchFile_[watchFd] << endl;
}
state_.erase(watchFd);
watchFile_.erase(watchFd);
freeWatchFds_.append(watchFd);
return watcher_->removeWatch(watchFd);
}
......@@ -369,10 +429,9 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
if (syncPar)
{
PackedList<2> stats(state_.size());
label i = 0;
forAllConstIter(Map<fileState>, state_, iter)
forAll(state_, watchFd)
{
stats[i++] = static_cast<unsigned int>(iter());
stats[watchFd] = static_cast<unsigned int>(state_[watchFd]);
}
// Save local state for warning message below
PackedList<2> thisProcStats(stats);
......@@ -391,26 +450,24 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
);
}
i = 0;
forAllIter(Map<fileState>, state_, iter)
forAll(state_, watchFd)
{
if (thisProcStats[i] != UNMODIFIED)
if (thisProcStats[watchFd] != UNMODIFIED)
{
if (stats[i] == UNMODIFIED)
if (stats[watchFd] == UNMODIFIED)
{
WarningIn("fileMonitor::updateStates(const bool) const")
<< "Delaying reading " << watchFile_[iter.key()]
<< "Delaying reading " << watchFile_[watchFd]
<< " due to inconsistent "
"file time-stamps between processors"
<< endl;
}
else
{
unsigned int stat = stats[i];
iter() = fileState(stat);
unsigned int stat = stats[watchFd];
state_[watchFd] = fileState(stat);
}
}
i++;
}
}
}
......@@ -419,19 +476,9 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
void Foam::fileMonitor::setUnmodified(const label watchFd)
{
#ifdef FOAM_USE_STAT
watcher_->lastMod[watchFd] = lastModified(watchFile_[watchFd]);
watcher_->lastMod_[watchFd] = lastModified(watchFile_[watchFd]);
#endif
Map<fileState>::iterator iter = state_.find(watchFd);
if (iter == state_.end())
{
FatalErrorIn("fileMonitor::setUnmodified(const label)")
<< "Illegal watchFd " << watchFd
<< abort(FatalError);
}
iter() = UNMODIFIED;
state_[watchFd] = UNMODIFIED;
}
......
......@@ -33,10 +33,6 @@ Note
Compiling with FOAM_USE_STAT (or if /usr/include/sys/inotify.h
does not exist) uses the stat function call.
- works fine except when a file is deleted and recreated:
it stops monitoring the file!
(does work though if the file gets moved)
SourceFiles
fileMonitor.C
......@@ -46,9 +42,9 @@ SourceFiles
#define fileMonitor_H
#include <sys/types.h>
#include "Map.H"
#include "NamedEnum.H"
#include "className.H"
#include "DynamicList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -83,13 +79,16 @@ private:
// Private data
//- State for all watchFds
mutable Map<fileState> state_;
mutable DynamicList<fileState> state_;
//- Filename for all watchFds
DynamicList<fileName> watchFile_;
//- From watch descriptor to filename
HashTable<fileName, label> watchFile_;
//- Free watchFds
DynamicList<label> freeWatchFds_;
//- Watch mechanism (stat or inotify)
mutable fileMonitorWatcher *watcher_;
mutable autoPtr<fileMonitorWatcher> watcher_;
// Private Member Functions
......
......@@ -371,6 +371,11 @@ Foam::Time::Time
Foam::Time::~Time()
{
if (controlDict_.watchIndex() != -1)
{
removeWatch(controlDict_.watchIndex());
}
// destroy function objects first
functionObjects_.clear();
}
......
......@@ -184,6 +184,7 @@ void Foam::Time::readDict()
if (!runTimeModifiable_ && controlDict_.watchIndex() != -1)
{
removeWatch(controlDict_.watchIndex());
controlDict_.watchIndex() = -1;
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment