mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
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.
This commit is contained in:
@ -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()
|
||||
{
|
||||
return inotify_add_watch
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
if (oldTime != 0)
|
||||
{
|
||||
state_.set(watchFd, DELETED);
|
||||
}
|
||||
else
|
||||
{
|
||||
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_;
|
||||
|
||||
//- From watch descriptor to filename
|
||||
HashTable<fileName, label> watchFile_;
|
||||
//- Filename for all watchFds
|
||||
DynamicList<fileName> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user