codeStream.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "codeStream.H"
28 #include "IStringStream.H"
29 #include "OStringStream.H"
30 #include "dynamicCode.H"
31 #include "dynamicCodeContext.H"
32 #include "Time.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38 namespace functionEntries
39 {
40  defineTypeNameAndDebug(codeStream, 0);
41 
43  (
44  functionEntry,
45  codeStream,
46  execute,
47  dictionaryIstream
48  );
49 
51  (
52  functionEntry,
53  codeStream,
54  execute,
55  primitiveEntryIstream
56  );
57 
58 }
59 }
60 
61 
62 const Foam::word Foam::functionEntries::codeStream::codeTemplateC =
63  "codeStreamTemplate.C";
64 
65 
66 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
67 
68 Foam::dlLibraryTable& Foam::functionEntries::codeStream::libs
69 (
70  const dictionary& dict
71 )
72 {
73  return Foam::libs;
74 }
75 
76 
77 bool Foam::functionEntries::codeStream::doingMasterOnlyReading
78 (
79  const dictionary& dict
80 )
81 {
82  const dictionary& topDict = dict.topDict();
83 
84  if (isA<baseIOdictionary>(topDict))
85  {
86  const baseIOdictionary& d = static_cast<const baseIOdictionary&>
87  (
88  topDict
89  );
90 
91  if (debug)
92  {
93  Pout<< "codeStream : baseIOdictionary:" << dict.name()
94  << " master-only-reading:" << d.global()
95  << endl;
96  }
97 
98  return d.global();
99  }
100  else
101  {
102  if (debug)
103  {
104  Pout<< "codeStream : not a baseIOdictionary:" << dict.name()
105  << " master-only-reading:" << false
106  << endl;
107  }
108 
109  // Fall back to false
110  return false;
111  }
112 }
113 
114 
115 Foam::functionEntries::codeStream::streamingFunctionType
116 Foam::functionEntries::codeStream::getFunction
117 (
118  const dictionary& parentDict,
119  const dictionary& codeDict
120 )
121 {
122  // get code, codeInclude, ...
123  dynamicCodeContext context(codeDict, {"code", "codeInclude", "localCode"});
124 
125  // codeName: codeStream + _<sha1>
126  // codeDir : _<sha1>
127  std::string sha1Str(context.sha1().str(true));
128  dynamicCode dynCode("codeStream" + sha1Str, sha1Str);
129 
130  // Load library if not already loaded
131  // Version information is encoded in the libPath (encoded with the SHA1)
132  const fileName libPath = dynCode.libPath();
133 
134  // see if library is loaded
135  void* lib = nullptr;
136 
137  const dictionary& topDict = parentDict.topDict();
138  if (isA<baseIOdictionary>(topDict))
139  {
140  lib = libs(parentDict).findLibrary(libPath);
141  }
142 
143  if (!lib)
144  {
145  Info<< "Using #codeStream with " << libPath << endl;
146  }
147 
148 
149  // nothing loaded
150  // avoid compilation if possible by loading an existing library
151  if (!lib)
152  {
153  if (isA<baseIOdictionary>(topDict))
154  {
155  // Cached access to dl libs. Guarantees clean up upon destruction
156  // of Time.
157  dlLibraryTable& dlLibs = libs(parentDict);
158  if (dlLibs.open(libPath, false))
159  {
160  lib = dlLibs.findLibrary(libPath);
161  }
162  }
163  else
164  {
165  // Uncached opening of libPath. Do not complain if cannot be loaded
166  lib = dlOpen(libPath, false);
167  }
168  }
169 
170 
171  // create library if required
172  if (!lib)
173  {
174  bool create =
176  || (regIOobject::fileModificationSkew <= 0); // not NFS
177 
178  if (create)
179  {
180  if (!dynCode.upToDate(context))
181  {
182  // filter with this context
183  dynCode.reset(context);
184 
185  // compile filtered C template
186  dynCode.addCompileFile(codeTemplateC);
187 
188  // define Make/options
189  dynCode.setMakeOptions
190  (
191  "EXE_INC = -g \\\n"
192  + context.options()
193  + "\n\nLIB_LIBS = \\\n"
194  + " -lOpenFOAM \\\n"
195  + context.libs()
196  );
197 
198  if (!dynCode.copyOrCreateFiles(true))
199  {
201  (
202  parentDict
203  ) << "Failed writing files for" << nl
204  << dynCode.libRelPath() << nl
205  << exit(FatalIOError);
206  }
207  }
208 
209  if (!dynCode.wmakeLibso())
210  {
212  (
213  parentDict
214  ) << "Failed wmake " << dynCode.libRelPath() << nl
215  << exit(FatalIOError);
216  }
217  }
218 
219  //- Only block if we're not doing master-only reading. (flag set by
220  // regIOobject::read, baseIOdictionary constructor)
221  if
222  (
223  !doingMasterOnlyReading(topDict)
225  )
226  {
227  //- Since the library has only been compiled on the master the
228  // other nodes need to pick this library up through NFS
229  // We do this by just polling a few times using the
230  // fileModificationSkew.
231 
232  off_t mySize = Foam::fileSize(libPath);
233  off_t masterSize = mySize;
234  Pstream::scatter(masterSize);
235 
236  if (debug)
237  {
238  Pout<< endl<< "on processor " << Pstream::myProcNo()
239  << " have masterSize:" << masterSize
240  << " and localSize:" << mySize
241  << endl;
242  }
243 
244 
245  if (mySize < masterSize)
246  {
247  if (debug)
248  {
249  Pout<< "Local file " << libPath
250  << " not of same size (" << mySize
251  << ") as master ("
252  << masterSize << "). Waiting for "
254  << " seconds." << endl;
255  }
257 
258  // Recheck local size
259  mySize = Foam::fileSize(libPath);
260 
261  if (mySize < masterSize)
262  {
264  (
265  parentDict
266  ) << "Cannot read (NFS mounted) library " << nl
267  << libPath << nl
268  << "on processor " << Pstream::myProcNo()
269  << " detected size " << mySize
270  << " whereas master size is " << masterSize
271  << " bytes." << nl
272  << "If your case is not NFS mounted"
273  << " (so distributed) set fileModificationSkew"
274  << " to 0"
275  << exit(FatalIOError);
276  }
277  }
278 
279  if (debug)
280  {
281  Pout<< endl<< "on processor " << Pstream::myProcNo()
282  << " after waiting: have masterSize:" << masterSize
283  << " and localSize:" << mySize
284  << endl;
285  }
286  }
287 
288  if (isA<baseIOdictionary>(topDict))
289  {
290  // Cached access to dl libs. Guarantees clean up upon destruction
291  // of Time.
292  dlLibraryTable& dlLibs = libs(parentDict);
293 
294  if (debug)
295  {
296  Pout<< "Opening cached dictionary:" << libPath << endl;
297  }
298 
299  if (!dlLibs.open(libPath, false))
300  {
302  (
303  parentDict
304  ) << "Failed loading library " << libPath << nl
305  << "Did you add all libraries to the 'libs' entry"
306  << " in system/controlDict?"
307  << exit(FatalIOError);
308  }
309 
310  lib = dlLibs.findLibrary(libPath);
311  }
312  else
313  {
314  // Uncached opening of libPath
315  if (debug)
316  {
317  Pout<< "Opening uncached dictionary:" << libPath << endl;
318  }
319  lib = dlOpen(libPath, true);
320  }
321  }
322 
323  bool haveLib = lib;
324  if (!doingMasterOnlyReading(topDict))
325  {
326  reduce(haveLib, andOp<bool>());
327  }
328 
329  if (!haveLib)
330  {
332  (
333  parentDict
334  ) << "Failed loading library " << libPath
335  << " on some processors."
336  << exit(FatalIOError);
337  }
338 
339 
340  // Find the function handle in the library
341  streamingFunctionType function =
342  reinterpret_cast<streamingFunctionType>
343  (
344  dlSym(lib, dynCode.codeName())
345  );
346 
347 
348  if (!function)
349  {
351  (
352  parentDict
353  ) << "Failed looking up symbol " << dynCode.codeName()
354  << " in library " << lib << exit(FatalIOError);
355  }
356 
357  return function;
358 }
359 
360 
361 Foam::string Foam::functionEntries::codeStream::run
362 (
363  const dictionary& parentDict,
364  Istream& is
365 )
366 {
367  Info<< "Using #codeStream at line " << is.lineNumber()
368  << " in file " << parentDict.name() << endl;
369 
371  (
372  "functionEntries::codeStream::execute(..)",
373  parentDict
374  );
375 
376  // get code dictionary
377  // must reference parent for stringOps::expand to work nicely
378  dictionary codeDict("#codeStream", parentDict, is);
379 
380  streamingFunctionType function = getFunction(parentDict, codeDict);
381 
382  // use function to write stream
383  OStringStream os(is.format());
384  (*function)(os, parentDict);
385 
386  // Return the string containing the results of the code execution
387  return os.str();
388 }
389 
390 
391 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
392 
394 (
395  dictionary& parentDict,
396  Istream& is
397 )
398 {
399  return insert(parentDict, run(parentDict, is));
400 }
401 
402 
404 (
405  const dictionary& parentDict,
406  primitiveEntry& thisEntry,
407  Istream& is
408 )
409 {
410  return insert(parentDict, thisEntry, run(parentDict, is));
411 }
412 
413 
414 // ************************************************************************* //
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:82
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
addToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream)
dlLibraryTable libs
Table of loaded dynamic libraries.
void insert(const scalar, DynamicList< floatScalar > &)
Append scalar to given DynamicList.
A keyword and a list of tokens is a &#39;primitiveEntry&#39;. An primitiveEntry can be read, written and printed, and the types and values of its tokens analysed.
A class for handling words, derived from string.
Definition: word.H:59
A table of dynamically loaded libraries.
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
static const char nl
Definition: Ostream.H:260
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
static bool execute(dictionary &parentDict, Istream &)
Execute the functionEntry in a sub-dict context.
Definition: codeStream.C:394
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:331
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
void * findLibrary(const fileName &libName)
Find the handle of the named library.
Macros for easy insertion into member function selection tables.
static float fileModificationSkew
Definition: regIOobject.H:103
messageStream Info
off_t fileSize(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return size of file.
Definition: POSIX.C:576
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:58
A class for handling character strings derived from std::string.
Definition: string.H:76
unsigned int sleep(const unsigned int)
Sleep for the specified number of seconds.
Definition: POSIX.C:1134
void * dlOpen(const fileName &lib, const bool check=true)
Open a shared library. Return handle to library. Print error message.
Definition: POSIX.C:1240
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: POSIX.C:1280
defineTypeNameAndDebug(calcEntry, 0)
Namespace for OpenFOAM.
IOerror FatalIOError