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-2020 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"
31 #include "StringStream.H"
32 #include "dynamicCode.H"
33 #include "dynamicCodeContext.H"
34 #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  const baseIOdictionary& d = static_cast<const baseIOdictionary&>
73  (
74  dict.topDict()
75  );
76  return d.time().libs();
77 }
78 
79 
81 (
82  const dictionary& dict
83 )
84 {
85  const dictionary& topDict = dict.topDict();
86 
87  if (isA<baseIOdictionary>(topDict))
88  {
89  const baseIOdictionary& d = static_cast<const baseIOdictionary&>
90  (
91  topDict
92  );
93 
94  DebugPout
95  << "codeStream : baseIOdictionary:" << dict.name()
96  << " master-only-reading:" << d.globalObject() << endl;
97 
98  return d.globalObject();
99  }
100 
101  DebugPout
102  << "codeStream : not a baseIOdictionary:" << dict.name()
103  << " master-only-reading:" << regIOobject::masterOnlyReading << endl;
104 
105  // Fall back to regIOobject::masterOnlyReading
106  return regIOobject::masterOnlyReading;
107 }
108 
109 
112 (
113  const dictionary& parentDict,
114  const dictionary& codeDict
115 )
116 {
117  // get code, codeInclude, codeOptions
118  dynamicCodeContext context(codeDict);
119 
120  // codeName: codeStream + _<sha1>
121  // codeDir : _<sha1>
122  std::string sha1Str(context.sha1().str(true));
123  dynamicCode dynCode("codeStream" + sha1Str, sha1Str);
124 
125  // Load library if not already loaded
126  // Version information is encoded in the libPath (encoded with the SHA1)
127  const fileName libPath = dynCode.libPath();
128 
129  // see if library is loaded
130  void* lib = nullptr;
131 
132  const dictionary& topDict = parentDict.topDict();
133 
134  if (isA<baseIOdictionary>(topDict))
135  {
136  lib = libs(parentDict).findLibrary(libPath);
137  }
138 
139  // nothing loaded
140  // avoid compilation if possible by loading an existing library
141  if (!lib)
142  {
143  DetailInfo
144  << "Using #codeStream with " << libPath << endl;
145 
146  if (isA<baseIOdictionary>(topDict))
147  {
148  // Cached access to libs, with cleanup upon termination
149  lib = libs(parentDict).open(libPath, false);
150  }
151  else
152  {
153  // Uncached opening of libPath. Do not complain if cannot be loaded
154  lib = Foam::dlOpen(libPath, false);
155  }
156  }
157 
158 
159  // create library if required
160  if (!lib)
161  {
162  const bool create =
163  Pstream::master()
164  || (regIOobject::fileModificationSkew <= 0); // not NFS
165 
166  if (create)
167  {
168  if (!dynCode.upToDate(context))
169  {
170  // filter with this context
171  dynCode.reset(context);
172 
173  // compile filtered C template
174  dynCode.addCompileFile(codeTemplateC);
175 
176  // define Make/options
177  dynCode.setMakeOptions
178  (
179  "EXE_INC = -g \\\n"
180  + context.options()
181  + "\n\nLIB_LIBS = \\\n"
182  " -lOpenFOAM \\\n"
183  + context.libs()
184  );
185 
186  if (!dynCode.copyOrCreateFiles(true))
187  {
188  FatalIOErrorInFunction(parentDict)
189  << "Failed writing files for" << nl
190  << dynCode.libRelPath() << nl
191  << exit(FatalIOError);
192  }
193  }
194 
195  if (!dynCode.wmakeLibso())
196  {
197  FatalIOErrorInFunction(parentDict)
198  << "Failed wmake " << dynCode.libRelPath() << nl
199  << exit(FatalIOError);
200  }
201  }
202 
203  //- Only block if we're not doing master-only reading. (flag set by
204  // regIOobject::read, baseIOdictionary constructor)
205  if
206  (
207  !doingMasterOnlyReading(topDict)
208  && regIOobject::fileModificationSkew > 0
209  )
210  {
211  //- Since the library has only been compiled on the master the
212  // other nodes need to pick this library up through NFS
213  // We do this by just polling a few times using the
214  // fileModificationSkew.
215 
216  off_t mySize = Foam::fileSize(libPath);
217  off_t masterSize = mySize;
218  Pstream::scatter(masterSize);
219 
220  for
221  (
222  label iter = 0;
223  iter < regIOobject::maxFileModificationPolls;
224  iter++
225  )
226  {
227  DebugPout
228  << "on processor " << Pstream::myProcNo()
229  << "masterSize:" << masterSize
230  << " and localSize:" << mySize
231  << endl;
232 
233  if (mySize == masterSize)
234  {
235  break;
236  }
237  else if (mySize > masterSize)
238  {
239  FatalIOErrorInFunction(context.dict())
240  << "Excessive size when reading (NFS mounted) library "
241  << nl << libPath << nl
242  << "on processor " << Pstream::myProcNo()
243  << " detected size " << mySize
244  << " whereas master size is " << masterSize
245  << " bytes." << nl
246  << "If your case is NFS mounted increase"
247  << " fileModificationSkew or maxFileModificationPolls;"
248  << nl << "If your case is not NFS mounted"
249  << " (so distributed) set fileModificationSkew"
250  << " to 0"
251  << exit(FatalIOError);
252  }
253  else
254  {
255  DebugPout
256  << "Local file " << libPath
257  << " not of same size (" << mySize
258  << ") as master ("
259  << masterSize << "). Waiting for "
260  << regIOobject::fileModificationSkew
261  << " seconds." << endl;
262 
263  Foam::sleep(regIOobject::fileModificationSkew);
264 
265  // Recheck local size
266  mySize = Foam::fileSize(libPath);
267  }
268  }
269 
270 
271  // Finished doing iterations. Do final check
272  if (mySize != masterSize)
273  {
274  FatalIOErrorInFunction(context.dict())
275  << "Cannot read (NFS mounted) library " << nl
276  << libPath << nl
277  << "on processor " << Pstream::myProcNo()
278  << " detected size " << mySize
279  << " whereas master size is " << masterSize
280  << " bytes." << nl
281  << "If your case is NFS mounted increase"
282  << " fileModificationSkew or maxFileModificationPolls;"
283  << nl << "If your case is not NFS mounted"
284  << " (so distributed) set fileModificationSkew"
285  << " to 0"
286  << exit(FatalIOError);
287  }
288 
289  DebugPout
290  << "on processor " << Pstream::myProcNo()
291  << " after waiting: have masterSize:" << masterSize
292  << " and localSize:" << mySize << endl;
293  }
294 
295  if (isA<baseIOdictionary>(topDict))
296  {
297  // Cached access to libs, with cleanup upon termination
298  DebugPout
299  << "Opening cached dictionary:" << libPath << endl;
300 
301  lib = libs(parentDict).open(libPath, false);
302 
303  if (!lib)
304  {
305  FatalIOErrorInFunction(parentDict)
306  << "Failed loading library " << libPath << nl
307  << "Did you add all libraries to the 'libs' entry"
308  << " in system/controlDict?"
309  << exit(FatalIOError);
310  }
311  }
312  else
313  {
314  // Uncached opening of libPath
315  DebugPout
316  << "Opening uncached dictionary:" << libPath << endl;
317 
318  lib = Foam::dlOpen(libPath, true);
319  }
320  }
321 
322  bool haveLib = lib;
323  if (!doingMasterOnlyReading(topDict))
324  {
325  reduce(haveLib, andOp<bool>());
326  }
327 
328  if (!haveLib)
329  {
330  FatalIOErrorInFunction(parentDict)
331  << "Failed loading library " << libPath
332  << " on some processors."
333  << exit(FatalIOError);
334  }
335 
336 
337  // Find the function handle in the library
338  streamingFunctionType function =
339  reinterpret_cast<streamingFunctionType>
340  (
341  Foam::dlSym(lib, dynCode.codeName())
342  );
343 
344 
345  if (!function)
346  {
347  FatalIOErrorInFunction(parentDict)
348  << "Failed looking up symbol " << dynCode.codeName()
349  << " in library " << lib << exit(FatalIOError);
350  }
351 
352  return function;
353 }
354 
355 
357 (
358  const dictionary& parentDict,
359  Istream& is
360 )
361 {
362  DetailInfo
363  << "Using #codeStream at line " << is.lineNumber()
364  << " in file " << parentDict.name() << endl;
365 
366  dynamicCode::checkSecurity
367  (
368  "functionEntries::codeStream::evaluate(..)",
369  parentDict
370  );
371 
372  // Get code dictionary
373  dictionary codeDict("#codeStream", parentDict, is);
374 
375  // Use function to write stream
376  OStringStream os(is.format());
377 
378  streamingFunctionType function = getFunction(parentDict, codeDict);
379  (*function)(os, parentDict);
380 
381  // Return evaluated content as string
382  return os.str();
383 }
384 
385 
386 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
387 
389 (
390  const dictionary& parentDict,
392  Istream& is
393 )
394 {
395  IStringStream result(evaluate(parentDict, is));
396  entry.read(parentDict, result);
397 
398  return true;
399 }
400 
401 
403 (
404  dictionary& parentDict,
405  Istream& is
406 )
407 {
408  IStringStream result(evaluate(parentDict, is));
409  parentDict.read(result);
410 
411  return true;
412 }
413 
414 
415 // ************************************************************************* //
Foam::dynamicCodeContext::libs
const string & libs() const
Return the code-libs.
Definition: dynamicCodeContext.H:146
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:495
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:69
Foam::SHA1::str
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1I.H:123
codeStream.H
Foam::dynamicCode
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:59
Foam::dynamicCodeContext::dict
const dictionary & dict() const
Return the parent dictionary context.
Definition: dynamicCodeContext.H:128
Foam::functionEntries::codeStream::evaluate
static string evaluate(const dictionary &parentDict, Istream &is)
Evaluate dynamically compiled code, returning result as string.
Definition: codeStream.C:357
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:289
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:389
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::string
A class for handling character strings derived from std::string.
Definition: string.H:73
dynamicCodeContext.H
Foam::IOobject::time
const Time & time() const
Return time.
Definition: IOobject.C:463
Foam::functionEntries::codeStream::getFunction
static streamingFunctionType getFunction(const dictionary &parentDict, const dictionary &codeDict)
Construct, compile, load and return streaming function.
Definition: codeStream.C:112
Foam::functionEntries::codeStream::streamingFunctionType
void(* streamingFunctionType)(Ostream &, const dictionary &)
Interpreter function type.
Definition: codeStream.H:123
Foam::dictionary::name
const fileName & name() const
The dictionary name.
Definition: dictionary.H:446
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::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::IOobject::globalObject
bool globalObject() const
Is object same for all processors?
Definition: IOobjectI.H:124
Foam::baseIOdictionary
baseIOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO function...
Definition: baseIOdictionary.H:57
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:36
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:121
reduce
reduce(hasMovingMesh, orOp< bool >())
Foam::Time::libs
dlLibraryTable & libs() const
Mutable access to the loaded dynamic libraries.
Definition: Time.H:505
Foam::dynamicCodeContext::options
const string & options() const
Return the code-options.
Definition: dynamicCodeContext.H:140
Foam::functionEntries::addNamedToMemberFunctionSelectionTable
addNamedToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream, calc)
Foam::IStringStream
Input from string buffer, using a ISstream.
Definition: StringStream.H:111
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
DebugPout
#define DebugPout
Report an information message using Foam::Pout.
Definition: messageStream.H:370
Foam::dictionary::read
bool read(Istream &is)
Read dictionary from Istream.
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:81
Time.H
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::OStringStream
Output to string buffer, using a OSstream.
Definition: StringStream.H:196
Foam::IOstream::lineNumber
label lineNumber() const
Const access to the current stream line number.
Definition: IOstream.H:309
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:401
Foam::dynamicCodeContext::sha1
const SHA1 & sha1() const
Return SHA1 calculated from options, libs, include, code.
Definition: dynamicCodeContext.H:164
Foam::sleep
unsigned int sleep(const unsigned int sec)
Sleep for the specified number of seconds.
Definition: MSwindows.C:1096
Foam::dlOpen
void * dlOpen(const fileName &libName, const bool check=true)
Open a shared library and return handle to library.
Definition: MSwindows.C:1206
Foam::stringOps::evaluate
string evaluate(const std::string &s, size_t pos=0, size_t len=std::string::npos)
Definition: stringOpsEvaluate.C:37