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-2014 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  "functionEntries::codeStream::execute(..)",
164  parentDict
165  ) << "Failed writing files for" << nl
166  << dynCode.libRelPath() << nl
167  << exit(FatalIOError);
168  }
169  }
170 
171  if (!dynCode.wmakeLibso())
172  {
174  (
175  "functionEntries::codeStream::execute(..)",
176  parentDict
177  ) << "Failed wmake " << dynCode.libRelPath() << nl
178  << exit(FatalIOError);
179  }
180  }
181 
182  //- Only block if we're not doing master-only reading. (flag set by
183  // regIOobject::read, IOdictionary constructor)
184  if
185  (
188  )
189  {
190  //- Since the library has only been compiled on the master the
191  // other nodes need to pick this library up through NFS
192  // We do this by just polling a few times using the
193  // fileModificationSkew.
194 
195  off_t mySize = Foam::fileSize(libPath);
196  off_t masterSize = mySize;
197  Pstream::scatter(masterSize);
198 
199  if (debug)
200  {
201  Pout<< endl<< "on processor " << Pstream::myProcNo()
202  << " have masterSize:" << masterSize
203  << " and localSize:" << mySize
204  << endl;
205  }
206 
207 
208  if (mySize < masterSize)
209  {
210  if (debug)
211  {
212  Pout<< "Local file " << libPath
213  << " not of same size (" << mySize
214  << ") as master ("
215  << masterSize << "). Waiting for "
217  << " seconds." << endl;
218  }
220 
221  // Recheck local size
222  mySize = Foam::fileSize(libPath);
223 
224  if (mySize < masterSize)
225  {
227  (
228  "functionEntries::codeStream::execute(..)",
229  parentDict
230  ) << "Cannot read (NFS mounted) library " << nl
231  << libPath << nl
232  << "on processor " << Pstream::myProcNo()
233  << " detected size " << mySize
234  << " whereas master size is " << masterSize
235  << " bytes." << nl
236  << "If your case is not NFS mounted"
237  << " (so distributed) set fileModificationSkew"
238  << " to 0"
239  << exit(FatalIOError);
240  }
241  }
242 
243  if (debug)
244  {
245  Pout<< endl<< "on processor " << Pstream::myProcNo()
246  << " after waiting: have masterSize:" << masterSize
247  << " and localSize:" << mySize
248  << endl;
249  }
250  }
251 
252  if (isA<IOdictionary>(parentDict.topDict()))
253  {
254  // Cached access to dl libs. Guarantees clean up upon destruction
255  // of Time.
256  dlLibraryTable& dlLibs = libs(parentDict);
257 
258  if (debug)
259  {
260  Pout<< "Opening cached dictionary:" << libPath << endl;
261  }
262 
263  if (!dlLibs.open(libPath, false))
264  {
266  (
267  "functionEntries::codeStream::execute(..)",
268  parentDict
269  ) << "Failed loading library " << libPath << nl
270  << "Did you add all libraries to the 'libs' entry"
271  << " in system/controlDict?"
272  << exit(FatalIOError);
273  }
274 
275  lib = dlLibs.findLibrary(libPath);
276  }
277  else
278  {
279  // Uncached opening of libPath
280  if (debug)
281  {
282  Pout<< "Opening uncached dictionary:" << libPath << endl;
283  }
284  lib = dlOpen(libPath, true);
285  }
286  }
287 
288  bool haveLib = lib;
290  {
291  reduce(haveLib, andOp<bool>());
292  }
293 
294  if (!haveLib)
295  {
297  (
298  "functionEntries::codeStream::execute(..)",
299  parentDict
300  ) << "Failed loading library " << libPath
301  << " on some processors."
302  << exit(FatalIOError);
303  }
304 
305 
306  // Find the function handle in the library
307  streamingFunctionType function =
308  reinterpret_cast<streamingFunctionType>
309  (
310  dlSym(lib, dynCode.codeName())
311  );
312 
313 
314  if (!function)
315  {
317  (
318  "functionEntries::codeStream::execute(..)",
319  parentDict
320  ) << "Failed looking up symbol " << dynCode.codeName()
321  << " in library " << lib << exit(FatalIOError);
322  }
323 
324  return function;
325 }
326 
327 
328 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
329 
331 (
332  const dictionary& parentDict,
333  primitiveEntry& entry,
334  Istream& is
335 )
336 {
337  Info<< "Using #codeStream at line " << is.lineNumber()
338  << " in file " << parentDict.name() << endl;
339 
341  (
342  "functionEntries::codeStream::execute(..)",
343  parentDict
344  );
345 
346  // get code dictionary
347  // must reference parent for stringOps::expand to work nicely
348  dictionary codeDict("#codeStream", parentDict, is);
349 
350  streamingFunctionType function = getFunction(parentDict, codeDict);
351 
352  // use function to write stream
353  OStringStream os(is.format());
354  (*function)(os, parentDict);
355 
356  // get the entry from this stream
357  IStringStream resultStream(os.str());
358  entry.read(parentDict, resultStream);
359 
360  return true;
361 }
362 
363 
365 (
366  dictionary& parentDict,
367  Istream& is
368 )
369 {
370  Info<< "Using #codeStream at line " << is.lineNumber()
371  << " in file " << parentDict.name() << endl;
372 
374  (
375  "functionEntries::codeStream::execute(..)",
376  parentDict
377  );
378 
379  // get code dictionary
380  // must reference parent for stringOps::expand to work nicely
381  dictionary codeDict("#codeStream", parentDict, is);
382 
383  streamingFunctionType function = getFunction(parentDict, codeDict);
384 
385  // use function to write stream
386  OStringStream os(is.format());
387  (*function)(os, parentDict);
388 
389  // get the entry from this stream
390  IStringStream resultStream(os.str());
391  parentDict.read(resultStream);
392 
393  return true;
394 }
395 
396 
397 // ************************************************************************* //
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Input from memory buffer stream.
Definition: IStringStream.H:49
bool read(Istream &)
Read dictionary from Istream.
Definition: dictionaryIO.C:126
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
A class for handling words, derived from string.
Definition: word.H:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
messageStream Info
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:103
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
Namespace for OpenFOAM.
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:57
static const char nl
Definition: Ostream.H:260
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
IOerror FatalIOError
defineTypeNameAndDebug(calcEntry, 0)
void * dlOpen(const fileName &lib, const bool check=true)
Open a shared library. Return handle to library. Print error message.
Definition: POSIX.C:1168
addToMemberFunctionSelectionTable(functionEntry, calcEntry, execute, dictionaryIstream)
streamFormat format() const
Return current stream format.
Definition: IOstream.H:377
static int fileModificationSkew
Definition: regIOobject.H:126
Output to memory buffer stream.
Definition: OStringStream.H:49
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
label lineNumber() const
Return current stream line number.
Definition: IOstream.H:438
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:404
unsigned int sleep(const unsigned int)
Sleep for the specified number of seconds.
Definition: POSIX.C:1055
static bool execute(dictionary &parentDict, Istream &)
Execute the functionEntry in a sub-dict context.
Definition: codeStream.C:365
virtual bool read(const dictionary &, Istream &)
Read tokens from the given stream.
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.
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:398
Macros for easy insertion into member function selection tables.
static bool masterOnlyReading
To flag master-only reading of objects.
Definition: regIOobject.H:82
A table of dynamically loaded libraries.
#define FatalIOErrorIn(functionName, ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:325
off_t fileSize(const fileName &)
Return size of file.
Definition: POSIX.C:630
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: POSIX.C:1208
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53