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-2024 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"
27 #include "dynamicCode.H"
28 #include "dynamicCodeContext.H"
29 #include "Time.H"
30 #include "OSspecific.H"
31 #include "PstreamReduceOps.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38 namespace functionEntries
39 {
41 
43  (
45  codeStream,
46  execute,
47  dictionaryIstream
48  );
49 
51  (
53  codeStream,
54  execute,
55  primitiveEntryIstream
56  );
57 }
58 }
59 
60 
62  "codeStreamTemplate.C";
63 
64 
65 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
66 
67 bool Foam::functionEntries::codeStream::masterOnlyRead
68 (
69  const dictionary& dict
70 )
71 {
72  const dictionary& topDict = dict.topDict();
73 
74  if (debug)
75  {
76  Pout<< "codeStream : dictionary:" << dict.name()
77  << " master-only-reading:" << topDict.global()
78  << endl;
79  }
80 
81  return topDict.global();
82 }
83 
84 
85 Foam::functionEntries::codeStream::streamingFunctionType
86 Foam::functionEntries::codeStream::getFunction
87 (
88  const dictionary& parentDict,
89  const dictionary& codeDict
90 )
91 {
92  // Get code, codeInclude, ...
93  const dynamicCodeContext context
94  (
95  codeDict,
96  {"code", "codeInclude", "localCode"},
97  {"dict", word::null, word::null}
98  );
99 
100  // codeName: codeStream + _<sha1>
101  // codeDir : _<sha1>
102  const std::string sha1Str(context.sha1().str(true));
103  dynamicCode dynCode("codeStream" + sha1Str, sha1Str);
104 
105  // Load library if not already loaded
106  // Version information is encoded in the libPath (encoded with the SHA1)
107  const fileName libPath = dynCode.libPath();
108 
109  // See if library is loaded
110  void* lib = libs.findLibrary(libPath);
111 
112  if (debug && !lib)
113  {
114  Info<< "Using #codeStream with " << libPath << endl;
115  }
116 
117  // Nothing loaded
118  // avoid compilation if possible by loading an existing library
119  if (!lib)
120  {
121  // Cached access to dl libs.
122  // Guarantees clean up upon destruction of Time.
123  if (libs.open(libPath, false))
124  {
125  lib = libs.findLibrary(libPath);
126  }
127  else
128  {
129  // Uncached opening of libPath. Do not complain if cannot be loaded
130  lib = dlOpen(libPath, false);
131  }
132  }
133 
134  // Create library if required
135  if (!lib)
136  {
137  const bool create =
139  || (regIOobject::fileModificationSkew <= 0); // not NFS
140 
141  if (create)
142  {
143  if (!dynCode.upToDate(context))
144  {
145  // Filter with this context
146  dynCode.reset(context);
147 
148  // Compile filtered C template
149  dynCode.addCompileFile(codeTemplateC);
150 
151  // Define Make/options
152  dynCode.setMakeOptions
153  (
154  "EXE_INC = -g \\\n"
155  + context.options()
156  + "\n\nLIB_LIBS = \\\n"
157  + " -lOpenFOAM \\\n"
158  + context.libs()
159  );
160 
161  if (!dynCode.copyOrCreateFiles(true))
162  {
164  (
165  parentDict
166  ) << "Failed writing files for" << nl
167  << dynCode.libRelPath() << nl
168  << exit(FatalIOError);
169  }
170  }
171 
172  if (!dynCode.wmakeLibso())
173  {
175  (
176  parentDict
177  ) << "Failed wmake " << dynCode.libRelPath() << nl
178  << exit(FatalIOError);
179  }
180  }
181 
182  // Only block if not master only reading of a global dictionary
183  if
184  (
185  !masterOnlyRead(parentDict)
187  )
188  {
189  // Since the library has only been compiled on the master the
190  // other nodes need to pick this library up through NFS
191  // We do this by just polling a few times using the
192  // fileModificationSkew.
193 
194  off_t mySize = Foam::fileSize(libPath);
195  off_t masterSize = mySize;
196  Pstream::scatter(masterSize);
197 
198  if (debug)
199  {
200  Pout<< endl<< "on processor " << Pstream::myProcNo()
201  << " have masterSize:" << masterSize
202  << " and localSize:" << mySize
203  << endl;
204  }
205 
206 
207  if (mySize < masterSize)
208  {
209  if (debug)
210  {
211  Pout<< "Local file " << libPath
212  << " not of same size (" << mySize
213  << ") as master ("
214  << masterSize << "). Waiting for "
216  << " seconds." << endl;
217  }
219 
220  // Recheck local size
221  mySize = Foam::fileSize(libPath);
222 
223  if (mySize < masterSize)
224  {
226  (
227  parentDict
228  ) << "Cannot read (NFS mounted) library " << nl
229  << libPath << nl
230  << "on processor " << Pstream::myProcNo()
231  << " detected size " << mySize
232  << " whereas master size is " << masterSize
233  << " bytes." << nl
234  << "If your case is not NFS mounted"
235  << " (so distributed) set fileModificationSkew"
236  << " to 0"
237  << exit(FatalIOError);
238  }
239  }
240 
241  if (debug)
242  {
243  Pout<< endl<< "on processor " << Pstream::myProcNo()
244  << " after waiting: have masterSize:" << masterSize
245  << " and localSize:" << mySize
246  << endl;
247  }
248  }
249 
250  if (libs.open(libPath, false))
251  {
252  if (debug)
253  {
254  Pout<< "Opening cached dictionary:" << libPath << endl;
255  }
256 
257  lib = libs.findLibrary(libPath);
258  }
259  else
260  {
261  // Uncached opening of libPath
262  if (debug)
263  {
264  Pout<< "Opening uncached dictionary:" << libPath << endl;
265  }
266 
267  lib = dlOpen(libPath, true);
268  }
269  }
270 
271  if (!lib)
272  {
274  (
275  parentDict
276  ) << "Failed loading library " << libPath << nl
277  << "Did you add all libraries to the 'libs' entry"
278  << " in system/controlDict?"
279  << exit(FatalIOError);
280  }
281 
282  bool haveLib = lib;
283  if (!masterOnlyRead(parentDict))
284  {
285  reduce(haveLib, andOp<bool>());
286  }
287 
288  if (!haveLib)
289  {
291  (
292  parentDict
293  ) << "Failed loading library " << libPath
294  << " on some processors."
295  << exit(FatalIOError);
296  }
297 
298 
299  // Find the function handle in the library
300  const streamingFunctionType function =
301  reinterpret_cast<streamingFunctionType>
302  (
303  dlSym(lib, dynCode.codeName())
304  );
305 
306 
307  if (!function)
308  {
310  (
311  parentDict
312  ) << "Failed looking up symbol " << dynCode.codeName()
313  << " in library " << lib << exit(FatalIOError);
314  }
315 
316  return function;
317 }
318 
319 
320 Foam::string Foam::functionEntries::codeStream::run
321 (
322  const dictionary& parentDict,
323  Istream& is
324 )
325 {
326  if (debug)
327  {
328  Info<< "Using #codeStream at line " << is.lineNumber()
329  << " in file " << parentDict.name() << endl;
330  }
331 
333  (
334  "functionEntries::codeStream::execute(..)",
335  parentDict
336  );
337 
338  // Construct codeDict for codeStream
339  // Parent dictionary provided for string expansion and variable substitution
340  const dictionary codeDict("#codeStream", parentDict, is);
341 
342  const streamingFunctionType function = getFunction(parentDict, codeDict);
343 
344  // Use function to write stream
345  OStringStream os(is.format());
346  (*function)(os, parentDict);
347 
348  // Return the string containing the results of the code execution
349  return os.str();
350 }
351 
352 
353 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
354 
356 (
357  dictionary& parentDict,
358  Istream& is
359 )
360 {
361  return insert(parentDict, run(parentDict, is));
362 }
363 
364 
366 (
367  const dictionary& parentDict,
368  primitiveEntry& thisEntry,
369  Istream& is
370 )
371 {
372  return insert(parentDict, thisEntry, run(parentDict, is));
373 }
374 
375 
376 // ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Inter-processor communication reduction functions.
Macros for easy insertion into member function selection tables.
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:60
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:111
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:162
const dictionary & topDict() const
Return the top of the tree.
Definition: dictionary.C:414
void * findLibrary(const fileName &libName)
Find the handle of the named library.
bool open(const fileName &libName, const bool verbose=true)
Open the named library, optionally with warnings if problems occur.
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:58
Dictionary entry that contains C++ OpenFOAM code that is compiled to generate the entry itself.
Definition: codeStream.H:208
static bool execute(dictionary &parentDict, Istream &)
Execute the functionEntry in a sub-dict context.
Definition: codeStream.C:356
static const word codeTemplateC
Name of the C code template to be used.
Definition: codeStream.H:241
A functionEntry causes entries to be added/manipulated on the specified dictionary given an input str...
Definition: functionEntry.H:66
A keyword and a list of tokens is a 'primitiveEntry'. An primitiveEntry can be read,...
const dictionary & dict() const
This entry is not a dictionary,.
static float fileModificationSkew
Definition: regIOobject.H:100
A class for handling character strings derived from std::string.
Definition: string.H:79
A class for handling words, derived from string.
Definition: word.H:62
static const word null
An empty word.
Definition: word.H:77
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
defineTypeNameAndDebug(includeFvConstraintEntry, 0)
addToMemberFunctionSelectionTable(functionEntry, includeFvConstraintEntry, execute, dictionaryIstream)
void insert(const scalar, DynamicList< floatScalar > &)
Append scalar to given DynamicList.
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
dlLibraryTable libs
Table of loaded dynamic libraries.
off_t fileSize(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return size of file.
Definition: POSIX.C:576
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
void * dlOpen(const fileName &lib, const bool check=true)
Open a shared library. Return handle to library. Print error message.
Definition: POSIX.C:1236
messageStream Info
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
IOerror FatalIOError
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: POSIX.C:1276
unsigned int sleep(const unsigned int)
Sleep for the specified number of seconds.
Definition: POSIX.C:1130
static const char nl
Definition: Ostream.H:266
dictionary dict