ENH: new encapsulation: dynamicCode, dynamicCodeContext

- improve loading/unloading characteristics for codedFixedValue
  but still needs work
This commit is contained in:
Mark Olesen
2011-02-24 17:14:59 +01:00
parent 51399bbbd1
commit 74bc658fe9
11 changed files with 946 additions and 731 deletions

View File

@ -0,0 +1,479 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2011 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\*---------------------------------------------------------------------------*/
#include "dynamicCode.H"
#include "dynamicCodeContext.H"
#include "stringOps.H"
#include "IFstream.H"
#include "OFstream.H"
#include "OSspecific.H"
#include "dictionary.H"
#include "dlLibraryTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
int Foam::dynamicCode::allowSystemOperations
(
Foam::debug::infoSwitch("allowSystemOperations", 0)
);
const Foam::word Foam::dynamicCode::codeTemplateEnvName
= "FOAM_CODE_TEMPLATES";
const Foam::fileName Foam::dynamicCode::codeTemplateDirName
= "codeTemplates/dynamicCode";
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
void Foam::dynamicCode::checkSecurity
(
const char* title,
const dictionary& dict
)
{
if (isAdministrator())
{
FatalIOErrorIn
(
title,
dict
) << "This code should not be executed by someone with administrator"
<< " rights due to security reasons." << nl
<< "(it writes a shared library which then gets loaded "
<< "using dlopen)"
<< exit(FatalIOError);
}
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::dynamicCode::copyAndFilter
(
ISstream& is,
OSstream& os,
const HashTable<string>& mapping
) const
{
if (!is.good())
{
FatalErrorIn
(
"dynamicCode::copyAndFilter()"
" const"
) << "Failed opening for reading " << is.name()
<< exit(FatalError);
}
if (!os.good())
{
FatalErrorIn
(
"dynamicCode::copyAndFilter()"
" const"
) << "Failed writing " << os.name()
<< exit(FatalError);
}
// Copy file while rewriting $VARS and ${VARS}
string line;
do
{
is.getLine(line);
// expand according to mapping
// expanding according to env variables might cause too many
// surprises
stringOps::inplaceExpand(line, mapping);
os << line.c_str() << nl;
}
while (is.good());
}
Foam::List<Foam::fileName>
Foam::dynamicCode::resolveTemplates(const UList<fileName>& names)
{
// try to get template from FOAM_CODESTREAM_TEMPLATES
const fileName templateDir(Foam::getEnv(codeTemplateEnvName));
DynamicList<fileName> badFiles(names.size());
List<fileName> resolved(names.size());
label nResolved = 0;
forAll(names, fileI)
{
const fileName& templateName = names[fileI];
fileName file;
if (!templateDir.empty() && isDir(templateDir))
{
file = templateDir/templateName;
if (!isFile(file, false))
{
file.clear();
}
}
// not found - fallback to ~OpenFOAM expansion
if (file.empty())
{
file = findEtcFile(codeTemplateDirName/templateName);
}
if (file.empty())
{
badFiles.append(templateName);
}
else
{
resolved[nResolved++] = file;
}
}
resolved.setSize(nResolved);
if (!badFiles.empty())
{
FatalErrorIn
(
"dynamicCode::resolveTemplates(..)"
) << "Could not find the code template(s): "
<< badFiles << nl
<< "Under the $" << codeTemplateDirName
<< " directory or via via the ~OpenFOAM/"
<< codeTemplateDirName << " expansion"
<< exit(FatalError);
}
return resolved;
}
// * * * * * * * * * * * * * * * * 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)
:
codeName_(codeName),
codeDirName_(codeDirName)
{
filterVars_.set("typeName", codeName_);
filterVars_.set("SHA1sum", SHA1Digest().str());
}
// Foam::dynamicCode::dynamicCode(const dynamicCode& dc)
// :
// codeName_(dc.codeName_),
// copyFiles_(dc.copyFiles_),
// filesContents_(dc.filesContents_)
// {}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::dynamicCode::clear()
{
filterVars_.clear();
filterFiles_.clear();
createFiles_.clear();
filterVars_.set("typeName", codeName_);
filterVars_.set("SHA1sum", SHA1Digest().str());
}
void Foam::dynamicCode::addCreateFile
(
const fileName& name,
const string& contents
)
{
createFiles_.append(fileAndContent(name, contents));
}
void Foam::dynamicCode::addFilterFile
(
const fileName& name
)
{
filterFiles_.append(name);
}
void Foam::dynamicCode::setFilterContext
(
const dynamicCodeContext& context
)
{
filterVars_.set("code", context.code());
filterVars_.set("codeInclude", context.include());
filterVars_.set("SHA1sum", context.sha1().str());
}
void Foam::dynamicCode::setFilterVariable
(
const word& key,
const string& value
)
{
filterVars_.set(key, value);
}
Foam::fileName Foam::dynamicCode::codePath() const
{
return stringOps::expand("$FOAM_CASE/dynamicCode/" + codeDirName_);
}
Foam::fileName Foam::dynamicCode::libPath() const
{
return
(
stringOps::expand
(
"$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)
{
FatalErrorIn
(
"dynamicCode::copyFilesContents(const fileName&) const"
) << "Loading a shared library using case-supplied code is not"
<< " enabled by default" << nl
<< "because of security issues. If you trust the code you can"
<< " enable this" << nl
<< "facility be adding to the InfoSwitches setting in the system"
<< " controlDict:" << nl << nl
<< " allowSystemOperations 1" << nl << nl
<< "The system controlDict is either" << nl << nl
<< " ~/.OpenFOAM/$WM_PROJECT_VERSION/controlDict" << nl << nl
<< "or" << nl << nl
<< " $WM_PROJECT_DIR/etc/controlDict" << nl
<< endl
<< exit(FatalError);
}
List<fileName> resolvedFiles = resolveTemplates(filterFiles_);
// Create dir
const fileName outputDir = this->codePath();
// Create dir
mkDir(outputDir);
// Copy/filter files
forAll(resolvedFiles, fileI)
{
const fileName& srcFile = resolvedFiles[fileI];
const fileName dstFile(outputDir/srcFile.name());
IFstream is(srcFile);
//Info<< "Reading from " << is.name() << endl;
if (!is.good())
{
FatalErrorIn
(
"dynamicCode::copyFilesContents(const fileName&)"
" const"
) << "Failed opening " << srcFile
<< exit(FatalError);
}
OFstream os(dstFile);
//Info<< "Writing to " << dstFile.name() << endl;
if (!os.good())
{
FatalErrorIn
(
"dynamicCode::copyFilesContents(const fileName&)"
" const"
) << "Failed writing " << dstFile
<< exit(FatalError);
}
// variables mapping
copyAndFilter(is, os, filterVars_);
}
// Create files:
forAll(createFiles_, fileI)
{
const fileName dstFile
(
outputDir/stringOps::expand(createFiles_[fileI].first())
);
mkDir(dstFile.path());
OFstream os(dstFile);
//Info<< "Writing to " << createFiles_[fileI].first() << endl;
if (!os.good())
{
FatalErrorIn
(
"dynamicCode::copyFilesContents()"
" const"
) << "Failed writing " << dstFile
<< exit(FatalError);
}
os << createFiles_[fileI].second().c_str() << endl;
}
return true;
}
bool Foam::dynamicCode::wmakeLibso() const
{
const Foam::string wmakeCmd("wmake libso " + this->codePath());
Info<< "Invoking " << wmakeCmd << endl;
if (Foam::system(wmakeCmd))
{
return false;
}
else
{
return true;
}
}
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
{
const fileName dirName = this->codePath();
if (!exists(dirName/"SHA1Digest") || readDigest(dirName) != sha1)
{
writeDigest(dirName, sha1);
return false;
}
else
{
return true;
}
}
bool Foam::dynamicCode::upToDate(const dynamicCodeContext& context) const
{
return upToDate(context.sha1());
}
// bool Foam::dynamicCode::openLibrary() const
// {
// return dlLibraryTable::openLibrary(this->libPath(), false);
// }
//
//
// bool Foam::dynamicCode::closeLibrary() const
// {
// return dlLibraryTable::closeLibrary(this->libPath(), false);
// }
//
//
// void* Foam::dynamicCode::findLibrary() const
// {
// return dlLibraryTable::findLibrary(this->libPath());
// }
// 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

@ -0,0 +1,215 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2011 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::dynamicCode
Description
Tools for handling dynamic code compilation
SourceFiles
dynamicCode.C
\*---------------------------------------------------------------------------*/
#ifndef dynamicCode_H
#define dynamicCode_H
#include "Tuple2.H"
#include "SHA1Digest.H"
#include "HashTable.H"
#include "DynamicList.H"
#include "dlLibraryTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
class dynamicCodeContext;
class ISstream;
class OSstream;
/*---------------------------------------------------------------------------*\
Class dynamicCode Declaration
\*---------------------------------------------------------------------------*/
class dynamicCode
{
public:
typedef Tuple2<fileName, string> fileAndContent;
private:
// Private data
//- Name for code
word codeName_;
//- Name for code subdirectory
mutable word codeDirName_;
//- Variables to use during filtering
HashTable<string> filterVars_;
//- Direct contents for files
DynamicList<fileAndContent> createFiles_;
//- Files to copy and filter
DynamicList<fileName> filterFiles_;
protected:
void copyAndFilter
(
ISstream&,
OSstream&,
const HashTable<string>& mapping
) const;
//- Resolve code-templates via the codeTemplateEnvName
// alternatively in the codeTemplateDirName via Foam::findEtcFile
static List<fileName> resolveTemplates
(
const UList<fileName>& names
);
bool writeDigest(const fileName& dir, const SHA1Digest& sha1) const;
SHA1Digest readDigest(const fileName& dir) const;
public:
// Static data members
//- Name of the code template environment variable
// Used to located the codeTemplateName
static const word codeTemplateEnvName;
//- Name of the code template sub-directory
// Used when locating the codeTemplateName via Foam::findEtcFile
static const fileName codeTemplateDirName;
static int allowSystemOperations;
// Static Member functions
//- Check security for creating dynamic code
static void checkSecurity
(
const char* title,
const dictionary& dict
);
// Constructors
//- Construct for a specified code name
dynamicCode(const word& codeName);
//- Construct for a specified code name and directory name
dynamicCode(const word& codeName, const word& dirName);
// Member functions
//- Return the code-name
const word& codeName() const
{
return codeName_;
}
//- Return the code-dirname
const word& codeDirName() const
{
return codeDirName_;
}
//- Clear variables and files
void clear();
//- Add a file to create with its contents. Will not be filtered
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
void setFilterContext(const dynamicCodeContext&);
//- Define a filter variable
void setFilterVariable(const word& key, const string& value);
//- Local path for specified code name
// 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;
//- Verify if the copied code is up-to-date
bool upToDate(const SHA1Digest& sha1) const;
//- Copy/create files prior to compilation
bool copyFilesContents() const;
//- Compile a libso
bool wmakeLibso() const;
// //- Open the libPath() library
// bool openLibrary() const;
//
// //- Close the libPath() library
// bool closeLibrary() const;
//
// //- Find the handle of the libPath() library
// void* findLibrary() const;
// bool read(const dictionary&);
// void writeDict(Ostream&) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2011 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\*---------------------------------------------------------------------------*/
#include "dynamicCodeContext.H"
#include "stringOps.H"
#include "OSHA1stream.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::dynamicCodeContext::dynamicCodeContext(const dictionary& dict)
:
dict_(dict),
code_(stringOps::trim(dict["code"])),
include_(),
options_()
{
// expand dictionary entries
stringOps::inplaceExpand(code_, dict);
// note: removes any leading/trailing whitespace
// - necessary for compilation options, convenient for includes
// and body.
// optional
if (dict.found("codeInclude"))
{
include_ = stringOps::trim(dict["codeInclude"]);
stringOps::inplaceExpand(include_, dict);
}
// optional
if (dict.found("codeOptions"))
{
options_ = stringOps::trim(dict["codeOptions"]);
stringOps::inplaceExpand(options_, dict);
}
// calculate SHA1 digest from include, options, code
OSHA1stream os;
os << include_ << options_ << code_;
sha1_ = os.digest();
}
// ************************************************************************* //

View File

@ -0,0 +1,120 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2011 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::dynamicCodeContext
Description
Encapsulation of dynamic code dictionaries
SourceFiles
dynamicCodeContext.C
\*---------------------------------------------------------------------------*/
#ifndef dynamicCodeContext_H
#define dynamicCodeContext_H
#include "dictionary.H"
#include "SHA1Digest.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class dynamicCodeContext Declaration
\*---------------------------------------------------------------------------*/
class dynamicCodeContext
{
// Private data
//- The parent dictionary context
const dictionary& dict_;
//- Mandatory "code" entry
string code_;
//- Optional "codeInclude" entry
string include_;
//- Optional "codeOptions" entry
string options_;
//- Calculated SHA1Digest
SHA1Digest sha1_;
public:
// Constructors
//- Construct from a dictionary
dynamicCodeContext(const dictionary&);
// Member functions
//- Return the parent dictionary context
const dictionary& dict() const
{
return dict_;
}
//- Return the code-includes
const string& include() const
{
return include_;
}
//- Return the code-options
const string& options() const
{
return options_;
}
//- Return the code
const string& code() const
{
return code_;
}
//- Return SHA1 digest calculated from include, options, code
const SHA1Digest& sha1() const
{
return sha1_;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //