Loading...
Searching...
No Matches
codedBase.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2016-2023 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "codedBase.H"
30#include "SHA1Digest.H"
31#include "dynamicCode.H"
32#include "dynamicCodeContext.H"
33#include "dlLibraryTable.H"
34#include "objectRegistry.H"
35#include "IOdictionary.H"
36#include "Pstream.H"
37#include "PstreamReduceOps.H"
38#include "OSspecific.H"
39#include "Ostream.H"
40#include "Time.H"
41#include "regIOobject.H"
42
43// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44
45namespace Foam
46{
48}
50
51// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
52
53namespace Foam
54{
55
56static inline void writeEntryIfPresent
57(
58 Ostream& os,
59 const dictionary& dict,
60 const word& key
61)
62{
63 const entry* eptr = dict.findEntry(key, keyType::LITERAL);
64 if (!eptr)
65 {
66 // Nothing to do
67 }
68 else if (eptr->isDict())
69 {
70 eptr->dict().writeEntry(os);
71 }
72 else
73 {
74 const tokenList& toks = eptr->stream();
75
76 if (!toks.empty()) // Could also check that it is a string-type
77 {
78 os.writeEntry(key, toks[0]);
79 }
80 }
82
83} // End namespace Foam
84
85
86// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
87
89{
90 writeEntryIfPresent(os, dict, "codeContext");
91 writeEntryIfPresent(os, dict, "codeInclude");
92 writeEntryIfPresent(os, dict, "localCode");
94 writeEntryIfPresent(os, dict, "codeOptions");
95 writeEntryIfPresent(os, dict, "codeLibs");
96}
97
98
101(
102 const objectRegistry& obr,
103 const word& dictName
104)
105{
106 auto* dictptr = obr.getObjectPtr<IOdictionary>(dictName);
107
108 if (!dictptr)
109 {
110 dictptr = new IOdictionary
111 (
113 (
114 dictName,
115 obr.time().system(),
116 obr,
120 )
121 );
122
123 obr.store(dictptr);
124 }
125
126 return *dictptr;
127}
128
129
130// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
131
132void* Foam::codedBase::loadLibrary
133(
134 const fileName& libPath,
135 const std::string& funcName,
136 const dynamicCodeContext& context
137) const
138{
139 // Avoid compilation by loading an existing library
140
141 void* handle = libs().open(libPath, false);
142
143 if (!handle)
144 {
145 return handle;
146 }
147
148 // Verify the loaded version and unload if needed
149
150 // Manual execution of code after loading.
151 // This is mandatory for codedBase.
152
153 const bool ok = libs().loadHook(handle, funcName, false);
154
155 if (!ok)
156 {
157 FatalIOErrorInFunction(context.dict())
158 << "Failed symbol lookup " << funcName.c_str() << nl
159 << "from " << libPath << nl
160 << exit(FatalIOError);
161
162 handle = nullptr;
163 if (!libs().close(libPath, false))
164 {
165 FatalIOErrorInFunction(context.dict())
166 << "Failed unloading library " << libPath << nl
167 << exit(FatalIOError);
168 }
169 }
170
171 return handle;
172}
173
174
175void Foam::codedBase::unloadLibrary
176(
177 const fileName& libPath,
178 const std::string& funcName,
179 const dynamicCodeContext& context
180) const
181{
182 void* handle = libs().open(libPath, false);
183
184 if (!handle)
185 {
186 return;
187 }
188
189 // Manual execution of code before unloading.
190 // This is mandatory for codedBase.
191
192 const bool ok = libs().unloadHook(handle, funcName, false);
193
194 if (!ok)
195 {
196 IOWarningInFunction(context.dict())
197 << "Failed looking up symbol " << funcName << nl
198 << "from " << libPath << nl;
199 }
200
201 if (!libs().close(libPath, false))
202 {
203 FatalIOErrorInFunction(context.dict())
204 << "Failed unloading library " << libPath << nl
205 << exit(FatalIOError);
206 }
207}
208
209
210void Foam::codedBase::createLibrary
211(
212 dynamicCode& dynCode,
213 const dynamicCodeContext& context
214) const
215{
216 // No library?
217 // The overall master should compile it (so only it needs a compiler) and
218 // - see if it appears at the other processors
219 // - or copy it across if it does not
220
221 // Indicates NFS filesystem
222 const bool isNFS = (IOobject::fileModificationSkew > 0);
223
224 if
225 (
226 (UPstream::master() || !isNFS)
227 && !dynCode.upToDate(context)
228 )
229 {
230 // Filter with this context
231 dynCode.reset(context);
232
233 this->prepare(dynCode, context);
234
235 if (!dynCode.copyOrCreateFiles(true))
236 {
237 FatalIOErrorInFunction(context.dict())
238 << "Failed writing files for" << nl
239 << dynCode.libRelPath() << nl
240 << exit(FatalIOError);
241 }
242
243 if (!dynCode.wmakeLibso())
244 {
245 FatalIOErrorInFunction(context.dict())
246 << "Failed wmake " << dynCode.libRelPath() << nl
247 << exit(FatalIOError);
248 }
249 }
250
251 if (isNFS)
252 {
253 // Wait for compile to finish before attempting filesystem polling
255 }
256
257 const fileName libPath = dynCode.libPath();
258
259 // Broadcast to distributed masters
260 if (fileHandler().distributed())
261 {
262 fileHandler().broadcastCopy
263 (
266 libPath,
267 libPath
268 );
269 }
271 dynamicCode::waitForFile(libPath, context.dict());
272}
273
274
275// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
278{
279 context_.setCodeContext(dict);
280}
281
283void Foam::codedBase::append(const std::string& str)
284{
285 context_.append(str);
286}
287
288
290(
291 const word& name,
292 const dynamicCodeContext& context
293) const
294{
296 (
297 "codedBase::updateLibrary()",
298 context.dict()
299 );
300
301 // codeName: name + _<sha1>
302 // codeDir : name
303 dynamicCode dynCode
304 (
305 name + context.sha1().str(true),
306 name
307 );
308
309 const fileName libPath = dynCode.libPath();
310
311
312 // The correct library was already loaded => we are done
313 if (libs().findLibrary(libPath))
314 {
315 return;
316 }
317
319 << "Using dynamicCode for " << this->description().c_str()
320 << " at line " << context.dict().startLineNumber()
321 << " in " << context.dict().name() << endl;
322
323
324 // Remove instantiation of fvPatchField provided by library
325 this->clearRedirect();
326
327 // May need to unload old library
328 unloadLibrary(oldLibPath_, dlLibraryTable::basename(oldLibPath_), context);
329
330 // Try loading an existing library (avoid compilation when possible)
331 void* lib = loadLibrary(libPath, dynCode.codeName(), context);
332
333 if (returnReduceOr(lib == nullptr))
334 {
335 if (lib)
336 {
337 // Ensure consistency
338 unloadLibrary(libPath, dlLibraryTable::basename(libPath), context);
339 }
340
341 createLibrary(dynCode, context);
342
343 loadLibrary(libPath, dynCode.codeName(), context);
345
346 // Retain for future reference
347 oldLibPath_ = libPath;
348}
349
350
352(
353 const word& name,
355) const
356{
358}
359
360
362{
363 if (context_.good())
364 {
365 updateLibrary(name, context_);
366 }
367 else
368 {
369 updateLibrary(name, dynamicCodeContext(this->codeDict()));
370 }
371}
372
373
374// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
static void * loadLibrary(const Foam::fileName &libName)
Definition POSIX.C:111
Inter-processor communication reduction functions.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
@ REGISTER
Request registration (bool: true).
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition IOobject.H:363
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition SHA1I.H:114
const word & system() const noexcept
Return system name.
Definition TimePathsI.H:137
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
static void barrier(const int communicator, UPstream::Request *req=nullptr)
Impose a synchronisation barrier (optionally non-blocking).
Definition UPstream.C:106
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition UPstream.H:1069
Base class for function objects and boundary conditions using dynamic code that provides methods for ...
Definition codedBase.H:63
void updateLibrary(const word &name, const dynamicCodeContext &context) const
Update library as required, using the given context.
Definition codedBase.C:283
virtual void clearRedirect() const =0
void setCodeContext(const dictionary &dict)
Set code context from a dictionary.
Definition codedBase.C:270
virtual dlLibraryTable & libs() const =0
Mutable access to the loaded dynamic libraries.
virtual string description() const =0
void append(const std::string &str)
Add content to SHA1 hashing.
Definition codedBase.C:276
virtual const dictionary & codeDict() const =0
static void writeCodeDict(Ostream &os, const dictionary &dict)
Write code-dictionary contents.
Definition codedBase.C:81
static const dictionary & codeDict(const objectRegistry &obr, const word &dictName="codeDict")
Return "codeDict" from objectRegistry or read from disk.
Definition codedBase.C:94
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
const fileName & name() const noexcept
The dictionary name.
Definition dictionaryI.H:41
void writeEntry(Ostream &os) const
Write sub-dictionary with its dictName as its header.
label startLineNumber() const
Return line number of first token in dictionary.
Definition dictionary.C:198
static word basename(const fileName &libPath)
Library basename without leading 'lib' or trailing '.so'.
Encapsulation of dynamic code dictionaries.
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
const dictionary & dict() const noexcept
Return the parent dictionary context.
Tools for handling dynamic code compilation.
Definition dynamicCode.H:57
static void waitForFile(const fileName &file, const dictionary &contextDict)
Wait for libPath() file to appear on sub-ranks.
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition dynamicCode.C:59
fileName libPath() const
Library path for specified code name.
const word & codeName() const noexcept
Return the code-name.
A keyword and a list of tokens is an 'entry'.
Definition entry.H:66
virtual ITstream & stream() const =0
Return token stream, if entry is a primitive entry.
virtual bool isDict() const noexcept
True if this entry is a dictionary.
Definition entry.H:284
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary, otherwise Fatal.
A class for handling file names.
Definition fileName.H:75
@ LITERAL
String literal.
Definition keyType.H:82
Registry of regIOobjects.
const Time & time() const noexcept
Return time registry.
Type * getObjectPtr(const word &name, const bool recursive=false) const
Return non-const pointer to the object of the given Type, using a const-cast to have it behave like a...
bool store()
Register object with its registry and transfer ownership to the registry.
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
#define DetailInfo
Definition evalEntry.C:30
OBJstream os(runTime.globalPath()/outputName)
const word dictName("faMeshDefinition")
auto & name
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
Namespace for OpenFOAM.
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler().
static void writeEntryIfPresent(Ostream &os, const dictionary &dict, const word &key)
Definition codedBase.C:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
List< token > tokenList
List of token, used for dictionary primitive entry (for example).
Definition tokenList.H:32
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict