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-2021 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}
49
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 }
81}
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");
93 writeEntryIfPresent(os, dict, "code");
94 writeEntryIfPresent(os, dict, "codeOptions");
95 writeEntryIfPresent(os, dict, "codeLibs");
96}
97
98
101(
102 const objectRegistry& obr,
103 const word& dictName
104)
105{
107
108 if (!dictptr)
109 {
110 dictptr = new IOdictionary
111 (
113 (
114 dictName,
115 obr.time().system(),
116 obr,
119 )
120 );
121
122 obr.store(dictptr);
123 }
124
125 return *dictptr;
126}
127
128
129// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
130
131void* Foam::codedBase::loadLibrary
132(
133 const fileName& libPath,
134 const std::string& funcName,
135 const dynamicCodeContext& context
136) const
137{
138 // Avoid compilation by loading an existing library
139
140 void* handle = libs().open(libPath, false);
141
142 if (!handle)
143 {
144 return handle;
145 }
146
147 // Verify the loaded version and unload if needed
148
149 // Manual execution of code after loading.
150 // This is mandatory for codedBase.
151
152 const bool ok = libs().loadHook(handle, funcName, false);
153
154 if (!ok)
155 {
157 << "Failed symbol lookup " << funcName.c_str() << nl
158 << "from " << libPath << nl
159 << exit(FatalIOError);
160
161 handle = nullptr;
162 if (!libs().close(libPath, false))
163 {
165 << "Failed unloading library " << libPath << nl
166 << exit(FatalIOError);
167 }
168 }
169
170 return handle;
171}
172
173
174void Foam::codedBase::unloadLibrary
175(
176 const fileName& libPath,
177 const std::string& funcName,
178 const dynamicCodeContext& context
179) const
180{
181 void* handle = libs().open(libPath, false);
182
183 if (!handle)
184 {
185 return;
186 }
187
188 // Manual execution of code before unloading.
189 // This is mandatory for codedBase.
190
191 const bool ok = libs().unloadHook(handle, funcName, false);
192
193 if (!ok)
194 {
195 IOWarningInFunction(context.dict())
196 << "Failed looking up symbol " << funcName << nl
197 << "from " << libPath << nl;
198 }
199
200 if (!libs().close(libPath, false))
201 {
202 FatalIOErrorInFunction(context.dict())
203 << "Failed unloading library " << libPath << nl
204 << exit(FatalIOError);
205 }
206}
207
208
209void Foam::codedBase::createLibrary
210(
211 dynamicCode& dynCode,
212 const dynamicCodeContext& context
213) const
214{
215 bool create =
217 || (IOobject::fileModificationSkew <= 0); // not NFS
218
219 if (create)
220 {
221 // Write files for new library
222 if (!dynCode.upToDate(context))
223 {
224 // filter with this context
225 dynCode.reset(context);
226
227 this->prepare(dynCode, context);
228
229 if (!dynCode.copyOrCreateFiles(true))
230 {
231 FatalIOErrorInFunction(context.dict())
232 << "Failed writing files for" << nl
233 << dynCode.libRelPath() << nl
234 << exit(FatalIOError);
235 }
236 }
237
238 if (!dynCode.wmakeLibso())
239 {
240 FatalIOErrorInFunction(context.dict())
241 << "Failed wmake " << dynCode.libRelPath() << nl
242 << exit(FatalIOError);
243 }
244 }
245
246
247 // all processes must wait for compile to finish
249 {
250 //- Since the library has only been compiled on the master the
251 // other nodes need to pick this library up through NFS
252 // We do this by just polling a few times using the
253 // fileModificationSkew.
254
255 const fileName libPath = dynCode.libPath();
256
257 off_t mySize = Foam::fileSize(libPath);
258 off_t masterSize = mySize;
259 Pstream::broadcast(masterSize);
260
261 for
262 (
263 label iter = 0;
265 ++iter
266 )
267 {
269 << "on processor " << Pstream::myProcNo()
270 << " have masterSize:" << masterSize
271 << " and localSize:" << mySize
272 << endl;
273
274 if (mySize == masterSize)
275 {
276 break;
277 }
278 else if (mySize > masterSize)
279 {
280 FatalIOErrorInFunction(context.dict())
281 << "Excessive size when reading (NFS mounted) library "
282 << nl << libPath << nl
283 << "on processor " << Pstream::myProcNo()
284 << " detected size " << mySize
285 << " whereas master size is " << masterSize
286 << " bytes." << nl
287 << "If your case is NFS mounted increase"
288 << " fileModificationSkew or maxFileModificationPolls;"
289 << nl << "If your case is not NFS mounted"
290 << " (so distributed) set fileModificationSkew"
291 << " to 0"
292 << exit(FatalIOError);
293 }
294 else
295 {
297 << "Local file " << libPath
298 << " not of same size (" << mySize
299 << ") as master ("
300 << masterSize << "). Waiting for "
302 << " seconds." << endl;
303
305
306 // Recheck local size
307 mySize = Foam::fileSize(libPath);
308 }
309 }
310
311
312 // Finished doing iterations. Do final check
313 if (mySize != masterSize)
314 {
315 FatalIOErrorInFunction(context.dict())
316 << "Cannot read (NFS mounted) library " << nl
317 << libPath << nl
318 << "on processor " << Pstream::myProcNo()
319 << " detected size " << mySize
320 << " whereas master size is " << masterSize
321 << " bytes." << nl
322 << "If your case is NFS mounted increase"
323 << " fileModificationSkew or maxFileModificationPolls;"
324 << nl << "If your case is not NFS mounted"
325 << " (so distributed) set fileModificationSkew"
326 << " to 0"
327 << exit(FatalIOError);
328 }
329
331 << "on processor " << Pstream::myProcNo()
332 << " after waiting: have masterSize:" << masterSize
333 << " and localSize:" << mySize << endl;
334 }
335 reduce(create, orOp<bool>());
336}
337
338
339// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
340
342{
343 context_.setCodeContext(dict);
344}
345
346
347void Foam::codedBase::append(const std::string& str)
348{
349 context_.append(str);
350}
351
352
354(
355 const word& name,
356 const dynamicCodeContext& context
357) const
358{
360 (
361 "codedBase::updateLibrary()",
362 context.dict()
363 );
364
365 // codeName: name + _<sha1>
366 // codeDir : name
367 dynamicCode dynCode
368 (
369 name + context.sha1().str(true),
370 name
371 );
372
373 const fileName libPath = dynCode.libPath();
374
375
376 // The correct library was already loaded => we are done
377 if (libs().findLibrary(libPath))
378 {
379 return;
380 }
381
383 << "Using dynamicCode for " << this->description().c_str()
384 << " at line " << context.dict().startLineNumber()
385 << " in " << context.dict().name() << endl;
386
387
388 // Remove instantiation of fvPatchField provided by library
389 this->clearRedirect();
390
391 // May need to unload old library
392 unloadLibrary
393 (
394 oldLibPath_,
395 dlLibraryTable::basename(oldLibPath_),
396 context
397 );
398
399 // Try loading an existing library (avoid compilation when possible)
400 if (!loadLibrary(libPath, dynCode.codeName(), context))
401 {
402 createLibrary(dynCode, context);
403
404 loadLibrary(libPath, dynCode.codeName(), context);
405 }
406
407 // Retain for future reference
408 oldLibPath_ = libPath;
409}
410
411
413(
414 const word& name,
415 const dictionary& dict
416) const
417{
418 updateLibrary(name, dynamicCodeContext(dict));
419}
420
421
423{
424 if (context_.valid())
425 {
426 updateLibrary(name, context_);
427 }
428 else
429 {
430 updateLibrary(name, dynamicCodeContext(this->codeDict()));
431 }
432}
433
434
435// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Inter-processor communication reduction functions.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition: IOobject.H:306
static int maxFileModificationPolls
Max number of times to poll for file modification changes.
Definition: IOobject.H:309
@ MUST_READ_IF_MODIFIED
Definition: IOobject.H:180
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:239
static void broadcast(Type &value, const label comm=UPstream::worldComm)
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1I.H:121
const word & system() const
Return system name.
Definition: TimePathsI.H:102
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:427
Base class for function objects and boundary conditions using dynamic code that provides methods for ...
Definition: codedBase.H:67
void updateLibrary(const word &name, const dynamicCodeContext &context) const
Update library as required, using the given context.
Definition: codedBase.C:354
void setCodeContext(const dictionary &dict)
Set code context from a dictionary.
Definition: codedBase.C:341
virtual const dictionary & codeDict() const =0
static void writeCodeDict(Ostream &os, const dictionary &dict)
Write code-dictionary contents.
Definition: codedBase.C:88
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
const fileName & name() const noexcept
The dictionary name.
Definition: dictionaryI.H:48
entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX)
Find for an entry (non-const access) with the given keyword.
Definition: dictionaryI.H:97
void writeEntry(Ostream &os) const
Write sub-dictionary with its dictName as its header.
Definition: dictionaryIO.C:164
label startLineNumber() const
Return line number of first token in dictionary.
Definition: dictionary.C:205
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:60
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:65
fileName libPath() const
Library path for specified code name.
Definition: dynamicCode.C:315
const word & codeName() const
Return the code-name.
Definition: dynamicCode.H:189
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:70
virtual ITstream & stream() const =0
Return token stream, if entry is a primitive entry.
virtual bool isDict() const noexcept
Return true if this entry is a dictionary.
Definition: entry.H:233
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary.
A class for handling file names.
Definition: fileName.H:76
@ LITERAL
String literal.
Definition: keyType.H:81
Registry of regIOobjects.
const Time & time() const noexcept
Return time registry.
Type * getObjectPtr(const word &name, const bool recursive=false) const
int myProcNo() const noexcept
Return processor number.
splitCell * master() const
Definition: splitCell.H:113
bool append() const noexcept
True if output format uses an append mode.
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
#define DetailInfo
Definition: evalEntry.C:37
OBJstream os(runTime.globalPath()/outputName)
const word dictName("faMeshDefinition")
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
#define DebugPout
Report an information message using Foam::Pout.
bitSet create(const label n, const labelHashSet &locations, const bool on=true)
Create a bitSet with length n with the specified on locations.
Definition: BitOps.C:212
Namespace for OpenFOAM.
static void writeEntryIfPresent(Ostream &os, const dictionary &dict, const word &key)
Definition: codedBase.C:57
unsigned int sleep(const unsigned int sec)
Sleep for the specified number of seconds.
Definition: MSwindows.C:1114
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
off_t fileSize(const fileName &name, const bool followLink=true)
Return size of file or -1 on failure (normally follows symbolic links).
Definition: MSwindows.C:684
IOerror FatalIOError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict