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 
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  const IOdictionary& d = static_cast<const IOdictionary&>(dict.topDict());
74  return const_cast<Time&>(d.time()).libs();
75 }
76 
77 
78 Foam::functionEntries::codeStream::streamingFunctionType
79 Foam::functionEntries::codeStream::getFunction
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 =
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  (
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 "
215  << " seconds." << endl;
216  }
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;
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,
327  primitiveEntry& entry,
328  Istream& is
329 )
330 {
331  Info<< "Using #codeStream at line " << is.lineNumber()
332  << " in file " << parentDict.name() << endl;
333 
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 
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 // ************************************************************************* //
bool read(Istream &)
Read dictionary from Istream.
Definition: dictionaryIO.C:126
streamFormat format() const
Return current stream format.
Definition: IOstream.H:377
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:137
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:417
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:411
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:103
addToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream)
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.
off_t fileSize(const fileName &)
Return size of file.
Definition: POSIX.C:498
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
static const char nl
Definition: Ostream.H:262
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
static bool masterOnlyReading
To flag master-only reading of objects.
Definition: regIOobject.H:82
static bool execute(dictionary &parentDict, Istream &)
Execute the functionEntry in a sub-dict context.
Definition: codeStream.C:359
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:331
Input from memory buffer stream.
Definition: IStringStream.H:49
label lineNumber() const
Return current stream line number.
Definition: IOstream.H:438
static int fileModificationSkew
Definition: regIOobject.H:126
Macros for easy insertion into member function selection tables.
messageStream Info
virtual bool read(const dictionary &, Istream &)
Read tokens from the given stream.
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:58
unsigned int sleep(const unsigned int)
Sleep for the specified number of seconds.
Definition: POSIX.C:919
void * dlOpen(const fileName &lib, const bool check=true)
Open a shared library. Return handle to library. Print error message.
Definition: POSIX.C:1026
Output to memory buffer stream.
Definition: OStringStream.H:49
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: POSIX.C:1066
defineTypeNameAndDebug(calcEntry, 0)
Namespace for OpenFOAM.
IOerror FatalIOError