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 -------------------------------------------------------------------------------
11 License
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 
38 namespace Foam
39 {
40 namespace functionEntries
41 {
42  defineTypeNameAndDebug(codeStream, 0);
43 
45  (
46  functionEntry,
47  codeStream,
48  execute,
49  dictionaryIstream,
50  codeStream
51  );
52 
54  (
55  functionEntry,
56  codeStream,
57  execute,
58  primitiveEntryIstream,
59  codeStream
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 
90  DebugPout
91  << "codeStream : baseIOdictionary:" << dict.name()
92  << " master-only-reading:" << masterOnly << endl;
93  }
94  else
95  {
96  DebugPout
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  {
138  DetailInfo
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 =
158  Pstream::master()
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)
203  && IOobject::fileModificationSkew > 0
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::scatter(masterSize);
214 
215  for
216  (
217  label iter = 0;
218  iter < IOobject::maxFileModificationPolls;
219  ++iter
220  )
221  {
222  DebugPout
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  {
234  FatalIOErrorInFunction(context.dict())
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  {
250  DebugPout
251  << "Local file " << libPath
252  << " not of same size (" << mySize
253  << ") as master ("
254  << masterSize << "). Waiting for "
255  << IOobject::fileModificationSkew
256  << " seconds." << endl;
257 
258  Foam::sleep(IOobject::fileModificationSkew);
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  {
269  FatalIOErrorInFunction(context.dict())
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 
284  DebugPout
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
293  DebugPout
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
310  DebugPout
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 {
357  DetailInfo
358  << "Using #codeStream at line " << is.lineNumber()
359  << " in file " << parentDict.relativeName() << endl;
360 
361  dynamicCode::checkSecurity
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 // ************************************************************************* //
Foam::entry
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:67
Foam::PackedList::reset
void reset()
Clear all bits but do not adjust the addressable size.
Definition: PackedListI.H:505
Foam::BitSetOps::create
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:123
Foam::dlLibraryTable
A table of dynamically loaded libraries.
Definition: dlLibraryTable.H:63
Foam::primitiveEntry
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
Definition: primitiveEntry.H:63
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
Foam::SHA1::str
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1I.H:122
codeStream.H
Foam::dynamicCode
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:59
Foam::functionEntries::codeStream::evaluate
static string evaluate(const dictionary &parentDict, Istream &is)
Evaluate dynamically compiled code, returning result as string.
Definition: codeStream.C:352
Foam::dynamicCodeContext
Encapsulation of dynamic code dictionaries.
Definition: dynamicCodeContext.H:53
Foam::functionEntries::defineTypeNameAndDebug
defineTypeNameAndDebug(codeStream, 0)
Foam::IOstreamOption::format
streamFormat format() const noexcept
Get the current stream format.
Definition: IOstreamOption.H:286
Foam::IOstream::lineNumber
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:318
StringStream.H
Input/output from string buffers.
Foam::FatalIOError
IOerror FatalIOError
Foam::functionEntries::codeStream::execute
static bool execute(const dictionary &parentDict, primitiveEntry &entry, Istream &is)
Execute in a primitiveEntry context.
Definition: codeStream.C:384
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::string
A class for handling character strings derived from std::string.
Definition: string.H:76
Foam::dynamicCodeContext::dict
const dictionary & dict() const noexcept
Return the parent dictionary context.
Definition: dynamicCodeContext.H:128
dynamicCodeContext.H
Foam::functionEntries::codeStream::getFunction
static streamingFunctionType getFunction(const dictionary &parentDict, const dictionary &codeDict)
Construct, compile, load and return streaming function.
Definition: codeStream.C:107
Foam::dynamicCodeContext::sha1
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
Definition: dynamicCodeContext.H:164
Foam::functionEntries::codeStream::streamingFunctionType
void(* streamingFunctionType)(Ostream &, const dictionary &)
Interpreter function type.
Definition: codeStream.H:123
Foam::fileSize
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:676
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:61
Foam::dictionary::relativeName
fileName relativeName(const bool caseTag=false) const
The dictionary name relative to the case.
Definition: dictionary.C:186
Foam::dlSym
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: OSspecific.H:289
Foam::functionEntries::codeStream::libs
static dlLibraryTable & libs(const dictionary &dict)
Helper function: access to dlLibraryTable of Time.
Definition: codeStream.C:68
Foam::baseIOdictionary
baseIOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO function...
Definition: baseIOdictionary.H:56
addToMemberFunctionSelectionTable.H
Macros for easy insertion into member function selection tables.
Foam::andOp
Definition: ops.H:233
dynamicCode.H
DetailInfo
#define DetailInfo
Definition: evalEntry.C:37
Foam::dynamicCodeContext::libs
const string & libs() const noexcept
The code libs (LIB_LIBS)
Definition: dynamicCodeContext.H:140
Foam::dictionary::topDict
const dictionary & topDict() const
Return the top of the tree.
Definition: dictionary.C:192
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
reduce
reduce(hasMovingMesh, orOp< bool >())
os
OBJstream os(runTime.globalPath()/outputName)
Foam::functionEntries::addNamedToMemberFunctionSelectionTable
addNamedToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream, calc)
Foam::IStringStream
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:108
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
DebugPout
#define DebugPout
Report an information message using Foam::Pout.
Definition: messageStream.H:393
Foam::dictionary::read
bool read(Istream &is)
Read dictionary from Istream. Discards the header.
Definition: dictionaryIO.C:141
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::functionEntries::codeStream::doingMasterOnlyReading
static bool doingMasterOnlyReading(const dictionary &dict)
Helper: access IOobject for master-only-reading functionality.
Definition: codeStream.C:77
Time.H
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::OStringStream
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:227
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
Foam::sleep
unsigned int sleep(const unsigned int sec)
Sleep for the specified number of seconds.
Definition: MSwindows.C:1106
Foam::dynamicCodeContext::options
const string & options() const noexcept
The code options (Make/options)
Definition: dynamicCodeContext.H:134
Foam::dlOpen
void * dlOpen(const fileName &libName, const bool check=true)
Open a shared library and return handle to library.
Definition: MSwindows.C:1216
Foam::stringOps::evaluate
string evaluate(label fieldWidth, const std::string &s, size_t pos=0, size_t len=std::string::npos)
String evaluation with specified (positive, non-zero) field width.
Definition: stringOpsEvaluate.C:37