ENH: cleanup codeStream - use dynamicCode, dynamicCodeContext encapsulation

Problems remain with codedFixedValueFvPatchScalarField:

- readIfModified() notices change on system/codeDict, but the
  codeProperties::setUnmodified() means that only a single entry will
  get processed

- it appears that while dlclose() may (or may not) be actually closing
  the library, there are probably still references about. This means
  that a subsequent reloading still points to the original functions
  and the lookup is not updated correctly.
This commit is contained in:
Mark Olesen
2011-03-01 14:19:24 +01:00
parent 6b79aae433
commit 97cd3af1ff
8 changed files with 523 additions and 333 deletions

View File

@ -13,7 +13,7 @@
provide the actual dictionary entry. The snippet gets provided as three provide the actual dictionary entry. The snippet gets provided as three
sections of C++ code which just gets inserted into a template: sections of C++ code which just gets inserted into a template:
- =code= section: the actual body of the code. It gets called with arguments - =code= section: the actual body of the code. It gets called with arguments
=const dictionary& dict, OStream& os= and the C++ code can do a =OStream& os, const dictionary& dict= and the C++ code can do a
=dict.lookup= to find current dictionary values. =dict.lookup= to find current dictionary values.
- optional =codeInclude= section: any #include statements to include OpenFOAM - optional =codeInclude= section: any #include statements to include OpenFOAM
files. files.

View File

