codedBase.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-2016 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 "codedBase.H"
27 #include "SHA1Digest.H"
28 #include "dynamicCode.H"
29 #include "dynamicCodeContext.H"
30 #include "dlLibraryTable.H"
31 #include "PstreamReduceOps.H"
32 #include "OSspecific.H"
33 #include "regIOobject.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39  defineTypeNameAndDebug(codedBase, 0);
40 }
41 
42 
43 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
44 
45 void* Foam::codedBase::loadLibrary
46 (
47  const fileName& libPath,
48  const string& globalFuncName,
49  const dictionary& contextDict
50 ) const
51 {
52  void* lib = 0;
53 
54  // avoid compilation by loading an existing library
55  if (!libPath.empty())
56  {
57  if (libs().open(libPath, false))
58  {
59  lib = libs().findLibrary(libPath);
60 
61  // verify the loaded version and unload if needed
62  if (lib)
63  {
64  // provision for manual execution of code after loading
65  if (dlSymFound(lib, globalFuncName))
66  {
67  loaderFunctionType function =
68  reinterpret_cast<loaderFunctionType>
69  (
70  dlSym(lib, globalFuncName)
71  );
72 
73  if (function)
74  {
75  (*function)(true); // force load
76  }
77  else
78  {
80  (
81  contextDict
82  ) << "Failed looking up symbol " << globalFuncName
83  << nl << "from " << libPath << exit(FatalIOError);
84  }
85  }
86  else
87  {
89  (
90  contextDict
91  ) << "Failed looking up symbol " << globalFuncName << nl
92  << "from " << libPath << exit(FatalIOError);
93 
94  lib = 0;
95  if (!libs().close(libPath, false))
96  {
98  (
99  contextDict
100  ) << "Failed unloading library "
101  << libPath
102  << exit(FatalIOError);
103  }
104  }
105  }
106  }
107  }
108 
109  return lib;
110 }
111 
112 
113 void Foam::codedBase::unloadLibrary
114 (
115  const fileName& libPath,
116  const string& globalFuncName,
117  const dictionary& contextDict
118 ) const
119 {
120  void* lib = 0;
121 
122  if (libPath.empty())
123  {
124  return;
125  }
126 
127  lib = libs().findLibrary(libPath);
128 
129  if (!lib)
130  {
131  return;
132  }
133 
134  // provision for manual execution of code before unloading
135  if (dlSymFound(lib, globalFuncName))
136  {
137  loaderFunctionType function =
138  reinterpret_cast<loaderFunctionType>
139  (
140  dlSym(lib, globalFuncName)
141  );
142 
143  if (function)
144  {
145  (*function)(false); // force unload
146  }
147  else
148  {
150  (
151  contextDict
152  ) << "Failed looking up symbol " << globalFuncName << nl
153  << "from " << libPath << exit(FatalIOError);
154  }
155  }
156 
157  if (!libs().close(libPath, false))
158  {
160  (
161  contextDict
162  ) << "Failed unloading library " << libPath
163  << exit(FatalIOError);
164  }
165 }
166 
167 
168 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
169 
170 void Foam::codedBase::createLibrary
171 (
172  dynamicCode& dynCode,
173  const dynamicCodeContext& context
174 ) const
175 {
176  bool create =
178  || (regIOobject::fileModificationSkew <= 0); // not NFS
179 
180  if (create)
181  {
182  // Write files for new library
183  if (!dynCode.upToDate(context))
184  {
185  // filter with this context
186  dynCode.reset(context);
187 
188  this->prepare(dynCode, context);
189 
190  if (!dynCode.copyOrCreateFiles(true))
191  {
193  (
194  context.dict()
195  ) << "Failed writing files for" << nl
196  << dynCode.libRelPath() << nl
197  << exit(FatalIOError);
198  }
199  }
200 
201  if (!dynCode.wmakeLibso())
202  {
204  (
205  context.dict()
206  ) << "Failed wmake " << dynCode.libRelPath() << nl
207  << exit(FatalIOError);
208  }
209  }
210 
211 
212  // all processes must wait for compile to finish
214  {
215  //- Since the library has only been compiled on the master the
216  // other nodes need to pick this library up through NFS
217  // We do this by just polling a few times using the
218  // fileModificationSkew.
219 
220  const fileName libPath = dynCode.libPath();
221 
222  off_t mySize = Foam::fileSize(libPath);
223  off_t masterSize = mySize;
224  Pstream::scatter(masterSize);
225 
226  if (debug)
227  {
228  Pout<< endl<< "on processor " << Pstream::myProcNo()
229  << " have masterSize:" << masterSize
230  << " and localSize:" << mySize
231  << endl;
232  }
233 
234 
235  if (mySize < masterSize)
236  {
237  if (debug)
238  {
239  Pout<< "Local file " << libPath
240  << " not of same size (" << mySize
241  << ") as master ("
242  << masterSize << "). Waiting for "
244  << " seconds." << endl;
245  }
247 
248  // Recheck local size
249  mySize = Foam::fileSize(libPath);
250 
251  if (mySize < masterSize)
252  {
254  (
255  context.dict()
256  ) << "Cannot read (NFS mounted) library " << nl
257  << libPath << nl
258  << "on processor " << Pstream::myProcNo()
259  << " detected size " << mySize
260  << " whereas master size is " << masterSize
261  << " bytes." << nl
262  << "If your case is not NFS mounted"
263  << " (so distributed) set fileModificationSkew"
264  << " to 0"
265  << exit(FatalIOError);
266  }
267  }
268 
269  if (debug)
270  {
271  Pout<< endl<< "on processor " << Pstream::myProcNo()
272  << " after waiting: have masterSize:" << masterSize
273  << " and localSize:" << mySize
274  << endl;
275  }
276  }
277  reduce(create, orOp<bool>());
278 }
279 
280 
282 (
283  const word& name
284 ) const
285 {
286  const dictionary& dict = this->codeDict();
287 
289  (
290  "codedBase::updateLibrary()",
291  dict
292  );
293 
294  dynamicCodeContext context(dict);
295 
296  // codeName: name + _<sha1>
297  // codeDir : name
298  dynamicCode dynCode
299  (
300  name + context.sha1().str(true),
301  name
302  );
303  const fileName libPath = dynCode.libPath();
304 
305 
306  // the correct library was already loaded => we are done
307  if (libs().findLibrary(libPath))
308  {
309  return;
310  }
311 
312  Info<< "Using dynamicCode for " << this->description().c_str()
313  << " at line " << dict.startLineNumber()
314  << " in " << dict.name() << endl;
315 
316 
317  // remove instantiation of fvPatchField provided by library
318  this->clearRedirect();
319 
320  // may need to unload old library
321  unloadLibrary
322  (
323  oldLibPath_,
324  dynamicCode::libraryBaseName(oldLibPath_),
325  context.dict()
326  );
327 
328  // try loading an existing library (avoid compilation when possible)
329  if (!loadLibrary(libPath, dynCode.codeName(), context.dict()))
330  {
331  createLibrary(dynCode, context);
332 
333  loadLibrary(libPath, dynCode.codeName(), context.dict());
334  }
335 
336  // retain for future reference
337  oldLibPath_ = libPath;
338 }
339 
340 
341 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
342 
344 {}
345 
346 
347 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
348 
350 {}
351 
352 
353 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
354 
355 
356 // ************************************************************************* //
std::string str(const bool prefixed=false) const
Return (40-byte) text representation, optionally with &#39;_&#39; prefix.
Definition: SHA1Digest.C:112
dictionary dict
A class for handling file names.
Definition: fileName.H:69
Inter-processor communication reduction functions.
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
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
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
A class for handling words, derived from string.
Definition: word.H:59
void updateLibrary(const word &name) const
Update library as required.
Definition: codedBase.C:282
label startLineNumber() const
Return line number of first token in dictionary.
Definition: dictionary.C:246
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
codedBase()
Construct null.
Definition: codedBase.C:343
defineTypeNameAndDebug(combustionModel, 0)
static word libraryBaseName(const fileName &libPath)
Return the library basename without leading &#39;lib&#39; or trailing &#39;.so&#39;.
Definition: dynamicCode.C:93
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
const SHA1Digest & sha1() const
Return SHA1 digest calculated from include, options, code.
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:56
Encapsulation of dynamic code dictionaries.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:331
static int fileModificationSkew
Definition: regIOobject.H:126
messageStream Info
const dictionary & dict() const
Return the parent dictionary context.
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
virtual ~codedBase()
Destructor.
Definition: codedBase.C:349
void * dlSym(void *handle, const std::string &symbol)
Lookup a symbol in a dlopened library using handle to library.
Definition: POSIX.C:1066
bool dlSymFound(void *handle, const std::string &symbol)
Report if symbol in a dlopened library could be found.
Definition: POSIX.C:1094
Namespace for OpenFOAM.
IOerror FatalIOError