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 | Copyright (C) 2011-2015 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 
63  = "codeStreamTemplate.C";
64 
65 
66 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
67 
69 (
70  const dictionary& dict
71 )
72 {
73  const IOdictionary& d = static_cast<const IOdictionary&>(dict.topDict());
74  return const_cast<Time&>(d.time()).libs();
75 }
76 
77 
80 (
81  const dictionary& parentDict,
82  const dictionary& codeDict
83 )
84 {
85  // get code, codeInclude, codeOptions
86  dynamicCodeContext context(codeDict);
87 
88  // codeName: codeStream + _<sha1>
89  // codeDir : _<sha1>
90  std::string sha1Str(context.sha1().str(true));
91  dynamicCode dynCode("codeStream" + sha1Str, sha1Str);
92 
93  // Load library if not already loaded
94  // Version information is encoded in the libPath (encoded with the SHA1)
95  const fileName libPath = dynCode.libPath();
96 
97  // see if library is loaded
98  void* lib = NULL;
99  if (isA<IOdictionary>(parentDict.topDict()))
100  {
101  lib = libs(parentDict).findLibrary(libPath);
102  }
103 
104  if (!lib)
105  {
106  Info<< "Using #codeStream with " << libPath << endl;
107  }
108 
109 
110  // nothing loaded
111  // avoid compilation if possible by loading an existing library
112  if (!lib)
113  {
114  if (isA<IOdictionary>(parentDict.topDict()))
115  {
116  // Cached access to dl libs. Guarantees clean up upon destruction
117  // of Time.
118  dlLibraryTable& dlLibs = libs(parentDict);
119  if (dlLibs.open(libPath, false))
120  {
121  lib = dlLibs.findLibrary(libPath);
122  }
123  }
124  else
125  {
126  // Uncached opening of libPath. Do not complain if cannot be loaded
127  lib = dlOpen(libPath, false);
128  }
129  }
130 
131 
132  // create library if required
133  if (!lib)
134  {
135  bool create =
136  Pstream::master()
137  || (regIOobject::fileModificationSkew <= 0); // not NFS
138 
139  if (create)
140  {
141  if (!dynCode.upToDate(context))
142  {
143  // filter with this context
144  dynCode.reset(context);
145 
146  // compile filtered C template
147  dynCode.addCompileFile(codeTemplateC);
148 
149  // define Make/options
150  dynCode.setMakeOptions
151  (
152  "EXE_INC = -g \\\n"
153  + context.options()
154  + "\n\nLIB_LIBS = \\\n"
155  + " -lOpenFOAM \\\n"
156  + context.libs()
157  );
158 
159  if (!dynCode.copyOrCreateFiles(true))
160  {
162  (
163  parentDict
164  ) << "Failed writing files for" << nl
165  << dynCode.libRelPath() << nl
166  << exit(FatalIOError);
167  }
168  }
169 
170  if (!dynCode.wmakeLibso())
171  {
173  (
174  parentDict
175  ) << "Failed wmake " << dynCode.libRelPath() << nl
176  << exit(FatalIOError);
177  }
178  }
179 
180  //- Only block if we're not doing master-only reading. (flag set by
181  // regIOobject::read, IOdictionary constructor)
182  if
183  (
184  !regIOobject::masterOnlyReading
185  && regIOobject::fileModificationSkew > 0
186  )
187  {
188  //- Since the library has only been compiled on the master the
189  // other nodes need to pick this library up through NFS
190  // We do this by just polling a few times using the
191  // fileModificationSkew.
192 
193  off_t mySize = Foam::fileSize(libPath);
194  off_t masterSize = mySize;
195  Pstream::scatter(masterSize);
196 
197  if (debug)
198  {
199  Pout<< endl<< "on processor " << Pstream::myProcNo()
200  << " have masterSize:" << masterSize
201  << " and localSize:" << mySize
202  << endl;
203  }
204 
205 
206  if (mySize < masterSize)
207  {
208  if (debug)
209  {
210  Pout<< "Local file " << libPath
211  << " not of same size (" << mySize
212  << ") as master ("
213  << masterSize << "). Waiting for "
214  << regIOobject::fileModificationSkew
215  << " seconds." << endl;
216  }
217  Foam::sleep(regIOobject::fileModificationSkew);
218 
219  // Recheck local size
220  mySize = Foam::fileSize(libPath);
221 
222  if (mySize < masterSize)
223  {
225  (
226  parentDict
227  ) << "Cannot read (NFS mounted) library " << nl
228  << libPath << nl
229  << "on processor " << Pstream::myProcNo()
230  << " detected size " << mySize
231  << " whereas master size is " << masterSize
232  << " bytes." << nl
233  << "If your case is not NFS mounted"
234  << " (so distributed) set fileModificationSkew"
235  << " to 0"
236  << exit(FatalIOError);
237  }
238  }
239 
240  if (debug)
241  {
242  Pout<< endl<< "on processor " << Pstream::myProcNo()
243  << " after waiting: have masterSize:" << masterSize
244  << " and localSize:" << mySize
245  << endl;
246  }
247  }
248 
249  if (isA<IOdictionary>(parentDict.topDict()))
250  {
251  // Cached access to dl libs. Guarantees clean up upon destruction
252  // of Time.
253  dlLibraryTable& dlLibs = libs(parentDict);
254 
255  if (debug)
256  {
257  Pout<< "Opening cached dictionary:" << libPath << endl;
258  }
259 
260  if (!dlLibs.open(libPath, false))
261  {
263  (
264  parentDict
265  ) << "Failed loading library " << libPath << nl
266  << "Did you add all libraries to the 'libs' entry"
267  << " in system/controlDict?"
268  << exit(FatalIOError);
269  }
270 
271  lib = dlLibs.findLibrary(libPath);
272  }
273  else
274  {
275  // Uncached opening of libPath
276  if (debug)
277  {
278  Pout<< "Opening uncached dictionary:" << libPath << endl;
279  }
280  lib = dlOpen(libPath, true);
281  }
282  }
283 
284  bool haveLib = lib;
285  if (!regIOobject::masterOnlyReading)
286  {
287  reduce(haveLib, andOp<bool>());
288  }
289 
290  if (!haveLib)
291  {
293  (
294  parentDict
295  ) << "Failed loading library " << libPath
296  << " on some processors."
297  << exit(FatalIOError);
298  }
299 
300 
301  // Find the function handle in the library
302  streamingFunctionType function =
303  reinterpret_cast<streamingFunctionType>
304  (
305  dlSym(lib, dynCode.codeName())
306  );
307 
308 
309  if (!function)
310  {
312  (
313  parentDict
314  ) << "Failed looking up symbol " << dynCode.codeName()
315  << " in library " << lib << exit(FatalIOError);
316  }
317 
318  return function;
319 }
320 
321 
322 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
323 
325 (
326  const dictionary& parentDict,
328  Istream& is
329 )
330 {
331  Info<< "Using #codeStream at line " << is.lineNumber()
332  << " in file " << parentDict.name() << endl;
333 
334  dynamicCode::checkSecurity
335  (
336  "functionEntries::codeStream::execute(..)",
337  parentDict
338  );
339 
340  // get code dictionary
341  // must reference parent for stringOps::expand to work nicely
342  dictionary codeDict("#codeStream", parentDict, is);
343 
344  streamingFunctionType function = getFunction(parentDict, codeDict);
345 
346  // use function to write stream
347  OStringStream os(is.format());
348  (*function)(os, parentDict);
349 
350  // get the entry from this stream
351  IStringStream resultStream(os.str());
352  entry.read(parentDict, resultStream);
353 
354  return true;
355 }
356 
357 
359 (
360  dictionary& parentDict,
361  Istream& is
362 )
363 {
364  Info<< "Using #codeStream at line " << is.lineNumber()
365  << " in file " << parentDict.name() << endl;
366 
367  dynamicCode::checkSecurity
368  (
369  "functionEntries::codeStream::execute(..)",
370  parentDict
371  );
372 
373  // get code dictionary
374  // must reference parent for stringOps::expand to work nicely
375  dictionary codeDict("#codeStream", parentDict, is);
376 
377  streamingFunctionType function = getFunction(parentDict, codeDict);
378 
379  // use function to write stream
380  OStringStream os(is.format());
381  (*function)(os, parentDict);
382 
383  // get the entry from this stream
384  IStringStream resultStream(os.str());
385  parentDict.read(resultStream);
386 
387  return true;
388 }
389 
390 
391 // ************************************************************************* //
Foam::dynamicCodeContext::libs
const string & libs() const
Return the code-libs.
Definition: dynamicCodeContext.H:102
Foam::entry
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:65
Foam::IOdictionary
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:53
Foam::IOstream::format
streamFormat format() const
Return current stream format.
Definition: IOstream.H:377
Foam::dlLibraryTable
A table of dynamically loaded libraries.
Definition: dlLibraryTable.H:49
Foam::Time
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:68
Foam::primitiveEntry
A keyword and a list of tokens is a 'primitiveEntry'. An primitiveEntry can be read,...
Definition: primitiveEntry.H:62
Foam::word
A class for handling words, derived from string.
Definition: word.H:59
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::dynamicCode::libPath
fileName libPath() const
Library path for specified code name.
Definition: dynamicCode.H:221
Foam::dlLibraryTable::findLibrary
void * findLibrary(const fileName &name)
Find the handle of the named library.
Definition: dlLibraryTable.C:164
Foam::dynamicCode::copyOrCreateFiles
bool copyOrCreateFiles(const bool verbose=false) const
Copy/create files prior to compilation.
Definition: dynamicCode.C:399
codeStream.H
Foam::dynamicCode
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:56
Foam::dlSym
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: POSIX.C:1224
Foam::dynamicCode::wmakeLibso
bool wmakeLibso() const
Compile a libso.
Definition: dynamicCode.C:494
Foam::dictionaryName::name
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:103
Foam::dynamicCodeContext
Encapsulation of dynamic code dictionaries.
Definition: dynamicCodeContext.H:49
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
dynamicCodeContext.H
Foam::IOobject::time
const Time & time() const
Return time.
Definition: IOobject.C:245
Foam::sleep
unsigned int sleep(const unsigned int)
Sleep for the specified number of seconds.
Definition: POSIX.C:1054
Foam::functionEntries::codeStream::codeTemplateC
static const word codeTemplateC
Name of the C code template to be used.
Definition: codeStream.H:148
IStringStream.H
Foam::functionEntries::codeStream::getFunction
static streamingFunctionType getFunction(const dictionary &parentDict, const dictionary &codeDict)
Construct, compile, load and return streaming function.
Definition: codeStream.C:80
Foam::functionEntries::codeStream::streamingFunctionType
void(* streamingFunctionType)(Ostream &, const dictionary &)
Interpreter function type.
Definition: codeStream.H:118
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:43
Foam::dynamicCode::addCompileFile
void addCompileFile(const fileName &name)
Add a file template name, which will be found and filtered.
Definition: dynamicCode.C:349
Foam::dynamicCode::codeName
const word & codeName() const
Return the code-name.
Definition: dynamicCode.H:187
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:57
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::Info
messageStream Info
Foam::functionEntries::codeStream::libs
static dlLibraryTable & libs(const dictionary &dict)
Helper function: access to dlLibraryTable of Time.
Definition: codeStream.C:69
OStringStream.H
addToMemberFunctionSelectionTable.H
Macros for easy insertion into member function selection tables.
dynamicCode.H
Foam::dlOpen
void * dlOpen(const fileName &lib, const bool check=true)
Open a shared library. Return handle to library. Print error message.
Definition: POSIX.C:1161
Foam::dynamicCode::libRelPath
fileName libRelPath() const
Library path for specified code name relative to $FOAM_CASE.
Definition: dynamicCode.C:317
Foam::dictionary::topDict
const dictionary & topDict() const
Return the top of the tree.
Definition: dictionary.C:229
Foam::dynamicCodeContext::sha1
const SHA1Digest & sha1() const
Return SHA1 digest calculated from include, options, code.
Definition: dynamicCodeContext.H:120
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dictionary
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:137
Foam::dynamicCodeContext::options
const string & options() const
Return the code-options.
Definition: dynamicCodeContext.H:96
Foam::IStringStream
Input from memory buffer stream.
Definition: IStringStream.H:49
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::functionEntries::addToMemberFunctionSelectionTable
addToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream)
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::dynamicCode::reset
void reset(const dynamicCodeContext &)
Clear files and reset variables to specified context.
Definition: dynamicCode.C:340
Foam::andOp
Definition: ops.H:177
Foam::dynamicCode::upToDate
bool upToDate(const dynamicCodeContext &context) const
Verify if the copied code is up-to-date, based on Make/SHA1Digest.
Definition: dynamicCode.C:523
Foam::dynamicCode::setMakeOptions
void setMakeOptions(const std::string &content)
Define contents for Make/options.
Definition: dynamicCode.C:393
Foam::functionEntries::codeStream::execute
static bool execute(dictionary &parentDict, Istream &)
Execute the functionEntry in a sub-dict context.
Definition: codeStream.C:359
Foam::Pout
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Foam::dlLibraryTable::open
bool open(const fileName &name, const bool verbose=true)
Open the named library, optionally with warnings if problems occur.
Definition: dlLibraryTable.C:77
Foam::OStringStream
Output to memory buffer stream.
Definition: OStringStream.H:49
Foam::IOstream::lineNumber
label lineNumber() const
Return current stream line number.
Definition: IOstream.H:438
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:330
Foam::dictionary::read
bool read(Istream &)
Read dictionary from Istream.
Definition: dictionaryIO.C:126
Foam::functionEntries::defineTypeNameAndDebug
defineTypeNameAndDebug(calcEntry, 0)
Foam::fileSize
off_t fileSize(const fileName &)
Return size of file.
Definition: POSIX.C:629
Foam::SHA1Digest::str
std::string str(const bool prefixed=false) const
Return (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1Digest.C:112