Provides an abstract interface for handling various DLL operations. More...
#include <DLL_Manager.h>
Public Member Functions | |
ACE_DLL_Handle (void) | |
Default construtor. | |
~ACE_DLL_Handle (void) | |
Destructor. | |
const ACE_TCHAR * | dll_name () const |
Returns the name of the shared library (without prefixes or suffixes). | |
int | open (const ACE_TCHAR *dll_name, int open_mode, ACE_SHLIB_HANDLE handle) |
int | close (int unload=0) |
sig_atomic_t | refcount (void) const |
Return the current refcount. | |
void * | symbol (const ACE_TCHAR *symbol_name, int ignore_errors=0) |
ACE_SHLIB_HANDLE | get_handle (int become_owner=0) |
Private Member Functions | |
auto_ptr< ACE_TString > | error (void) |
void | get_dll_names (const ACE_TCHAR *dll_name, ACE_Array< ACE_TString > &try_names) |
ACE_DLL_Handle (const ACE_DLL_Handle &) | |
Disallow copying and assignment since we don't handle them. | |
void | operator= (const ACE_DLL_Handle &) |
Private Attributes | |
sig_atomic_t | refcount_ |
ACE_TCHAR * | dll_name_ |
Name of the shared library. | |
ACE_SHLIB_HANDLE | handle_ |
Handle to the actual library loaded by the OS. | |
Static Private Attributes | |
static sig_atomic_t | open_called_ |
Provides an abstract interface for handling various DLL operations.
This class is an wrapper over the various methods for utilizing a dynamically linked library (DLL), which is called a shared library on some platforms. It is refcounted and managed by ACE_DLL_Manager, so there will only be a single instance of this class for each dll loaded, no matter how many instances of ACE_DLL an application has open. Operations open(), close(), and symbol() have been implemented to help opening/closing and extracting symbol information from a DLL, respectively.
Most of this class came from the original ACE_DLL class. ACE_DLL is now just an interface that passed all it's calls either directly or via ACE_DLL_Manager to this class for execution.
Definition at line 57 of file DLL_Manager.h.
ACE_DLL_Handle::ACE_DLL_Handle | ( | void | ) |
Default construtor.
ACE_DLL_Handle::~ACE_DLL_Handle | ( | void | ) |
Destructor.
Definition at line 35 of file DLL_Manager.cpp.
ACE_DLL_Handle::ACE_DLL_Handle | ( | const ACE_DLL_Handle & | ) | [private] |
Disallow copying and assignment since we don't handle them.
int ACE_DLL_Handle::close | ( | int | unload = 0 |
) |
Call to close the DLL object. If unload = 0, it only decrements the refcount, but if unload = 1, then it will actually unload the library when the refcount == 0;
Definition at line 238 of file DLL_Manager.cpp.
{ ACE_TRACE ("ACE_DLL_Handle::close"); int retval = 0; ACE_SHLIB_HANDLE h = ACE_SHLIB_INVALID_HANDLE; // Only hold the lock until it comes time to dlclose() the DLL. Closing // the DLL can cause further shutdowns as DLLs and their dependents are // unloaded. { ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); // Since we don't actually unload the dll as soon as the refcount // reaches zero, we need to make sure we don't decrement it below // zero. if (this->refcount_ > 0) --this->refcount_; else this->refcount_ = 0; if (ACE::debug ()) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE (%P|%t) DLL_Handle::close - ") ACE_TEXT ("%s (handle=%d, refcount=%d)\n"), this->dll_name_, this->handle_, this->refcount_)); if (this->refcount_ == 0 && this->handle_ != ACE_SHLIB_INVALID_HANDLE && unload == 1) { if (ACE::debug ()) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE (%P|%t) DLL_Handle::close: ") ACE_TEXT ("Unloading %s (handle=%d)\n"), this->dll_name_, this->handle_)); // First remove any associated Framework Components. ACE_Framework_Repository *frPtr= ACE_Framework_Repository::instance (); if (frPtr) { frPtr->remove_dll_components (this->dll_name_); } h = this->handle_; this->handle_ = ACE_SHLIB_INVALID_HANDLE; } } // Release lock_ here if (h != ACE_SHLIB_INVALID_HANDLE) { retval = ACE_OS::dlclose (h); if (retval != 0 && ACE::debug ()) ACE_ERROR ((LM_ERROR, ACE_TEXT ("ACE (%P|%t) DLL_Handle::close - ") ACE_TEXT ("Failed with: \"%s\".\n"), this->error ()->c_str ())); } return retval; }
const ACE_TCHAR * ACE_DLL_Handle::dll_name | ( | void | ) | const |
Returns the name of the shared library (without prefixes or suffixes).
Definition at line 43 of file DLL_Manager.cpp.
auto_ptr< ACE_TString > ACE_DLL_Handle::error | ( | void | ) | [private] |
Returns a pointer to a string explaining why <symbol> or <open> failed. This is used internal to print out the error to the log, but since this object is shared, we can't store or return the error to the caller.
Definition at line 385 of file DLL_Manager.cpp.
{ ACE_TRACE ("ACE_DLL_Handle::error"); const ACE_TCHAR *error = ACE_OS::dlerror (); auto_ptr<ACE_TString> str (new ACE_TString (error ? error : ACE_TEXT ("no error"))); return str; }
void ACE_DLL_Handle::get_dll_names | ( | const ACE_TCHAR * | dll_name, | |
ACE_Array< ACE_TString > & | try_names | |||
) | [private] |
Builds array of DLL names to try to dlopen, based on platform and configured DLL prefixes/suffixes. Returns the array of names to try in try_names.
Definition at line 395 of file DLL_Manager.cpp.
{ // Build the array of DLL names to try on this platform by applying the // proper prefixes and/or suffixes to the specified dll_name. ACE_TString base (dll_name); ACE_TString base_dir, base_file, base_suffix; // 1. Separate the dll_name into the dir part and the file part. We // only decorate the file part to determine the names to try loading. ACE_TString::size_type pos = base.rfind (ACE_DIRECTORY_SEPARATOR_CHAR); if (pos != ACE_TString::npos) { base_dir = base.substr (0, pos + 1); base_file = base.substr (pos + 1); } else base_file = base; // 2. Locate the file suffix, if there is one. Move the '.' and the // suffix to base_suffix. if ((pos = base_file.rfind (ACE_TEXT ('.'))) != ACE_TString::npos) { base_suffix = base_file.substr (pos); base_file = base_file.substr (0, pos); } // 3. Build the combinations to try for this platform. // Try these combinations: // - name with decorator and platform's suffix appended (if not supplied) // - name with platform's suffix appended (if not supplied) // - name with platform's dll prefix (if it has one) and suffix // - name with platform's dll prefix, decorator, and suffix. // - name as originally given // We first try to find the file using the decorator so that when a // filename with and without decorator is used, we get the file with // the same decorator as the ACE dll has and then as last resort // the one without. For example with msvc, the debug build has a "d" // decorator, but the release build has none and we really want to get // the debug version of the library in a debug application instead // of the release one. // So we need room for 5 entries in try_names. try_names.size (0); if ((try_names.max_size () - try_names.size ()) < 5) try_names.max_size (try_names.max_size () + 5); #if defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK) ACE_TString decorator (ACE_LD_DECORATOR_STR); #endif ACE_TString suffix (ACE_DLL_SUFFIX); ACE_TString prefix (ACE_DLL_PREFIX); for (size_t i = 0; i < 5 && try_names.size () < try_names.max_size (); ++i) { ACE_TString try_this; size_t const j = try_names.size (); switch (i) { case 0: // Name + decorator + suffix case 1: // Name + suffix case 2: // Prefix + name + decorator + suffix case 3: // Prefix + name + suffix if ( base_suffix.length () > 0 #if !(defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)) || (i == 1 || i == 3) // No decorator desired; skip #endif ) break; try_this = base_dir; if (i > 1) try_this += prefix; try_this += base_file; if (base_suffix.length () > 0) try_this += base_suffix; else { #if defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK) try_this += decorator; #endif try_this += suffix; } break; case 4: try_this = dll_name; break; } if (try_this.length ()) { try_names.size (j + 1); try_names.set (try_this, j); } } return; }
ACE_SHLIB_HANDLE ACE_DLL_Handle::get_handle | ( | int | become_owner = 0 |
) |
Return the handle to the caller. If become_owner is non-0 then caller assumes ownership of the handle so we decrement the retcount.
Definition at line 348 of file DLL_Manager.cpp.
{ ACE_TRACE ("ACE_DLL_Handle::get_handle"); ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); if (this->refcount_ == 0 && become_owner != 0) { if (ACE::debug ()) ACE_ERROR ((LM_ERROR, ACE_TEXT ("ACE (%P|%t) DLL_Handle::get_handle: ") ACE_TEXT ("cannot become owner, refcount == 0.\n"))); return ACE_SHLIB_INVALID_HANDLE; } ACE_SHLIB_HANDLE handle = this->handle_; if (become_owner != 0) { if (--this->refcount_ == 0) this->handle_ = ACE_SHLIB_INVALID_HANDLE; } if (ACE::debug ()) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE (%P|%t) DLL_Handle::get_handle: ") ACE_TEXT ("post call: handle %s, refcount %d\n"), this->handle_ == ACE_SHLIB_INVALID_HANDLE ? ACE_TEXT ("invalid") : ACE_TEXT ("valid"), this->refcount_)); return handle; }
int ACE_DLL_Handle::open | ( | const ACE_TCHAR * | dll_name, | |
int | open_mode, | |||
ACE_SHLIB_HANDLE | handle | |||
) |
This method opens and dynamically links dll_name. The default mode is RTLD_LAZY
, which loads identifier symbols but not the symbols for functions, which are loaded dynamically on-demand. Other supported modes include: RTLD_NOW
, which performs all necessary relocations when dll_name is first loaded and RTLD_GLOBAL
, which makes symbols available for relocation processing of any other DLLs. Returns -1 on failure and 0 on success.
Definition at line 50 of file DLL_Manager.cpp.
{ ACE_TRACE ("ACE_DLL_Handle::open"); ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); if (this->dll_name_) { // Once dll_name_ has been set, it can't be changed.. if (ACE_OS::strcmp (this->dll_name_, dll_name) != 0) { if (ACE::debug ()) ACE_ERROR ((LM_ERROR, ACE_TEXT ("ACE (%P|%t) DLL_Handle::open: error, ") ACE_TEXT ("tried to reopen %s with name %s\n"), this->dll_name_, dll_name)); return -1; } } else this->dll_name_ = ACE::strnew (dll_name); if (!this->open_called_) this->open_called_ = 1; // If it hasn't been loaded yet, go ahead and do that now. if (this->handle_ == ACE_SHLIB_INVALID_HANDLE) { if (handle) this->handle_ = handle; else { /* ** Get the set of names to try loading. We need to do this to ** properly support the ability for a user to specify a simple, ** unadorned name (for example, "ACE") that will work across ** platforms. We apply platform specifics to get a name that will ** work (e.g. libACE, ACEd.dll, ACE.dll, etc.) We rely on the ** underlying dlopen() implementation to "Do The Right Thing" in ** terms of using relative paths, LD_LIBRARY_PATH, system security ** rules, etc. except when ACE_MUST_HELP_DLOPEN_SEARCH_PATH is set. ** If it is set, then ACE::ldfind() scans the configured path ** looking for a match on the name and prefix/suffix applications. ** NOTE: having ACE scan for a file and then pass a fully-qualified ** pathname to dlopen() is a potential security hole; therefore, ** do not use ACE_MUST_HELP_DLOPEN_SEARCH_PATH unless necessary ** and only after considering the risks. */ ACE_Array<ACE_TString> dll_names; dll_names.max_size (10); // Decent guess to avoid realloc later #if defined (ACE_MUST_HELP_DLOPEN_SEARCH_PATH) // Find out where the library is ACE_TCHAR dll_pathname[MAXPATHLEN + 1]; // Transform the pathname into the appropriate dynamic link library // by searching the ACE_LD_SEARCH_PATH. ACE::ldfind (dll_name, dll_pathname, (sizeof dll_pathname / sizeof (ACE_TCHAR))); ACE_TString dll_str (dll_pathname); dll_names.size (1); dll_names.set (dll_str, 0); #else this->get_dll_names (dll_name, dll_names); #endif ACE_Array_Iterator<ACE_TString> name_iter (dll_names); ACE_TString *name = 0; while (name_iter.next (name)) { // The ACE_SHLIB_HANDLE object is obtained. this->handle_ = ACE_OS::dlopen (name->c_str (), open_mode); if (ACE::debug ()) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE (%P|%t) DLL_Handle::open ") ACE_TEXT ("(\"%s\", 0x%x) -> %s: %s\n"), name->c_str (), open_mode, ((this->handle_ != ACE_SHLIB_INVALID_HANDLE) ? ACE_TEXT ("succeeded") : ACE_TEXT ("failed")), this->error()->c_str())); } if (this->handle_ != ACE_SHLIB_INVALID_HANDLE) // Good one? break; // If errno is ENOENT we just skip over this one, // anything else - like an undefined symbol, for // instance must be flagged here or the next error will // mask it. // @TODO: If we've found our DLL _and_ it's // broken, should we continue at all? if ((errno != 0) && (errno != ENOENT) && ACE::debug ()) ACE_ERROR ((LM_ERROR, ACE_TEXT ("ACE (%P|%t) DLL_Handle::open ") ACE_TEXT ("(\'%s\') failed, errno=") ACE_TEXT ("%d: <%s>\n"), name->c_str (), ACE_ERRNO_GET, this->error ()->c_str ())); #if defined (AIX) // AIX often puts the shared library file (most often named // shr.o) inside an archive library. If this is an archive // library name, then try appending [shr.o] and retry. if (ACE_TString::npos != name->strstr (ACE_TEXT (".a"))) { ACE_TCHAR aix_pathname[MAXPATHLEN + 1]; ACE_OS::strncpy (aix_pathname, name->c_str (), name->length ()); aix_pathname[name->length ()] = '\0'; ACE_OS::strcat (aix_pathname, ACE_TEXT ("(shr.o)")); open_mode |= RTLD_MEMBER; if (ACE::debug ()) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE (%P|%t) DLL_Handle::open ") ACE_TEXT ("(\"%s\", 0x%x) -> %s: %s\n"), aix_pathname, open_mode, (this->handle_ != ACE_SHLIB_INVALID_HANDLE ? ACE_TEXT ("succeeded") : ACE_TEXT ("failed")), this->error()->c_str())); } this->handle_ = ACE_OS::dlopen (aix_pathname, open_mode); if (this->handle_ != ACE_SHLIB_INVALID_HANDLE) break; // If errno is ENOENT we just skip over this one, anything // else - like an undefined symbol, for instance // must be flagged here or the next error will mask it. // // @TODO: If we've found our DLL _and_ it's broken, // should we continue at all? if (ACE::debug () && (errno != 0) && (errno != ENOENT)) ACE_ERROR ((LM_ERROR, ACE_TEXT ("ACE (%P|%t) DLL_Handle::open ") ACE_TEXT ("(\'%s\') failed, errno=") ACE_TEXT ("%d: %s\n"), name->c_str (), errno, this->error ()->c_str ())); } #endif /* AIX */ name_iter.advance (); } if (this->handle_ == ACE_SHLIB_INVALID_HANDLE) { if (ACE::debug ()) ACE_ERROR ((LM_ERROR, ACE_TEXT ("ACE (%P|%t) DLL_Handle::open (\"%s\"): ") ACE_TEXT ("Invalid handle error: %s\n"), this->dll_name_, this->error ()->c_str ())); return -1; } } } ++this->refcount_; if (ACE::debug ()) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE (%P|%t) DLL_Handle::open - %s (%d), refcount=%d\n"), this->dll_name_, this->handle_, this->refcount_)); return 0; }
void ACE_DLL_Handle::operator= | ( | const ACE_DLL_Handle & | ) | [private] |
sig_atomic_t ACE_DLL_Handle::refcount | ( | void | ) | const |
Return the current refcount.
Definition at line 305 of file DLL_Manager.cpp.
{ return this->refcount_; }
void * ACE_DLL_Handle::symbol | ( | const ACE_TCHAR * | symbol_name, | |
int | ignore_errors = 0 | |||
) |
If symbol_name is in the symbol table of the DLL a pointer to the symbol_name is returned. Otherwise, returns 0. Set the ignore_errors flag to supress logging errors if symbol_name isn't found. This is nice if you just want to probe a dll to see what's available, since missing functions in that case aren't really errors.
Definition at line 311 of file DLL_Manager.cpp.
{ ACE_TRACE ("ACE_DLL_Handle::symbol"); ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); ACE_Auto_Array_Ptr <ACE_TCHAR> auto_name (ACE::ldname (sym_name)); // handle_ can be invalid especially when ACE_DLL_Handle resigned ownership // BTW. Handle lifecycle management is a little crazy in ACE if (this->handle_ != ACE_SHLIB_INVALID_HANDLE) { #if defined (ACE_OPENVMS) void *sym = ACE::ldsymbol (this->handle_, auto_name.get ()); #else void *sym = ACE_OS::dlsym (this->handle_, auto_name.get ()); #endif // Linux says that the symbol could be null and that it isn't an // error. So you should check the error message also, but since // null symbols won't do us much good anyway, let's still report // an error. if (!sym && ignore_errors != 1) { if (ACE::debug ()) ACE_ERROR ((LM_ERROR, ACE_TEXT ("ACE (%P|%t) DLL_Handle::symbol (\"%s\") ") ACE_TEXT (" failed with \"%s\".\n"), auto_name.get (), this->error ()->c_str ())); return 0; } return sym; } return 0; }
ACE_TCHAR* ACE_DLL_Handle::dll_name_ [private] |
Name of the shared library.
Definition at line 130 of file DLL_Manager.h.
ACE_SHLIB_HANDLE ACE_DLL_Handle::handle_ [private] |
Handle to the actual library loaded by the OS.
Definition at line 133 of file DLL_Manager.h.
sig_atomic_t ACE_DLL_Handle::open_called_ [static, private] |
Keeps track of whether or not open() has ever been called. This helps get around problem on Linux, and perhaps other OS's, that seg-fault if dlerror() is called before the ld library has been initialized by a call to dlopen().
Definition at line 139 of file DLL_Manager.h.
sig_atomic_t ACE_DLL_Handle::refcount_ [private] |
Keep track of how many ACE_DLL objects have a reference to this dll.
Definition at line 127 of file DLL_Manager.h.