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 (
63  {"code", "codeInclude", "localCode"}
64 );
65 
67 (
68  {"dict", word::null, word::null}
69 );
70 
72  "codeStreamTemplate.C";
73 
74 
75 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
76 
77 bool Foam::functionEntries::codeStream::masterOnlyRead
78 (
79  const dictionary& dict
80 )
81 {
82  const dictionary& topDict = dict.topDict();
83 
84  if (debug)
85  {
86  Pout<< "codeStream : dictionary:" << dict.name()
87  << " master-only-reading:" << topDict.global()
88  << endl;
89  }
90 
91  return topDict.global();
92 }
93 
94 
95 Foam::functionEntries::codeStream::streamingFunctionType
96 Foam::functionEntries::codeStream::getFunction
97 (
98  const dictionary& contextDict,
99  const dictionary& codeDict
100 )
101 {
102  // Get code, codeInclude, ...
103  const dynamicCodeContext context
104  (
105  contextDict,
106  codeDict,
107  codeKeys,
108  codeDictVars
109  );
110 
111  // codeName: codeStream + _<sha1>
112  // codeDir : _<sha1>
113  const std::string sha1Str(context.sha1().str(true));
114  dynamicCode dynCode("codeStream" + sha1Str, sha1Str);
115 
116  // Load library if not already loaded
117  // Version information is encoded in the libPath (encoded with the SHA1)
118  const fileName libPath = dynCode.libPath();
119 
120  // See if library is loaded
121  void* lib = libs.findLibrary(libPath);
122 
123  if (debug && !lib)
124  {
125  Info<< "Using #codeStream with " << libPath << endl;
126  }
127 
128  // Nothing loaded
129  // avoid compilation if possible by loading an existing library
130  if (!lib)
131  {
132  // Cached access to dl libs.
133  // Guarantees clean up upon destruction of Time.
134  if (libs.open(libPath, false))
135  {
136  lib = libs.findLibrary(libPath);
137  }
138  else
139  {
140  // Uncached opening of libPath. Do not complain if cannot be loaded
141  lib = dlOpen(libPath, false);
142  }
143  }
144 
145  // Create library if required
146  if (!lib)
147  {
148  const bool create =
150  || (regIOobject::fileModificationSkew <= 0); // not NFS
151 
152  if (create)
153  {
154  if (!dynCode.upToDate(context))
155  {
156  // Filter with this context
157  dynCode.reset(context);
158 
159  // Compile filtered C template
160  dynCode.addCompileFile(codeTemplateC);
161 
162  // Define Make/options
163  dynCode.setMakeOptions
164  (
165  "EXE_INC = -g \\\n"
166  + context.options()
167  + "\n\nLIB_LIBS = \\\n"
168  + " -lOpenFOAM \\\n"
169  + context.libs()
170  );
171 
172  if (!dynCode.copyOrCreateFiles(true))
173  {
175  (
176  contextDict
177  ) << "Failed writing files for" << nl
178  << dynCode.libRelPath() << nl
179  << exit(FatalIOError);
180  }
181  }
182 
183  if (!dynCode.wmakeLibso())
184  {
186  (
187  contextDict
188  ) << "Failed wmake " << dynCode.libRelPath() << nl
189  << exit(FatalIOError);
190  }
191  }
192 
193  // Only block if not master only reading of a global dictionary
194  if
195  (
196  !masterOnlyRead(contextDict)
198  )
199  {
200  // Since the library has only been compiled on the master the
201  // other nodes need to pick this library up through NFS
202  // We do this by just polling a few times using the
203  // fileModificationSkew.
204 
205  off_t mySize = Foam::fileSize(libPath);
206  off_t masterSize = mySize;
207  Pstream::scatter(masterSize);
208 
209  if (debug)
210  {
211  Pout<< endl<< "on processor " << Pstream::myProcNo()
212  << " have masterSize:" << masterSize
213  << " and localSize:" << mySize
214  << endl;
215  }
216 
217 
218  if (mySize < masterSize)
219  {
220  if (debug)
221  {
222  Pout<< "Local file " << libPath
223  << " not of same size (" << mySize
224  << ") as master ("
225  << masterSize << "). Waiting for "
227  << " seconds." << endl;
228  }
230 
231  // Recheck local size
232  mySize = Foam::fileSize(libPath);
233 
234  if (mySize < masterSize)
235  {
237  (
238  contextDict
239  ) << "Cannot read (NFS mounted) library " << nl
240  << libPath << nl
241  << "on processor " << Pstream::myProcNo()
242  << " detected size " << mySize
243  << " whereas master size is " << masterSize
244  << " bytes." << nl
245  << "If your case is not NFS mounted"
246  << " (so distributed) set fileModificationSkew"
247  << " to 0"
248  << exit(FatalIOError);
249  }
250  }
251 
252  if (debug)
253  {
254  Pout<< endl<< "on processor " << Pstream::myProcNo()
255  << " after waiting: have masterSize:" << masterSize
256  << " and localSize:" << mySize
257  << endl;
258  }
259  }
260 
261  if (libs.open(libPath, false))
262  {
263  if (debug)
264  {
265  Pout<< "Opening cached dictionary:" << libPath << endl;
266  }
267 
268  lib = libs.findLibrary(libPath);
269  }
270  else
271  {
272  // Uncached opening of libPath
273  if (debug)
274  {
275  Pout<< "Opening uncached dictionary:" << libPath << endl;
276  }
277 
278  lib = dlOpen(libPath, true);
279  }
280  }
281 
282  if (!lib)
283  {
285  (
286  contextDict
287  ) << "Failed loading library " << libPath << nl
288  << "Did you add all libraries to the 'libs' entry"
289  << " in system/controlDict?"
290  << exit(FatalIOError);
291  }
292 
293  bool haveLib = lib;
294  if (!masterOnlyRead(contextDict))
295  {
296  reduce(haveLib, andOp<bool>());
297  }
298 
299  if (!haveLib)
300  {
302  (
303  contextDict
304  ) << "Failed loading library " << libPath
305  << " on some processors."
306  << exit(FatalIOError);
307  }
308 
309 
310  // Find the function handle in the library
311  const streamingFunctionType function =
312  reinterpret_cast<streamingFunctionType>
313  (
314  dlSym(lib, dynCode.codeName())
315  );
316 
317 
318  if (!function)
319  {
321  (
322  contextDict
323  ) << "Failed looking up symbol " << dynCode.codeName()
324  << " in library " << lib << exit(FatalIOError);
325  }
326 
327  return function;
328 }
329 
330 
331 Foam::string Foam::functionEntries::codeStream::run
332 (
333  const dictionary& contextDict,
334  Istream& is
335 )
336 {
337  if (debug)
338  {
339  Info<< "Using #codeStream at line " << is.lineNumber()
340  << " in file " << contextDict.name() << endl;
341  }
342 
344  (
345  "functionEntries::codeStream::execute(..)",
346  contextDict
347  );
348 
349  // Construct codeDict for codeStream
350  // Parent dictionary provided for string expansion and variable substitution
351  const dictionary codeDict("#codeStream", contextDict, is);
352 
353  const streamingFunctionType function = getFunction(contextDict, codeDict);
354 
355  // Use function to write stream
356  OStringStream os(is.format());
357  (*function)(os, contextDict);
358 
359  // Return the string containing the results of the code execution
360  return os.str();
361 }
362 
363 
364 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
365 
367 (
368  dictionary& contextDict,
369  Istream& is
370 )
371 {
372  return insert(contextDict, run(contextDict, is));
373 }
374 
375 
377 (
378  const dictionary& contextDict,
379  primitiveEntry& thisEntry,
380  Istream& is
381 )
382 {
383  return insert(contextDict, thisEntry, run(contextDict, is));
384 }
385 
386 
387 // ************************************************************************* //
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.
bool global() const
Return global state.
Definition: IOstream.H:438
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 keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
const dictionary & topDict() const
Return the top of the tree.
Definition: dictionary.C:437
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 const wordList codeKeys
Keywords associated with source code.
Definition: codeStream.H:241
static const word codeTemplateC
Name of the C code template to be used.
Definition: codeStream.H:247
static const wordList codeDictVars
Name of the dictionary variables in the source code.
Definition: codeStream.H:244
static bool execute(dictionary &contextDict, Istream &)
Execute the functionEntry in a sub-dict context.
Definition: codeStream.C:367
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
#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:258
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:267
dictionary dict