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-------------------------------------------------------------------------------
11License
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
44namespace Foam
45{
47}
48
50(
51 Foam::debug::optimisationSwitch("dlcloseOnTerminate", 0)
52);
53
54
55std::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
91bool 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
167void* 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
270Foam::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
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
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
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
611Foam::Ostream& Foam::operator<<
612(
613 Ostream& os,
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// ************************************************************************* //
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
A helper class for outputting values to Ostream.
Definition: InfoProxy.H:52
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: UList.H:94
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
A table of dynamically loaded libraries.
const UList< void * > & pointers() const
Pointers to the libraries in use. Access with caution.
static bool unloadHook(void *handle, const std::string &funcName, const bool verbose=false, const std::string &context="")
label size() const
The number of libraries loaded by the table.
static dlLibraryTable & libs()
Table of global libraries.
bool empty() const
True if there are no libraries loaded by the table.
List< fileName > loaded() const
Names of the libraries in use.
~dlLibraryTable()
Destructor. Closes all libraries loaded by the table.
const UList< fileName > & names() const
Names of the libraries in use, or requested.
static bool loadHook(void *handle, const std::string &funcName, const bool verbose=false, const std::string &context="")
void * findLibrary(const fileName &libName)
Find the handle of the named library.
static word fullname(word libName)
Library fullname, prefix with 'lib', suffix with '.so'.
void clear()
Clears the table, without attempting to close the libraries.
static word basename(const fileName &libPath)
Library basename without leading 'lib' or trailing '.so'.
static int dlcloseOnTerminate
Use dlclose() when clearing the dlLibraryTable.
dlLibraryTable()=default
Default construct.
A class for handling file names.
Definition: fileName.H:76
static std::string nameLessExt(const std::string &str)
Return basename, without extension.
Definition: fileName.C:396
bool removeStart(const std::string &text)
Remove the given text from the start of the string.
Definition: string.C:214
@ BEGIN_LIST
Begin list [isseparator].
Definition: token.H:155
@ END_LIST
End list [isseparator].
Definition: token.H:156
@ SPACE
Space [isspace].
Definition: token.H:125
bool append() const noexcept
True if output format uses an append mode.
A class for handling words, derived from Foam::string.
Definition: word.H:68
word ext() const
Return file name extension (part after last .)
Definition: word.C:126
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
#define EXT_SO
OBJstream os(runTime.globalPath()/outputName)
#define WarningInFunction
Report a warning using Foam::Warning.
#define DebugInFunction
Report an information message using Foam::Info.
rAUs append(new volScalarField(IOobject::groupName("rAU", phase1.name()), 1.0/(U1Eqn.A()+byDt(max(phase1.residualAlpha() - alpha1, scalar(0)) *rho1))))
int optimisationSwitch(const char *name, const int deflt=0)
Lookup optimisation switch or add default value.
Definition: debug.C:237
Namespace for OpenFOAM.
bool dlClose(void *handle)
Close a dlopened library using handle. Return true if successful.
Definition: MSwindows.C:1319
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
void * dlSymFind(void *handle, const std::string &symbol, bool required=false)
Look for symbol in a dlopened library.
Definition: MSwindows.C:1339
OSstream Serr
OSstream wrapped stderr (std::cerr)
void * dlOpen(const fileName &libName, const bool check=true)
Open a shared library and return handle to library.
Definition: MSwindows.C:1224
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:346
static constexpr char close
Definition: FlatOutput.H:74
static constexpr char open
Definition: FlatOutput.H:73