dlLibraryTable.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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2018-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "dlLibraryTable.H"
30 #include "OSspecific.H"
31 #include "IOstreams.H"
32 
33 // Could be constexpr in the header if required
34 #ifdef __APPLE__
35  #define EXT_SO "dylib"
36 #elif defined _WIN32
37  #define EXT_SO "dll"
38 #else
39  #define EXT_SO "so"
40 #endif
41 
42 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 
44 namespace Foam
45 {
46  defineTypeNameAndDebug(dlLibraryTable, 0);
47 }
48 
50 (
51  Foam::debug::optimisationSwitch("dlcloseOnTerminate", 0)
52 );
53 
54 
55 std::unique_ptr<Foam::dlLibraryTable> Foam::dlLibraryTable::global_(nullptr);
56 
57 
58 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
59 
61 {
62  word libName(libPath.nameLessExt());
63  libName.removeStart("lib"); // Remove leading 'lib' from name
64  return libName;
65 }
66 
67 
69 {
70  if (libName.empty())
71  {
72  return libName;
73  }
74 
75  // Add leading 'lib' and trailing '.so'
76  return "lib" + libName.ext(EXT_SO);
77 }
78 
79 
81 {
82  if (!global_)
83  {
84  global_.reset(new dlLibraryTable{});
85  }
86 
87  return *global_;
88 }
89 
90 
91 bool Foam::dlLibraryTable::functionHook
92 (
93  const bool load,
94  void* handle,
95  const std::string& funcName,
96  const bool verbose,
97  const std::string& context
98 )
99 {
100  if (!handle || funcName.empty())
101  {
102  return false;
103  }
104 
105  bool ok = false;
106 
107  void* symbol = Foam::dlSymFind(handle, funcName);
108 
109  if (symbol)
110  {
111  // Execute loader/unloader code
112  try
113  {
114  loaderType fun = reinterpret_cast<loaderType>(symbol);
115 
116  if (fun)
117  {
118  (*fun)(load);
119  ok = true;
120  }
121  }
122  catch (...)
123  {}
124  }
125 
126  if (verbose && !ok)
127  {
128  auto& err = WarningInFunction
129  << "Failed symbol lookup " << funcName.c_str() << nl;
130 
131  if (!context.empty())
132  {
133  err << "from " << context.c_str() << nl;
134  }
135  }
136 
137  return ok;
138 }
139 
140 
142 (
143  void* handle,
144  const std::string& funcName,
145  const bool verbose,
146  const std::string& context
147 )
148 {
149  return functionHook(true, handle, funcName, verbose, context);
150 }
151 
152 
154 (
155  void* handle,
156  const std::string& funcName,
157  const bool verbose,
158  const std::string& context
159 )
160 {
161  return functionHook(false, handle, funcName, verbose, context);
162 }
163 
164 
165 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
166 
167 void* Foam::dlLibraryTable::openLibrary
168 (
169  const fileName& libName,
170  bool verbose
171 )
172 {
173  if (libName.empty())
174  {
175  return nullptr;
176  }
177 
178  std::string msg;
179  void* ptr = Foam::dlOpen(fileName(libName).expand(), msg);
180 
182  << "Opened " << libName
183  << " resulting in handle " << Foam::name(ptr) << nl;
184 
185  if (!ptr)
186  {
187  // Even with details turned off, we want some feedback about failure
188  OSstream& os = (verbose ? WarningInFunction : Serr);
189  os << "Could not load " << libName << nl << msg.c_str() << endl;
190  }
191 
192  return ptr;
193 }
194 
195 
196 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
197 
199 (
200  const UList<fileName>& libNames,
201  bool verbose
202 )
203 {
204  dlLibraryTable::open(libNames, verbose);
205 }
206 
207 
209 (
210  std::initializer_list<fileName> libNames,
211  bool verbose
212 )
213 {
214  dlLibraryTable::open(libNames, verbose);
215 }
216 
217 
219 (
220  const word& libsEntry,
221  const dictionary& dict,
222  bool verbose
223 )
224 {
225  fileNameList libNames;
226  dict.readIfPresent(libsEntry, libNames);
227  dlLibraryTable::open(libNames, verbose);
228 }
229 
230 
232 (
233  const dictionary& dict,
234  const word& libsEntry,
235  bool verbose
236 
237 )
238 :
239  dlLibraryTable(libsEntry, dict, verbose)
240 {}
241 
242 
243 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
244 
246 {
248  {
249  close();
250  }
251 }
252 
253 
254 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
255 
257 {
258  for (const void* ptr : libPtrs_)
259  {
260  if (ptr != nullptr)
261  {
262  return false;
263  }
264  }
265 
266  return true;
267 }
268 
269 
270 Foam::label Foam::dlLibraryTable::size() const
271 {
272  label nLoaded = 0;
273 
274  for (const void* ptr : libPtrs_)
275  {
276  if (ptr != nullptr)
277  {
278  ++nLoaded;
279  }
280  }
281 
282  return nLoaded;
283 }
284 
285 
287 {
288  libPtrs_.clear();
289  libNames_.clear();
290 }
291 
292 
294 {
295  List<fileName> list(libNames_.size());
296 
297  label nLoaded = 0;
298 
299  forAll(libNames_, i)
300  {
301  void* ptr = libPtrs_[i];
302  const fileName& libName = libNames_[i];
303 
304  if (ptr != nullptr && !libName.empty())
305  {
306  list[nLoaded] = libName;
307  ++nLoaded;
308  }
309  }
310 
311  list.resize(nLoaded);
312 
313  return list;
314 }
315 
316 
317 void Foam::dlLibraryTable::close(bool verbose)
318 {
319  label nLoaded = 0;
320 
321  forAllReverse(libPtrs_, i)
322  {
323  void* ptr = libPtrs_[i];
324 
325  if (ptr == nullptr)
326  {
327  libNames_[i].clear();
328  continue;
329  }
330 
331  if (Foam::dlClose(ptr))
332  {
334  << "Closed [" << i << "] " << libNames_[i]
335  << " with handle " << Foam::name(ptr) << nl;
336 
337  libPtrs_[i] = nullptr;
338  libNames_[i].clear();
339  }
340  else
341  {
342  ++nLoaded; // Still loaded
343 
344  if (verbose)
345  {
347  << "Failed closing " << libNames_[i]
348  << " with handle " << Foam::name(ptr) << endl;
349  }
350  }
351  }
352 
353 
354  // Compact the lists
355  if (nLoaded && nLoaded != libPtrs_.size())
356  {
357  nLoaded = 0;
358 
359  forAll(libPtrs_, i)
360  {
361  if (libPtrs_[i] != nullptr)
362  {
363  if (nLoaded != i)
364  {
365  libPtrs_[nLoaded] = libPtrs_[i];
366  libNames_[nLoaded] = std::move(libNames_[i]);
367  }
368 
369  ++nLoaded;
370  }
371  }
372  }
373 
374  libPtrs_.resize(nLoaded);
375  libNames_.resize(nLoaded);
376 }
377 
378 
380 {
381  if (libName.empty() || libNames_.found(libName))
382  {
383  return false;
384  }
385 
386  libPtrs_.append(nullptr);
387  libNames_.append(libName);
388 
389  return true;
390 }
391 
392 
393 Foam::label Foam::dlLibraryTable::append(const UList<fileName>& libNames)
394 {
395  label nAdded = 0;
396 
397  for (const fileName& libName : libNames)
398  {
399  if (append(libName))
400  {
401  ++nAdded;
402  }
403  }
404 
405  return nAdded;
406 }
407 
408 
409 bool Foam::dlLibraryTable::open(bool verbose)
410 {
411  label nOpen = 0;
412  label nCand = 0; // Number of candidates (have libName but no pointer)
413 
414  forAll(libPtrs_, i)
415  {
416  void* ptr = libPtrs_[i];
417  const fileName& libName = libNames_[i];
418 
419  if (ptr == nullptr && !libName.empty())
420  {
421  ++nCand;
422 
423  ptr = openLibrary(libName, verbose);
424 
425  if (ptr)
426  {
427  ++nOpen;
428  libPtrs_[i] = ptr;
429  }
430  else
431  {
432  libNames_[i].clear(); // Avoid trying again
433  }
434  }
435  }
436 
437  return nOpen && nOpen == nCand;
438 }
439 
440 
442 (
443  const fileName& libName,
444  bool verbose
445 )
446 {
447  // Handles empty name silently
448  void* ptr = openLibrary(libName, verbose);
449 
450  if (ptr)
451  {
452  libPtrs_.append(ptr);
453  libNames_.append(libName);
454  }
455 
456  return ptr;
457 }
458 
459 
461 (
462  const UList<fileName>& libNames,
463  bool verbose
464 )
465 {
466  decltype(libNames.size()) nOpen = 0;
467 
468  for (const fileName& libName : libNames)
469  {
470  const label index = libNames_.find(libName);
471 
472  if (index >= 0 && libPtrs_[index] != nullptr)
473  {
474  // Already known and opened
475  ++nOpen;
476  }
477  else if (dlLibraryTable::open(libName, verbose))
478  {
479  ++nOpen;
480  }
481  }
482 
483  return nOpen && nOpen == libNames.size();
484 }
485 
486 
488 (
489  std::initializer_list<fileName> libNames,
490  bool verbose
491 )
492 {
493  decltype(libNames.size()) nOpen = 0;
494 
495  for (const fileName& libName : libNames)
496  {
497  const label index = libNames_.find(libName);
498 
499  if (index >= 0 && libPtrs_[index] != nullptr)
500  {
501  // Already known and opened
502  ++nOpen;
503  }
504  else if (dlLibraryTable::open(libName, verbose))
505  {
506  ++nOpen;
507  }
508  }
509 
510  return nOpen && nOpen == libNames.size();
511 }
512 
513 
515 (
516  const fileName& libName,
517  bool verbose
518 )
519 {
520  const label index = libNames_.rfind(libName);
521 
522  if (index < 0 || libName.empty())
523  {
524  return false;
525  }
526 
527  void* ptr = libPtrs_[index];
528 
529  if (ptr == nullptr)
530  {
531  libNames_[index].clear();
532  return false;
533  }
534 
536  << "Closing " << libName
537  << " with handle " << Foam::name(ptr) << nl;
538 
539  const bool ok = Foam::dlClose(ptr);
540 
541  libPtrs_[index] = nullptr;
542  libNames_[index].clear();
543 
544  if (ok)
545  {
546  // From man dlopen(3)
547  // ...
548  // a dynamically loaded shared object is not deallocated until
549  // dlclose() has been called on it as many times as dlopen()
550  // has succeeded on it.
551 
552  // Handle aliased library names
553  for (label idx = 0; (idx = libPtrs_.find(ptr, idx)) >= 0; ++idx)
554  {
555  (void) Foam::dlClose(ptr);
556  libPtrs_[idx] = nullptr;
557  libNames_[idx].clear();
558  }
559  }
560  else if (verbose)
561  {
563  << "Could not close " << libName << endl;
564  }
565 
566  return ok;
567 }
568 
569 
571 {
572  const label index = libNames_.rfind(libName);
573 
574  if (index < 0 || libName.empty())
575  {
576  return nullptr;
577  }
578 
579  return libPtrs_[index];
580 }
581 
582 
584 (
585  const word& libsEntry,
586  const dictionary& dict,
587  bool verbose
588 )
589 {
590  fileNameList libNames;
591  return
592  (
593  dict.readIfPresent(libsEntry, libNames)
594  && dlLibraryTable::open(libNames, verbose)
595  );
596 }
597 
598 
600 (
601  const dictionary& dict,
602  const word& libsEntry
603 )
604 {
605  return dlLibraryTable::open(libsEntry, dict, true); // verbose = true
606 }
607 
608 
609 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
610 
611 Foam::Ostream& Foam::operator<<
612 (
613  Ostream& os,
614  const InfoProxy<dlLibraryTable>& ip
615 )
616 {
617  const dlLibraryTable& tbl = ip.t_;
618 
619  os << token::BEGIN_LIST << nl;
620 
621  // Lengths of pointers/names are guaranteed internally to be identical
622  forAll(tbl.pointers(), i)
623  {
624  const void* ptr = tbl.pointers()[i];
625  const fileName& libName = tbl.names()[i];
626 
627  // Also write out empty filenames
628  // (specified with '-lib' but did not load)
629 
630  os << Foam::name(ptr) << token::SPACE << libName << nl;
631  }
632 
633  os << token::END_LIST << nl;
634 
635  return os;
636 }
637 
638 
639 // ************************************************************************* //
Foam::dlLibraryTable::loaded
List< fileName > loaded() const
Names of the libraries in use.
Definition: dlLibraryTable.C:293
Foam::dlLibraryTable::pointers
const UList< void * > & pointers() const
Pointers to the libraries in use. Access with caution.
Definition: dlLibraryTable.H:234
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::dlLibraryTable
A table of dynamically loaded libraries.
Definition: dlLibraryTable.H:63
Foam::dlLibraryTable::findLibrary
void * findLibrary(const fileName &libName)
Find the handle of the named library.
Definition: dlLibraryTable.C:570
IOstreams.H
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
Foam::fileName::nameLessExt
static std::string nameLessExt(const std::string &str)
Return basename, without extension.
Definition: fileName.C:402
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
EXT_SO
#define EXT_SO
Definition: dlLibraryTable.C:39
Foam::InfoProxy
A helper class for outputting values to Ostream.
Definition: InfoProxy.H:47
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::dlLibraryTable::close
void close(bool verbose=true)
Definition: dlLibraryTable.C:317
Foam::dlLibraryTable::basename
static word basename(const fileName &libPath)
Library basename without leading 'lib' or trailing '.so'.
Definition: dlLibraryTable.C:60
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::Serr
OSstream Serr
OSstream wrapped stderr (std::cerr)
Foam::word::ext
word ext() const
Return file name extension (part after last .)
Definition: word.C:126
append
rAUs append(new volScalarField(IOobject::groupName("rAU", phase1.name()), 1.0/(U1Eqn.A()+byDt(max(phase1.residualAlpha() - alpha1, scalar(0)) *rho1))))
Foam::dlLibraryTable::empty
bool empty() const
True if there are no libraries loaded by the table.
Definition: dlLibraryTable.C:256
Foam::dlLibraryTable::unloadHook
static bool unloadHook(void *handle, const std::string &funcName, const bool verbose=false, const std::string &context="")
Definition: dlLibraryTable.C:154
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::stringOps::expand
string expand(const std::string &s, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:720
Foam::dlLibraryTable::append
bool append(const fileName &libName)
Add to the list of names, but do not yet open.
Definition: dlLibraryTable.C:379
Foam::dlSymFind
void * dlSymFind(void *handle, const std::string &symbol, bool required=false)
Look for symbol in a dlopened library.
Definition: MSwindows.C:1321
DebugInFunction
#define DebugInFunction
Report an information message using Foam::Info.
Definition: messageStream.H:365
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::List::resize
void resize(const label newSize)
Adjust allocated size of list.
Definition: ListI.H:139
Foam::dlLibraryTable::names
const UList< fileName > & names() const
Names of the libraries in use, or requested.
Definition: dlLibraryTable.H:228
Foam::debug::optimisationSwitch
int optimisationSwitch(const char *name, const int deflt=0)
Lookup optimisation switch or add default value.
Definition: debug.C:237
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::dlLibraryTable::open
bool open(bool verbose=true)
Definition: dlLibraryTable.C:409
Foam::dlLibraryTable::dlcloseOnTerminate
static int dlcloseOnTerminate
Use dlclose() when clearing the dlLibraryTable.
Definition: dlLibraryTable.H:106
Foam::dlLibraryTable::libs
static dlLibraryTable & libs()
Table of global libraries.
Definition: dlLibraryTable.C:80
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::List< fileName >
Foam::token::SPACE
Space [isspace].
Definition: token.H:117
dlLibraryTable.H
Foam::dlLibraryTable::fullname
static word fullname(word libName)
Library fullname, prefix with 'lib', suffix with '.so'.
Definition: dlLibraryTable.C:68
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:103
Foam::dlClose
bool dlClose(void *handle)
Close a dlopened library using handle. Return true if successful.
Definition: MSwindows.C:1301
Foam::dlLibraryTable::loadHook
static bool loadHook(void *handle, const std::string &funcName, const bool verbose=false, const std::string &context="")
Definition: dlLibraryTable.C:142
Foam::token::END_LIST
End list [isseparator].
Definition: token.H:123
Foam::UList::size
void size(const label n) noexcept
Override size to be inconsistent with allocated storage.
Definition: UListI.H:360
forAllReverse
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:309
Foam::string::removeStart
bool removeStart(const std::string &text)
Remove the given text from the start of the string.
Definition: string.C:227
Foam::dlLibraryTable::size
label size() const
The number of libraries loaded by the table.
Definition: dlLibraryTable.C:270
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::dlLibraryTable::clear
void clear()
Clears the table, without attempting to close the libraries.
Definition: dlLibraryTable.C:286
Foam::token::BEGIN_LIST
Begin list [isseparator].
Definition: token.H:122
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:303
Foam::dlLibraryTable::dlLibraryTable
dlLibraryTable()=default
Default construct.
Foam::dlOpen
void * dlOpen(const fileName &libName, const bool check=true)
Open a shared library and return handle to library.
Definition: MSwindows.C:1206
Foam::dictionary::readIfPresent
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:417
Foam::dlLibraryTable::~dlLibraryTable
~dlLibraryTable()
Destructor. Closes all libraries loaded by the table.
Definition: dlLibraryTable.C:245