@ -44,8 +44,8 @@ extern "C"
{ {
void ${typeName} void ${typeName}
( (
const dictionary& dict, Ostream& os,
Ostream& os const dictionary& dict
) )
{ {
//{{{ begin code //{{{ begin code

View File

@ -83,67 +83,61 @@ bool Foam::functionEntries::codeStream::execute
// get code, codeInclude, codeOptions // get code, codeInclude, codeOptions
dynamicCodeContext context(codeDict); dynamicCodeContext context(codeDict);
// codeName: prefix_ + sha1 // codeName: codeStream + _<sha1>
// codeDir : _<sha1> // codeDir : _<sha1>
dynamicCode dynCode dynamicCode dynCode
( (
"codeStream_" + context.sha1().str(), "codeStream" + context.sha1().str(true),
"_" + context.sha1().str() context.sha1().str(true)
); );
// Load library if not already loaded // Load library if not already loaded
// Version information is encoded in the libPath (encoded with the SHA1) // Version information is encoded in the libPath (encoded with the SHA1)
const fileName libPath = dynCode.libPath(); const fileName libPath = dynCode.libPath();
// see if library is loaded
void* lib = dlLibraryTable::findLibrary(libPath); void* lib = dlLibraryTable::findLibrary(libPath);
bool reuseLib = false;
// nothing loaded
// avoid compilation if possible by loading an existing library
if (!lib && dlLibraryTable::open(libPath, false)) if (!lib && dlLibraryTable::open(libPath, false))
{ {
lib = dlLibraryTable::findLibrary(libPath); lib = dlLibraryTable::findLibrary(libPath);
reuseLib = true;
} }
// did not load - need to compile it
// create library if required
if (!lib) if (!lib)
{ {
if (Pstream::master()) if (Pstream::master())
{ {
if (!dynCode.upToDate(context)) if (!dynCode.upToDate(context))
{ {
Info<< "Creating new library in "
<< dynCode.libPath() << endl;
// filter C template
dynCode.addFilterFile(codeTemplateC);
// filter with this context // filter with this context
dynCode.setFilterContext(context); dynCode.reset(context);
// Write Make/files // compile filtered C template
dynCode.addCreateFile dynCode.addCompileFile(codeTemplateC);
(
"Make/files",
codeTemplateC + "\n\n"
+ dynCode.libTarget()
);
// Write Make/options // define Make/options
dynCode.addCreateFile dynCode.setMakeOptions
( (
"Make/options",
"EXE_INC = -g \\\n" "EXE_INC = -g \\\n"
+ context.options() + context.options()
+ "\n\nLIB_LIBS =" + "\n\nLIB_LIBS ="
); );
if (!dynCode.copyFilesContents()) if (!dynCode.copyOrCreateFiles(true))
{ {
FatalIOErrorIn FatalIOErrorIn
( (
"functionEntries::codeStream::execute(..)", "functionEntries::codeStream::execute(..)",
parentDict parentDict
) << "Failed writing " << nl ) << "Failed writing files for" << nl
// << copyFiles << endl << dynCode.libPath() << nl
// << filesContents
<< exit(FatalIOError); << exit(FatalIOError);
} }
} }
@ -160,8 +154,8 @@ bool Foam::functionEntries::codeStream::execute
} }
// all processes must wait for compile // all processes must wait for compile
bool dummy = true; bool waiting = true;
reduce(dummy, orOp<bool>()); reduce(waiting, orOp<bool>());
if (!dlLibraryTable::open(libPath, false)) if (!dlLibraryTable::open(libPath, false))
{ {
@ -175,15 +169,15 @@ bool Foam::functionEntries::codeStream::execute
lib = dlLibraryTable::findLibrary(libPath); lib = dlLibraryTable::findLibrary(libPath);
} }
else else if (reuseLib)
{ {
Info<< "Reusing library in " << libPath << endl; Info<< "Reusing library in " << libPath << endl;
} }
// Find the library handle. // Find the function handle in the library
void (*function)(const dictionary&, Ostream&); void (*function)(Ostream&, const dictionary&);
function = reinterpret_cast<void(*)(const dictionary&, Ostream&)> function = reinterpret_cast<void(*)(Ostream&, const dictionary&)>
( (
dlSym(lib, dynCode.codeName()) dlSym(lib, dynCode.codeName())
); );
@ -199,8 +193,11 @@ bool Foam::functionEntries::codeStream::execute
<< " in library " << lib << exit(FatalIOError); << " in library " << lib << exit(FatalIOError);
} }
// use function to write stream
OStringStream os(is.format()); OStringStream os(is.format());
(*function)(parentDict, os); (*function)(os, parentDict);
// get the entry from this stream
IStringStream resultStream(os.str()); IStringStream resultStream(os.str());
entry.read(parentDict, resultStream); entry.read(parentDict, resultStream);

View File

@ -135,8 +135,8 @@ public:
static bool execute static bool execute
( (
const dictionary& parentDict, const dictionary& parentDict,
primitiveEntry& entry, primitiveEntry&,
Istream& is Istream&
); );
}; };

View File

@ -33,6 +33,7 @@ License
#include "dictionary.H" #include "dictionary.H"
#include "dlLibraryTable.H" #include "dlLibraryTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
int Foam::dynamicCode::allowSystemOperations int Foam::dynamicCode::allowSystemOperations
@ -47,6 +48,9 @@ const Foam::word Foam::dynamicCode::codeTemplateEnvName
const Foam::fileName Foam::dynamicCode::codeTemplateDirName const Foam::fileName Foam::dynamicCode::codeTemplateDirName
= "codeTemplates/dynamicCode"; = "codeTemplates/dynamicCode";
const char* Foam::dynamicCode::libTargetRoot =
"LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib/lib";
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
@ -78,7 +82,7 @@ void Foam::dynamicCode::copyAndFilter
ISstream& is, ISstream& is,
OSstream& os, OSstream& os,
const HashTable<string>& mapping const HashTable<string>& mapping
) const )
{ {
if (!is.good()) if (!is.good())
{ {
@ -110,27 +114,26 @@ void Foam::dynamicCode::copyAndFilter
// expanding according to env variables might cause too many // expanding according to env variables might cause too many
// surprises // surprises
stringOps::inplaceExpand(line, mapping); stringOps::inplaceExpand(line, mapping);
os.writeQuoted(line, false) << nl;
os << line.c_str() << nl;
} }
while (is.good()); while (is.good());
} }
Foam::List<Foam::fileName> bool Foam::dynamicCode::resolveTemplates
Foam::dynamicCode::resolveTemplates(const UList<fileName>& names) (
const UList<fileName>& templateNames,
DynamicList<fileName>& resolvedFiles,
DynamicList<fileName>& badFiles
)
{ {
// try to get template from FOAM_CODESTREAM_TEMPLATES // try to get template from FOAM_CODESTREAM_TEMPLATES
const fileName templateDir(Foam::getEnv(codeTemplateEnvName)); const fileName templateDir(Foam::getEnv(codeTemplateEnvName));
DynamicList<fileName> badFiles(names.size()); bool allOkay = true;
List<fileName> resolved(names.size()); forAll(templateNames, fileI)
label nResolved = 0;
forAll(names, fileI)
{ {
const fileName& templateName = names[fileI]; const fileName& templateName = templateNames[fileI];
fileName file; fileName file;
if (!templateDir.empty() && isDir(templateDir)) if (!templateDir.empty() && isDir(templateDir))
@ -151,73 +154,186 @@ Foam::dynamicCode::resolveTemplates(const UList<fileName>& names)
if (file.empty()) if (file.empty())
{ {
badFiles.append(templateName); badFiles.append(templateName);
allOkay = false;
} }
else else
{ {
resolved[nResolved++] = file; resolvedFiles.append(file);
} }
} }
resolved.setSize(nResolved); return allOkay;
}
if (!badFiles.empty())
bool Foam::dynamicCode::writeCommentSHA1(Ostream& os) const
{
const bool hasSHA1 = filterVars_.found("SHA1sum");
if (hasSHA1)
{
os << "/* dynamicCode:\n * SHA1 = ";
os.writeQuoted(filterVars_["SHA1sum"], false) << "\n */\n";
}
return hasSHA1;
}
bool Foam::dynamicCode::createMakeFiles() const
{
// Create Make/files
if (compileFiles_.empty())
{
return false;
}
const fileName dstFile(this->codePath()/"Make/files");
// Create dir
mkDir(dstFile.path());
OFstream os(dstFile);
//Info<< "Writing to " << dstFile << endl;
if (!os.good())
{ {
FatalErrorIn FatalErrorIn
( (
"dynamicCode::resolveTemplates(..)" "dynamicCode::createMakeFiles()"
) << "Could not find the code template(s): " " const"
<< badFiles << nl ) << "Failed writing " << dstFile
<< "Under the $" << codeTemplateDirName
<< " directory or via via the ~OpenFOAM/"
<< codeTemplateDirName << " expansion"
<< exit(FatalError); << exit(FatalError);
} }
return resolved; writeCommentSHA1(os);
// Write compile files
forAll(compileFiles_, fileI)
{
os.writeQuoted(compileFiles_[fileI], false) << nl;
}
os << nl
<< libTargetRoot << codeName_.c_str() << nl;
return true;
}
bool Foam::dynamicCode::createMakeOptions() const
{
// Create Make/options
if (compileFiles_.empty() || makeOptions_.empty())
{
return false;
}
const fileName dstFile(this->codePath()/"Make/options");
// Create dir
mkDir(dstFile.path());
OFstream os(dstFile);
//Info<< "Writing to " << dstFile << endl;
if (!os.good())
{
FatalErrorIn
(
"dynamicCode::createMakeOptions()"
" const"
) << "Failed writing " << dstFile
<< exit(FatalError);
}
writeCommentSHA1(os);
os.writeQuoted(makeOptions_, false) << nl;
return true;
}
bool Foam::dynamicCode::writeDigest(const SHA1Digest& sha1) const
{
const fileName file = digestFile();
mkDir(file.path());
OFstream os(file);
sha1.write(os, true) << nl;
return os.good();
}
bool Foam::dynamicCode::writeDigest(const std::string& sha1) const
{
const fileName file = digestFile();
mkDir(file.path());
OFstream os(file);
os << '_';
os.writeQuoted(sha1, false) << nl;
return os.good();
} }
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::dynamicCode::dynamicCode(const word& codeName)
:
codeName_(codeName),
codeDirName_(codeName)
{
filterVars_.set("typeName", codeName_);
filterVars_.set("SHA1sum", SHA1Digest().str());
}
Foam::dynamicCode::dynamicCode(const word& codeName, const word& codeDirName) Foam::dynamicCode::dynamicCode(const word& codeName, const word& codeDirName)
: :
codeRoot_(stringOps::expand("$FOAM_CASE/dynamicCode")),
libSubDir_(stringOps::expand("platforms/$WM_OPTIONS/lib")),
codeName_(codeName), codeName_(codeName),
codeDirName_(codeDirName) codeDirName_(codeDirName)
{ {
filterVars_.set("typeName", codeName_); if (codeDirName_.empty())
filterVars_.set("SHA1sum", SHA1Digest().str()); {
codeDirName_ = codeName_;
}
clear();
} }
// Foam::dynamicCode::dynamicCode(const dynamicCode& dc)
// :
// codeName_(dc.codeName_),
// copyFiles_(dc.copyFiles_),
// filesContents_(dc.filesContents_)
// {}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::dynamicCode::clear() void Foam::dynamicCode::clear()
{ {
filterVars_.clear(); compileFiles_.clear();
filterFiles_.clear(); copyFiles_.clear();
createFiles_.clear(); createFiles_.clear();
filterVars_.clear();
filterVars_.set("typeName", codeName_); filterVars_.set("typeName", codeName_);
filterVars_.set("SHA1sum", SHA1Digest().str()); filterVars_.set("SHA1sum", SHA1Digest().str());
// provide default Make/options
makeOptions_ =
"EXE_INC = -g\n"
"\n\nLIB_LIBS = ";
} }
void Foam::dynamicCode::reset
(
const dynamicCodeContext& context
)
{
clear();
setFilterContext(context);
}
void Foam::dynamicCode::addCompileFile(const fileName& name)
{
compileFiles_.append(name);
}
void Foam::dynamicCode::addCopyFile(const fileName& name)
{
copyFiles_.append(name);
}
void Foam::dynamicCode::addCreateFile void Foam::dynamicCode::addCreateFile
( (
@ -229,15 +345,6 @@ void Foam::dynamicCode::addCreateFile
} }
void Foam::dynamicCode::addFilterFile
(
const fileName& name
)
{
filterFiles_.append(name);
}
void Foam::dynamicCode::setFilterContext void Foam::dynamicCode::setFilterContext
( (
const dynamicCodeContext& context const dynamicCodeContext& context
@ -252,46 +359,31 @@ void Foam::dynamicCode::setFilterContext
void Foam::dynamicCode::setFilterVariable void Foam::dynamicCode::setFilterVariable
( (
const word& key, const word& key,
const string& value const std::string& value
) )
{ {
filterVars_.set(key, value); filterVars_.set(key, value);
} }
Foam::fileName Foam::dynamicCode::codePath() const void Foam::dynamicCode::setMakeOptions(const std::string& content)
{ {
return stringOps::expand("$FOAM_CASE/dynamicCode/" + codeDirName_); makeOptions_ = content;
} }
Foam::fileName Foam::dynamicCode::libPath() const bool Foam::dynamicCode::copyOrCreateFiles(const bool verbose) const
{ {
return if (verbose)
( {
stringOps::expand Info<< "Creating new library in " << this->libPath() << endl;
( }
"$FOAM_CASE/dynamicCode/platforms/$WM_OPTIONS/lib/lib"
)
+ codeName_ + ".so"
);
}
Foam::string Foam::dynamicCode::libTarget() const
{
return "LIB = $(PWD)/../platforms/$(WM_OPTIONS)/lib/lib" + codeName_;
}
bool Foam::dynamicCode::copyFilesContents() const
{
if (!allowSystemOperations) if (!allowSystemOperations)
{ {
FatalErrorIn FatalErrorIn
( (
"dynamicCode::copyFilesContents(const fileName&) const" "dynamicCode::copyOrCreateFiles() const"
) << "Loading a shared library using case-supplied code is not" ) << "Loading a shared library using case-supplied code is not"
<< " enabled by default" << nl << " enabled by default" << nl
<< "because of security issues. If you trust the code you can" << "because of security issues. If you trust the code you can"
@ -307,7 +399,29 @@ bool Foam::dynamicCode::copyFilesContents() const
<< exit(FatalError); << exit(FatalError);
} }
List<fileName> resolvedFiles = resolveTemplates(filterFiles_); const label nFiles = compileFiles_.size() + copyFiles_.size();
DynamicList<fileName> resolvedFiles(nFiles);
DynamicList<fileName> badFiles(nFiles);
// resolve template, or add to bad-files
resolveTemplates(compileFiles_, resolvedFiles, badFiles);
resolveTemplates(copyFiles_, resolvedFiles, badFiles);
if (!badFiles.empty())
{
FatalErrorIn
(
"dynamicCode::copyFilesContents(..)"
) << "Could not find the code template(s): "
<< badFiles << nl
<< "Under the $" << codeTemplateEnvName
<< " directory or via via the ~OpenFOAM/"
<< codeTemplateDirName << " expansion"
<< exit(FatalError);
}
// Create dir // Create dir
const fileName outputDir = this->codePath(); const fileName outputDir = this->codePath();
@ -345,7 +459,7 @@ bool Foam::dynamicCode::copyFilesContents() const
<< exit(FatalError); << exit(FatalError);
} }
// variables mapping // Copy lines while expanding variables
copyAndFilter(is, os, filterVars_); copyAndFilter(is, os, filterVars_);
} }
@ -365,14 +479,21 @@ bool Foam::dynamicCode::copyFilesContents() const
{ {
FatalErrorIn FatalErrorIn
( (
"dynamicCode::copyFilesContents()" "dynamicCode::copyOrCreateFiles()"
" const" " const"
) << "Failed writing " << dstFile ) << "Failed writing " << dstFile
<< exit(FatalError); << exit(FatalError);
} }
os << createFiles_[fileI].second().c_str() << endl; os.writeQuoted(createFiles_[fileI].second(), false) << nl;
} }
// Create Make/files + Make/options
createMakeFiles();
createMakeOptions();
writeDigest(filterVars_["SHA1sum"]);
return true; return true;
} }
@ -393,38 +514,16 @@ bool Foam::dynamicCode::wmakeLibso() const
} }
bool Foam::dynamicCode::writeDigest
(
const fileName& dirName,
const SHA1Digest& sha1
) const
{
mkDir(dirName);
OFstream os(dirName/"SHA1Digest");
os << sha1;
return os.good();
}
Foam::SHA1Digest Foam::dynamicCode::readDigest(const fileName& dirName) const
{
IFstream is(dirName/"SHA1Digest");
return SHA1Digest(is);
}
bool Foam::dynamicCode::upToDate(const SHA1Digest& sha1) const bool Foam::dynamicCode::upToDate(const SHA1Digest& sha1) const
{ {
const fileName dirName = this->codePath(); const fileName file = digestFile();
if (!exists(dirName/"SHA1Digest") || readDigest(dirName) != sha1)
if (!exists(file, false) || SHA1Digest(IFstream(file)()) != sha1)
{ {
writeDigest(dirName, sha1);
return false; return false;
} }
else
{
return true; return true;
}
} }
@ -452,28 +551,4 @@ bool Foam::dynamicCode::upToDate(const dynamicCodeContext& context) const
// } // }
// bool Foam::dynamicCode::read(const dictionary& dict)
// {
// dict.lookup("createFiles") >> createFiles_;
// dict.lookup("filterFiles") >> filterFiles_;
// dict.lookup("filterVariables") >> filterVariables_;
//
// return true;
// }
//
//
// void Foam::dynamicCode::writeDict(Ostream& os) const
// {
// os.writeKeyword("createFiles") << createFiles_
// << token::END_STATEMENT << nl;
//
// os.writeKeyword("filterFiles") << filterFiles_
// << token::END_STATEMENT << nl;
//
// os.writeKeyword("filterVariables") << filterVariables_
// << token::END_STATEMENT << nl;
// }
// ************************************************************************* // // ************************************************************************* //

