codeStream.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-2017 OpenFOAM Foundation
9 Copyright (C) 2018-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 "codeStream.H"
30#include "dynamicCode.H"
31#include "dynamicCodeContext.H"
32#include "StringStream.H"
33#include "Time.H"
35
36// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37
38namespace Foam
39{
40namespace functionEntries
41{
43
45 (
48 execute,
49 dictionaryIstream,
51 );
52
54 (
57 execute,
58 primitiveEntryIstream,
60 );
61} // End namespace functionEntries
62} // End namespace Foam
63
64
65// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
66
68(
69 const dictionary& dict
70)
71{
72 return static_cast<const baseIOdictionary&>(dict.topDict()).time().libs();
73}
74
75
77(
78 const dictionary& dict
79)
80{
81 // Fallback value
82 bool masterOnly = regIOobject::masterOnlyReading;
83
84 const auto* iodictPtr = isA<baseIOdictionary>(dict.topDict());
85
86 if (iodictPtr)
87 {
88 masterOnly = iodictPtr->globalObject();
89
91 << "codeStream : baseIOdictionary:" << dict.name()
92 << " master-only-reading:" << masterOnly << endl;
93 }
94 else
95 {
97 << "codeStream : not a baseIOdictionary:" << dict.name()
98 << " master-only-reading:" << masterOnly << endl;
99 }
100
101 return masterOnly;
102}
103
104
107(
108 const dictionary& parentDict,
109 const dictionary& codeDict
110)
111{
112 // get code, codeInclude, codeOptions
113 dynamicCodeContext context(codeDict);
114
115 // codeName: codeStream + _<sha1>
116 // codeDir : _<sha1>
117 std::string sha1Str(context.sha1().str(true));
118 dynamicCode dynCode("codeStream" + sha1Str, sha1Str);
119
120 // Load library if not already loaded
121 // Version information is encoded in the libPath (encoded with the SHA1)
122 const fileName libPath = dynCode.libPath();
123
124 // see if library is loaded
125 void* lib = nullptr;
126
127 const dictionary& topDict = parentDict.topDict();
128
129 if (isA<baseIOdictionary>(topDict))
130 {
131 lib = libs(parentDict).findLibrary(libPath);
132 }
133
134 // nothing loaded
135 // avoid compilation if possible by loading an existing library
136 if (!lib)
137 {
139 << "Using #codeStream with " << libPath << endl;
140
141 if (isA<baseIOdictionary>(topDict))
142 {
143 // Cached access to libs, with cleanup upon termination
144 lib = libs(parentDict).open(libPath, false);
145 }
146 else
147 {
148 // Uncached opening of libPath. Do not complain if cannot be loaded
149 lib = Foam::dlOpen(libPath, false);
150 }
151 }
152
153
154 // create library if required
155 if (!lib)
156 {
157 const bool create =
159 || (IOobject::fileModificationSkew <= 0); // not NFS
160
161 if (create)
162 {
163 if (!dynCode.upToDate(context))
164 {
165 // filter with this context
166 dynCode.reset(context);
167
168 // compile filtered C template
169 dynCode.addCompileFile(codeTemplateC);
170
171 // define Make/options
172 dynCode.setMakeOptions
173 (
174 "EXE_INC = -g \\\n"
175 + context.options()
176 + "\n\nLIB_LIBS = \\\n"
177 " -lOpenFOAM \\\n"
178 + context.libs()
179 );
180
181 if (!dynCode.copyOrCreateFiles(true))
182 {
183 FatalIOErrorInFunction(parentDict)
184 << "Failed writing files for" << nl
185 << dynCode.libRelPath() << nl
186 << exit(FatalIOError);
187 }
188 }
189
190 if (!dynCode.wmakeLibso())
191 {
192 FatalIOErrorInFunction(parentDict)
193 << "Failed wmake " << dynCode.libRelPath() << nl
194 << exit(FatalIOError);
195 }
196 }
197
198 //- Only block if we're not doing master-only reading. (flag set by
199 // regIOobject::read, baseIOdictionary constructor)
200 if
201 (
202 !doingMasterOnlyReading(topDict)
204 )
205 {
206 //- Since the library has only been compiled on the master the
207 // other nodes need to pick this library up through NFS
208 // We do this by just polling a few times using the
209 // fileModificationSkew.
210
211 off_t mySize = Foam::fileSize(libPath);
212 off_t masterSize = mySize;
213 Pstream::broadcast(masterSize);
214
215 for
216 (
217 label iter = 0;
219 ++iter
220 )
221 {
223 << "on processor " << Pstream::myProcNo()
224 << "masterSize:" << masterSize
225 << " and localSize:" << mySize
226 << endl;
227
228 if (mySize == masterSize)
229 {
230 break;
231 }
232 else if (mySize > masterSize)
233 {
235 << "Excessive size when reading (NFS mounted) library "
236 << nl << libPath << nl
237 << "on processor " << Pstream::myProcNo()
238 << " detected size " << mySize
239 << " whereas master size is " << masterSize
240 << " bytes." << nl
241 << "If your case is NFS mounted increase"
242 << " fileModificationSkew or maxFileModificationPolls;"
243 << nl << "If your case is not NFS mounted"
244 << " (so distributed) set fileModificationSkew"
245 << " to 0"
246 << exit(FatalIOError);
247 }
248 else
249 {
251 << "Local file " << libPath
252 << " not of same size (" << mySize
253 << ") as master ("
254 << masterSize << "). Waiting for "
256 << " seconds." << endl;
257
259
260 // Recheck local size
261 mySize = Foam::fileSize(libPath);
262 }
263 }
264
265
266 // Finished doing iterations. Do final check
267 if (mySize != masterSize)
268 {
270 << "Cannot read (NFS mounted) library " << nl
271 << libPath << nl
272 << "on processor " << Pstream::myProcNo()
273 << " detected size " << mySize
274 << " whereas master size is " << masterSize
275 << " bytes." << nl
276 << "If your case is NFS mounted increase"
277 << " fileModificationSkew or maxFileModificationPolls;"
278 << nl << "If your case is not NFS mounted"
279 << " (so distributed) set fileModificationSkew"
280 << " to 0"
281 << exit(FatalIOError);
282 }
283
285 << "on processor " << Pstream::myProcNo()
286 << " after waiting: have masterSize:" << masterSize
287 << " and localSize:" << mySize << endl;
288 }
289
290 if (isA<baseIOdictionary>(topDict))
291 {
292 // Cached access to libs, with cleanup upon termination
294 << "Opening cached dictionary:" << libPath << endl;
295
296 lib = libs(parentDict).open(libPath, false);
297
298 if (!lib)
299 {
300 FatalIOErrorInFunction(parentDict)
301 << "Failed loading library " << libPath << nl
302 << "Did you add all libraries to the 'libs' entry"
303 << " in system/controlDict?"
304 << exit(FatalIOError);
305 }
306 }
307 else
308 {
309 // Uncached opening of libPath
311 << "Opening uncached dictionary:" << libPath << endl;
312
313 lib = Foam::dlOpen(libPath, true);
314 }
315 }
316
317 bool haveLib = lib;
318 if (!doingMasterOnlyReading(topDict))
319 {
320 reduce(haveLib, andOp<bool>());
321 }
322
323 if (!haveLib)
324 {
325 FatalIOErrorInFunction(parentDict)
326 << "Failed loading library " << libPath
327 << " on some processors."
328 << exit(FatalIOError);
329 }
330
331
332 // Find the function handle in the library
333 streamingFunctionType function =
334 reinterpret_cast<streamingFunctionType>
335 (
336 Foam::dlSym(lib, dynCode.codeName())
337 );
338
339
340 if (!function)
341 {
342 FatalIOErrorInFunction(parentDict)
343 << "Failed looking up symbol " << dynCode.codeName()
344 << " in library " << lib << exit(FatalIOError);
345 }
346
347 return function;
348}
349
350
352(
353 const dictionary& parentDict,
354 Istream& is
355)
356{
358 << "Using #codeStream at line " << is.lineNumber()
359 << " in file " << parentDict.relativeName() << endl;
360
362 (
363 "functionEntries::codeStream::evaluate(..)",
364 parentDict
365 );
366
367 // Get code dictionary
368 dictionary codeDict("#codeStream", parentDict, is);
369
370 // Use function to write stream
371 OStringStream os(is.format());
372
373 streamingFunctionType function = getFunction(parentDict, codeDict);
374 (*function)(os, parentDict);
375
376 // Return evaluated content as string
377 return os.str();
378}
379
380
381// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
382
384(
385 const dictionary& parentDict,
387 Istream& is
388)
389{
390 IStringStream result(evaluate(parentDict, is));
391 entry.read(parentDict, result);
392
393 return true;
394}
395
396
398(
399 dictionary& parentDict,
400 Istream& is
401)
402{
403 IStringStream result(evaluate(parentDict, is));
404 parentDict.read(result);
405
406 return true;
407}
408
409
410// ************************************************************************* //
Input/output from string buffers.
Macros for easy insertion into member function selection tables.
#define addNamedToMemberFunctionSelectionTable(baseType, thisType, funcName, argNames, lookupName)
Add to hash-table of functions with 'lookupName' as the key.
void evaluate()
Evaluate boundary conditions.
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
streamFormat format() const noexcept
Get the current stream format.
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:318
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:112
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:64
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:231
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
baseIOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO function...
virtual dlLibraryTable & libs() const
Mutable access to the loaded dynamic libraries.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
const dictionary & topDict() const
Return the top of the tree.
Definition: dictionary.C:192
fileName relativeName(const bool caseTag=false) const
The dictionary name relative to the case.
Definition: dictionary.C:186
bool read(Istream &is)
Read dictionary from Istream. Discards the header.
Definition: dictionaryIO.C:141
A table of dynamically loaded libraries.
Encapsulation of dynamic code dictionaries.
const string & libs() const noexcept
The code libs (LIB_LIBS)
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
const string & options() const noexcept
The code options (Make/options)
const dictionary & dict() const noexcept
Return the parent dictionary context.
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:60
bool copyOrCreateFiles(const bool verbose=false) const
Copy/create files prior to compilation.
Definition: dynamicCode.C:403
void reset(const dynamicCodeContext &)
Clear files and reset variables to specified context.
Definition: dynamicCode.C:344
fileName libRelPath() const
Library path for specified code name relative to <case>
Definition: dynamicCode.C:321
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:65
void addCompileFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:353
bool upToDate(const dynamicCodeContext &context) const
Verify if the copied code is up-to-date, based on Make/SHA1Digest.
Definition: dynamicCode.C:530
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
bool wmakeLibso() const
Compile a libso.
Definition: dynamicCode.C:495
void setMakeOptions(const std::string &content)
Define contents for Make/options.
Definition: dynamicCode.C:397
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:70
A class for handling file names.
Definition: fileName.H:76
Dictionary entry that contains C++ OpenFOAM code that is compiled to generate the entry itself....
Definition: codeStream.H:119
static bool doingMasterOnlyReading(const dictionary &dict)
Helper: access IOobject for master-only-reading functionality.
Definition: codeStream.C:77
static streamingFunctionType getFunction(const dictionary &parentDict, const dictionary &codeDict)
Construct, compile, load and return streaming function.
Definition: codeStream.C:107
void(* streamingFunctionType)(Ostream &, const dictionary &)
Interpreter function type.
Definition: codeStream.H:123
A functionEntry causes entries to be added/manipulated on the specified dictionary given an input str...
Definition: functionEntry.H:69
virtual bool execute()
Calculate the output fields.
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
virtual const dictionary & dict() const
This entry is not a dictionary,.
int myProcNo() const noexcept
Return processor number.
static bool masterOnlyReading
To flag master-only reading of objects.
Definition: regIOobject.H:87
splitCell * master() const
Definition: splitCell.H:113
A class for handling character strings derived from std::string.
Definition: string.H:79
#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)
#define DebugPout
Report an information message using Foam::Pout.
Namespace for OpenFOAM.
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
void * dlOpen(const fileName &libName, const bool check=true)
Open a shared library and return handle to library.
Definition: MSwindows.C:1224
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: OSspecific.H:295
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