Loading...
Searching...
No Matches
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-2024 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"
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);
54
55std::unique_ptr<Foam::dlLibraryTable> Foam::dlLibraryTable::global_(nullptr);
56
57
58// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
59
62 word libName(libPath.stem());
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;
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 > 0 ? WarningInFunction : InfoErr);
189 os << "Could not load " << libName << nl << msg.c_str() << endl;
190 }
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)
225 List<fileName> libNames;
226 dict.readIfPresent(libsEntry, libNames, keyType::LITERAL);
227 dlLibraryTable::open(libNames, verbose);
228}
229
230
232(
233 const dictionary& dict,
234 const word& libsEntry,
235 bool verbose
236
237)
239 dlLibraryTable(libsEntry, dict, verbose)
240{}
241
242
243// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
244
246{
248 {
250 }
251}
252
253
254// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
255
257{
258 for (const void* ptr : libPtrs_)
259 {
260 if (ptr != nullptr)
261 {
262 return false;
264 }
265
266 return true;
267}
268
269
270Foam::label Foam::dlLibraryTable::size() const noexcept
271{
272 label nLoaded = 0;
273
274 for (const void* ptr : libPtrs_)
275 {
276 if (ptr != nullptr)
277 {
278 ++nLoaded;
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 }
311 list.resize(nLoaded);
312
313 return list;
314}
315
316
317void 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 }
373
374 libPtrs_.resize(nLoaded);
375 libNames_.resize(nLoaded);
376}
377
378
379bool Foam::dlLibraryTable::push_back(const fileName& libName)
380{
381 if (libName.empty() || libNames_.contains(libName))
382 {
383 return false;
384 }
385
386 libPtrs_.push_back(nullptr);
387 libNames_.push_back(libName);
388
389 return true;
390}
391
392
393Foam::label Foam::dlLibraryTable::push_back(const UList<fileName>& libNames)
394{
395 label nAdded = 0;
396
397 for (const fileName& libName : libNames)
398 {
399 if (push_back(libName))
400 {
401 ++nAdded;
403 }
404
405 return nAdded;
406}
407
408
409bool 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 }
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_.push_back(ptr);
453 libNames_.push_back(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;
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;
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
570void* Foam::dlLibraryTable::findLibrary(const fileName& libName)
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 List<fileName> libNames;
591 return
593 dict.readIfPresent(libsEntry, libNames, keyType::LITERAL)
594 && dlLibraryTable::open(libNames, verbose)
595 );
596}
597
598
600(
601 const dictionary& dict,
602 const word& libsEntry
603)
605 return dlLibraryTable::open(libsEntry, dict, true); // verbose = true
606}
607
608
609// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
610
611Foam::Ostream& Foam::operator<<
612(
613 Ostream& os,
614 const InfoProxy<dlLibraryTable>& iproxy
615)
616{
617 const auto& tbl = *iproxy;
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:49
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void resize(const label len)
Adjust allocated size of list.
Definition ListI.H:153
Generic output stream using a standard (STL) stream.
Definition OSstream.H:53
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
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:89
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
A table of dynamically loaded libraries.
bool push_back(const fileName &libName)
Add to the list of names, but do not yet open.
bool open(bool verbose=true)
Open named, but unopened libraries. These names will normally have been added with push_back().
static bool unloadHook(void *handle, const std::string &funcName, const bool verbose=false, const std::string &context="")
Low-level interface to execute global "void funcName(false)" from the library, typically for unloadin...
bool empty() const noexcept
True if there are no libraries loaded by the table.
static dlLibraryTable & libs()
Table of global libraries.
List< fileName > loaded() const
Names of the libraries in use.
~dlLibraryTable()
Destructor. Closes all libraries loaded by the table.
label size() const noexcept
The number of libraries loaded by the table.
static bool loadHook(void *handle, const std::string &funcName, const bool verbose=false, const std::string &context="")
Low-level interface to execute global "void funcName(true)" from the library, typically for additiona...
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.
void close(bool verbose=true)
Close all libraries loaded by the table and remove the closed functions from the table.
A class for handling file names.
Definition fileName.H:75
static std::string stem(const std::string &str)
Return the basename, without extension.
Definition fileName.C:391
@ LITERAL
String literal.
Definition keyType.H:82
bool removeStart(const std::string &text)
Remove the given text from the start of the string.
Definition string.C:207
bool contains(char c) const noexcept
True if string contains given character (cf. C++23).
Definition string.H:412
@ BEGIN_LIST
Begin list [isseparator].
Definition token.H:174
@ END_LIST
End list [isseparator].
Definition token.H:175
@ SPACE
Space [isspace].
Definition token.H:144
A class for handling words, derived from Foam::string.
Definition word.H:66
word ext() const
Return file name extension (part after last .).
Definition wordI.H:171
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#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.
int optimisationSwitch(const char *name, const int deflt=0)
Lookup optimisation switch or add default value.
Definition debug.C:234
string expand(const std::string &s, const HashTable< string > &mapping, const char sigil='$')
Expand occurrences of variables according to the mapping and return the expanded string.
Namespace for OpenFOAM.
bool dlClose(void *handle)
Close a dlopened library using handle. Return true if successful.
Definition POSIX.C:1929
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
void * dlSymFind(void *handle, const std::string &symbol, bool required=false)
Look for symbol in a dlopened library.
Definition POSIX.C:1941
void * dlOpen(const fileName &libName, const bool check=true)
Open a shared library and return handle to library.
Definition POSIX.C:1826
const direction noexcept
Definition scalarImpl.H:265
messageStream InfoErr
Information stream (stderr output on master, null elsewhere).
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition stdFoam.H:315