View File

@ -64,41 +64,86 @@ public:
private: private:
// Private data // Private data
//- Root for dynamic code compilation
fileName codeRoot_;
//- Subdirectory name for loading libraries
const fileName libSubDir_;
//- Name for code //- Name for code
word codeName_; word codeName_;
//- Name for code subdirectory //- Name for code subdirectory
mutable word codeDirName_; word codeDirName_;
//- Variables to use during filtering //- Files to copy and filter
HashTable<string> filterVars_; DynamicList<fileName> compileFiles_;
//- Files to copy and filter
DynamicList<fileName> copyFiles_;
//- Direct contents for files //- Direct contents for files
DynamicList<fileAndContent> createFiles_; DynamicList<fileAndContent> createFiles_;
//- Files to copy and filter //- Variables to use during filtering
DynamicList<fileName> filterFiles_; HashTable<string> filterVars_;
//- Contents for Make/options
std::string makeOptions_;
// Private Member Functions
//- Disallow default bitwise copy construct
dynamicCode(const dynamicCode&);
//- Disallow default bitwise assignment
void operator=(const dynamicCode&);
protected: protected:
void copyAndFilter // Static data members
//- Root of the LIB target for Make/files
static const char* libTargetRoot;
// Protected Member Functions
//- Copy lines while expanding variables
static void copyAndFilter
( (
ISstream&, ISstream&,
OSstream&, OSstream&,
const HashTable<string>& mapping const HashTable<string>& mapping
) const; );
//- Resolve code-templates via the codeTemplateEnvName //- Resolve code-templates via the codeTemplateEnvName
// alternatively in the codeTemplateDirName via Foam::findEtcFile // alternatively in the codeTemplateDirName via Foam::findEtcFile
static List<fileName> resolveTemplates static bool resolveTemplates
( (
const UList<fileName>& names const UList<fileName>& templateNames,
DynamicList<fileName>& resolvedFiles,
DynamicList<fileName>& badFiles
); );
//- Write SHA1 value as C-comment
bool writeCommentSHA1(Ostream&) const;
//- Copy/create Make/files prior to compilation
bool createMakeFiles() const;
//- Copy/create Make/options prior to compilation
bool createMakeOptions() const;
//- Write digest to Make/SHA1Digest
bool writeDigest(const SHA1Digest&) const;
//- Write digest to Make/SHA1Digest
bool writeDigest(const std::string&) const;
bool writeDigest(const fileName& dir, const SHA1Digest& sha1) const;
SHA1Digest readDigest(const fileName& dir) const;
public: public:
@ -112,26 +157,25 @@ public:
// Used when locating the codeTemplateName via Foam::findEtcFile // Used when locating the codeTemplateName via Foam::findEtcFile
static const fileName codeTemplateDirName; static const fileName codeTemplateDirName;
//- Flag if system operations are allowed
static int allowSystemOperations; static int allowSystemOperations;
// Static Member functions // Static Member functions
//- Check security for creating dynamic code //- Check security for creating dynamic code
static void checkSecurity static void checkSecurity(const char* title, const dictionary&);
(
const char* title,
const dictionary& dict
);
// Constructors // Constructors
//- Construct for a specified code name //- Construct for a specified code name and code directory name
dynamicCode(const word& codeName); // Defaults to using the code name for the code directory name
dynamicCode
//- Construct for a specified code name and directory name (
dynamicCode(const word& codeName, const word& dirName); const word& codeName,
const word& codeDirName = ""
);
// Member functions // Member functions
@ -148,43 +192,76 @@ public:
return codeDirName_; return codeDirName_;
} }
//- Clear variables and files //- Root for dynamic code compilation
// Expanded from \$FOAM_CASE/dynamicCode
const fileName& codeRoot() const
{
return codeRoot_;
}
//- Subdirectory name for loading libraries
// Expanded from platforms/\$WM_OPTIONS/lib
fileName libSubDir() const
{
return libSubDir_;
}
//- Path for specified code name
// Corresponds to codeRoot()/codeDirName()
fileName codePath() const
{
return codeRoot_/codeDirName_;
}
//- Library path for specified code name
// Corresponds to codeRoot()/libSubDir()/lib\<codeName\>.so
fileName libPath() const
{
return codeRoot_/libSubDir_/"lib" + codeName_ + ".so";
}
//- Path for SHA1Digest
// Corresponds to codePath()/Make/SHA1Digest
fileName digestFile() const
{
return codeRoot_/codeDirName_/"Make/SHA1Digest";
}
//- Clear files and variables
void clear(); void clear();
//- Clear files and reset variables to specified context
void reset(const dynamicCodeContext&);
//- Add a file template name, which will be found and filtered
void addCompileFile(const fileName& name);
//- Add a file template name, which will be found and filtered
void addCopyFile(const fileName& name);
//- Add a file to create with its contents. Will not be filtered //- Add a file to create with its contents. Will not be filtered
void addCreateFile(const fileName& name, const string& contents); void addCreateFile(const fileName& name, const string& contents);
//- Add a file template name, which will be found and filtered
void addFilterFile(const fileName& name);
//- Define filter variables for code, codeInclude, SHA1sum //- Define filter variables for code, codeInclude, SHA1sum
void setFilterContext(const dynamicCodeContext&); void setFilterContext(const dynamicCodeContext&);
//- Define a filter variable //- Define a filter variable
void setFilterVariable(const word& key, const string& value); void setFilterVariable(const word& key, const std::string& value);
//- Define contents for Make/options
void setMakeOptions(const std::string& content);
//- Local path for specified code name //- Verify if the copied code is up-to-date, based on Make/SHA1Digest
// Expanded from \$FOAM_CASE/dynamicCode/codeDirName
fileName codePath() const;
//- Local library path for specified code name
// Expanded from \$FOAM_CASE/dynamicCode/platforms/\$WM_OPTIONS/lib
fileName libPath() const;
//- The library target path for Make/files
string libTarget() const;
//- Verify if the copied code is up-to-date
bool upToDate(const dynamicCodeContext& context) const; bool upToDate(const dynamicCodeContext& context) const;
//- Verify if the copied code is up-to-date //- Verify if the copied code is up-to-date, based on Make/SHA1Digest
bool upToDate(const SHA1Digest& sha1) const; bool upToDate(const SHA1Digest& sha1) const;
//- Copy/create files prior to compilation //- Copy/create files prior to compilation
bool copyFilesContents() const; bool copyOrCreateFiles(const bool verbose = false) const;
//- Compile a libso //- Compile a libso
bool wmakeLibso() const; bool wmakeLibso() const;
@ -198,8 +275,6 @@ public:
// //- Find the handle of the libPath() library // //- Find the handle of the libPath() library
// void* findLibrary() const; // void* findLibrary() const;
// bool read(const dictionary&);
// void writeDict(Ostream&) const;
}; };

View File

@ -82,55 +82,47 @@ void Foam::codedFixedValueFvPatchScalarField::createLibrary
( (
dynamicCode& dynCode, dynamicCode& dynCode,
const dynamicCodeContext& context const dynamicCodeContext& context
) ) const
{ {
// Write files for new library // Write files for new library
if (Pstream::master() && !dynCode.upToDate(context)) if (Pstream::master() && !dynCode.upToDate(context))
{ {
Info<< "Creating new library in " << dynCode.libPath() << endl;
dynCode.clear();
// filter with this context // filter with this context
dynCode.setFilterContext(context); dynCode.reset(context);
// filter C/H template // compile filtered C template
dynCode.addFilterFile(codeTemplateC); dynCode.addCompileFile(codeTemplateC);
dynCode.addFilterFile(codeTemplateH);
// Make/files // copy filtered H template
dynCode.addCreateFile dynCode.addCopyFile(codeTemplateH);
// define Make/options
dynCode.setMakeOptions
( (
"Make/files",
codeTemplateC + "\n\n"
+ dynCode.libTarget()
);
// Make/options
dynCode.addCreateFile
(
"Make/options",
"EXE_INC = -g \\\n" "EXE_INC = -g \\\n"
"-I$(LIB_SRC)/finiteVolume/lnInclude\\\n" "-I$(LIB_SRC)/finiteVolume/lnInclude\\\n"
+ context.options() + context.options()
+ "\n\nLIB_LIBS = " + "\n\nLIB_LIBS = "
); );
if (!dynCode.copyFilesContents()) if (!dynCode.copyOrCreateFiles(true))
{ {
FatalIOErrorIn FatalIOErrorIn
( (
"codedFixedValueFvPatchScalarField::writeLibrary(..)", "codedFixedValueFvPatchScalarField::writeLibrary(..)",
context.dict() context.dict()
) << "Failed writing " << nl ) << "Failed writing files for" << nl
// << copyFiles << nl << dynCode.libPath() << nl
// << filesContents
<< exit(FatalIOError); << exit(FatalIOError);
} }
} }
} }
void Foam::codedFixedValueFvPatchScalarField::updateLibrary() void Foam::codedFixedValueFvPatchScalarField::updateLibrary
(
bool firstTime
) const
{ {
dynamicCode::checkSecurity dynamicCode::checkSecurity
( (
@ -138,97 +130,124 @@ void Foam::codedFixedValueFvPatchScalarField::updateLibrary()
dict_ dict_
); );
// use in-line or via codeProperties // use codeProperties or in-line
const bool useInlineDict = dict_.found("code"); const bool useCodeProps = !dict_.found("code");
// determine code context (code, codeInclude, codeOptions) const dictionary& codeDict =
dynamicCodeContext context
( (
useInlineDict useCodeProps
? dict_ ? this->dict().subDict(redirectType_)
: this->dict().subDict(redirectType_) : dict_
); );
// NOTE: probably don't need codeProperties anymore autoPtr<dynamicCodeContext> contextPtr;
// since we use the sha1 directly
if (!useInlineDict)
{
this->dict().setUnmodified();
}
// write code into redirectType_ subdir as well // write code into redirectType_ subdir as well
dynamicCode dynCode(redirectType_); dynamicCode dynCode(redirectType_);
// The version function name - based on the SHA1
const string checkFuncName
(
dynCode.codeName() + "_" + context.sha1().str()
);
const fileName libPath = dynCode.libPath(); const fileName libPath = dynCode.libPath();
// see if library is loaded
void* lib = dlLibraryTable::findLibrary(libPath); void* lib = dlLibraryTable::findLibrary(libPath);
// Load library if not already loaded bool reuseLib = false;
bool reusing = false;
if (!lib && dlLibraryTable::open(libPath, false))
{
lib = dlLibraryTable::findLibrary(libPath);
reusing = true;
}
// library may have loaded, the version may not be correct
bool waiting = false; bool waiting = false;
if (useCodeProps)
{
// library may be loaded, but out-of-date
const codeProperties& codeProps = this->dict();
if (codeProps.modified())
{
codeProps.setUnmodified();
// Remove instantiation of fvPatchField provided by library
redirectPatchFieldPtr_.clear();
contextPtr.reset(new dynamicCodeContext(codeDict));
// unload code
if (lib) if (lib)
{ {
// Unload library if needed firstTime = false;
if (!dlSym(lib, checkFuncName)) reuseLib = false;
{ lib = 0;
reusing = false;
waiting = true;
if (!dlLibraryTable::close(libPath, false)) if (!dlLibraryTable::close(libPath, false))
{ {
FatalIOErrorIn FatalIOErrorIn
( (
"codedFixedValueFvPatchScalarField::updateLibrary(..)", "codedFixedValueFvPatchScalarField::"
context.dict() "updateLibrary()",
contextPtr().dict()
) << "Failed unloading library " ) << "Failed unloading library "
<< libPath << libPath
<< exit(FatalIOError); << exit(FatalIOError);
} }
lib = 0;
} }
}
// unload from all processes
reduce(waiting, orOp<bool>());
} }
// create library // library exists (and was not unloaded) - we can leave now
if (!lib) if (lib)
{ {
if (useInlineDict) return;
{
createLibrary(dynCode, context);
} }
else
{
// Remove instantiation of fvPatchField provided by library // Remove instantiation of fvPatchField provided by library
redirectPatchFieldPtr_.clear(); redirectPatchFieldPtr_.clear();
createLibrary(dynCode, context);
if (contextPtr.empty())
{
contextPtr.reset(new dynamicCodeContext(codeDict));
} }
// function name serving as version control - based on the SHA1
const string sentinelName
= dynCode.codeName() + contextPtr().sha1().str(true);
// avoid compilation (first time only) by loading an existing library
if (firstTime && dlLibraryTable::open(libPath, false))
{
lib = dlLibraryTable::findLibrary(libPath);
// verify the loaded version and unload if needed
if (lib)
{
reuseLib = dlSymFound(lib, sentinelName);
if (!reuseLib)
{
lib = 0;
if (!dlLibraryTable::close(libPath, false))
{
FatalIOErrorIn
(
"codedFixedValueFvPatchScalarField::updateLibrary()",
contextPtr().dict()
) << "Failed unloading library "
<< libPath
<< exit(FatalIOError);
}
}
}
}
// really do need to create library
if (!lib)
{
if (Pstream::master()) if (Pstream::master())
{ {
createLibrary(dynCode, contextPtr());
if (!dynCode.wmakeLibso()) if (!dynCode.wmakeLibso())
{ {
FatalIOErrorIn FatalIOErrorIn
( (
"codedFixedValueFvPatchScalarField::updateLibrary()", "codedFixedValueFvPatchScalarField::updateLibrary()",
dict_ contextPtr().dict()
) << "Failed wmake " << libPath ) << "Failed wmake " << libPath
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -243,33 +262,43 @@ void Foam::codedFixedValueFvPatchScalarField::updateLibrary()
FatalIOErrorIn FatalIOErrorIn
( (
"codedFixedValueFvPatchScalarField::updateLibrary()", "codedFixedValueFvPatchScalarField::updateLibrary()",
dict_ contextPtr().dict()
) << "Failed loading library " << libPath ) << "Failed loading library " << libPath
<< exit(FatalIOError); << exit(FatalIOError);
} }
// paranoid - check that signature function is really there
lib = dlLibraryTable::findLibrary(libPath); lib = dlLibraryTable::findLibrary(libPath);
if (lib) if (!lib)
{
if (!dlSym(lib, checkFuncName))
{ {
FatalIOErrorIn FatalIOErrorIn
( (
"codedFixedValueFvPatchScalarField::updateLibrary(..)", "codedFixedValueFvPatchScalarField::"
dict_ "updateLibrary()",
) << "Library loaded - but wrong version!" contextPtr().dict()
<< libPath ) << "Failed to load library " << libPath
<< exit(FatalIOError); << exit(FatalIOError);
} }
lib = 0;
//#if 0
// Info<<"check " << libPath << " for " << sentinelName << nl;
// // paranoid - check that signature function is really there
// lib = dlLibraryTable::findLibrary(libPath);
// if (!lib || !dlSymFound(lib, sentinelName))
// {
// FatalIOErrorIn
// (
// "codedFixedValueFvPatchScalarField::"
// "updateLibrary()",
// contextPtr().dict()
// ) << "Failed to load library with correct signature "
// << libPath
// << exit(FatalIOError);
// }
//#endif
} }
} else if (reuseLib)
else if (reusing)
{ {
Info<< "Reusing library in " << libPath << nl Info<< "Reusing library in " << libPath << nl;
<< " with " << context.sha1().str() << nl;
} }
} }
@ -284,7 +313,7 @@ codedFixedValueFvPatchScalarField
) )
: :
fixedValueFvPatchField<scalar>(p, iF), fixedValueFvPatchField<scalar>(p, iF),
redirectPatchFieldPtr_(NULL) redirectPatchFieldPtr_()
{} {}
@ -300,7 +329,7 @@ codedFixedValueFvPatchScalarField
fixedValueFvPatchField<scalar>(ptf, p, iF, mapper), fixedValueFvPatchField<scalar>(ptf, p, iF, mapper),
dict_(ptf.dict_), dict_(ptf.dict_),
redirectType_(ptf.redirectType_), redirectType_(ptf.redirectType_),
redirectPatchFieldPtr_(NULL) redirectPatchFieldPtr_()
{} {}
@ -315,9 +344,9 @@ codedFixedValueFvPatchScalarField
fixedValueFvPatchField<scalar>(p, iF, dict), fixedValueFvPatchField<scalar>(p, iF, dict),
dict_(dict), dict_(dict),
redirectType_(dict.lookup("redirectType")), redirectType_(dict.lookup("redirectType")),
redirectPatchFieldPtr_(NULL) redirectPatchFieldPtr_()
{ {
updateLibrary(); updateLibrary(true);
} }
@ -330,7 +359,7 @@ codedFixedValueFvPatchScalarField
fixedValueFvPatchField<scalar>(ptf), fixedValueFvPatchField<scalar>(ptf),
dict_(ptf.dict_), dict_(ptf.dict_),
redirectType_(ptf.redirectType_), redirectType_(ptf.redirectType_),
redirectPatchFieldPtr_(NULL) redirectPatchFieldPtr_()
{} {}
@ -344,7 +373,7 @@ codedFixedValueFvPatchScalarField
fixedValueFvPatchField<scalar>(ptf, iF), fixedValueFvPatchField<scalar>(ptf, iF),
dict_(ptf.dict_), dict_(ptf.dict_),
redirectType_(ptf.redirectType_), redirectType_(ptf.redirectType_),
redirectPatchFieldPtr_(NULL) redirectPatchFieldPtr_()
{} {}
@ -366,6 +395,18 @@ Foam::codedFixedValueFvPatchScalarField::redirectPatchField() const
dictionary dict(is); dictionary dict(is);
Info<< "constructing patchField from :" << dict << endl; Info<< "constructing patchField from :" << dict << endl;
// if (fvPatchScalarField::dictionaryConstructorTablePtr_)
// {
// fvPatchScalarField::dictionaryConstructorPtr funcPtr =
// (
// fvPatchScalarField::dictionaryConstructorTablePtr_->
// find(redirectType_)()
// );
//
// Info<< redirectType_ << " FunctionPtr => "
// << long(funcPtr) << endl;
// }
redirectPatchFieldPtr_.set redirectPatchFieldPtr_.set
( (
fvPatchScalarField::New fvPatchScalarField::New

View File

@ -113,19 +113,21 @@ class codedFixedValueFvPatchScalarField
const codeProperties& dict() const; const codeProperties& dict() const;
void createLibrary(dynamicCode&, const dynamicCodeContext& dict); void createLibrary(dynamicCode&, const dynamicCodeContext&) const;
void updateLibrary(); //- Update library as required
// Use 'firstTime' to alter behaviour
void updateLibrary(bool firstTime=false) const;
public: public:
// Static data members // Static data members
//- Name of the C code template to be used //- Name of the C code template to be used
const static word codeTemplateC; static const word codeTemplateC;
//- Name of the H code template to be used //- Name of the H code template to be used
const static word codeTemplateH; static const word codeTemplateH;
//- Runtime type information //- Runtime type information
@ -217,7 +219,7 @@ public:
); );
//- Write //- Write
virtual void write(Ostream& os) const; virtual void write(Ostream&) const;
}; };