1 #include "ace/DLL_Manager.h"
3 #include "ace/Auto_Ptr.h"
4 #include "ace/Log_Category.h"
6 #include "ace/Framework_Component.h"
8 #include "ace/Lib_Find.h"
9 #include "ace/Object_Manager.h"
10 #include "ace/SString.h"
11 #include "ace/Recursive_Thread_Mutex.h"
12 #include "ace/Guard_T.h"
13 #include "ace/OS_NS_dlfcn.h"
14 #include "ace/OS_NS_string.h"
16 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
18 sig_atomic_t ACE_DLL_Handle::open_called_
= 0;
20 ACE_DLL_Handle::ACE_DLL_Handle ()
23 handle_ (ACE_SHLIB_INVALID_HANDLE
)
25 ACE_TRACE ("ACE_DLL_Handle::ACE_DLL_Handle");
28 ACE_DLL_Handle::~ACE_DLL_Handle ()
30 ACE_TRACE ("ACE_DLL_Handle::~ACE_DLL_Handle");
32 #if defined (ACE_HAS_ALLOC_HOOKS)
33 ACE_Allocator::instance()->free(this->dll_name_
);
35 delete[] this->dll_name_
;
36 #endif /* ACE_HAS_ALLOC_HOOKS */
39 ACE_ALLOC_HOOK_DEFINE(ACE_DLL_Handle
)
42 ACE_DLL_Handle::dll_name () const
44 ACE_TRACE ("ACE_DLL_Handle::dll_name");
45 return this->dll_name_
;
49 ACE_DLL_Handle::open (const ACE_TCHAR
*dll_name
,
51 ACE_SHLIB_HANDLE handle
,
54 ACE_TRACE ("ACE_DLL_Handle::open");
55 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, 0));
59 // Once dll_name_ has been set, it can't be changed..
60 if (ACE_OS::strcmp (this->dll_name_
, dll_name
) != 0)
63 ACELIB_ERROR ((LM_ERROR
,
64 ACE_TEXT ("ACE (%P|%t) DLL_Handle::open: error, ")
65 ACE_TEXT ("tried to reopen <%s> with name <%s>\n"),
73 this->dll_name_
= ACE::strnew (dll_name
);
75 if (!this->open_called_
)
76 this->open_called_
= 1;
78 // If it hasn't been loaded yet, go ahead and do that now.
79 if (this->handle_
== ACE_SHLIB_INVALID_HANDLE
)
82 this->handle_
= handle
;
86 ** Get the set of names to try loading. We need to do this to
87 ** properly support the ability for a user to specify a simple,
88 ** unadorned name (for example, "ACE") that will work across
89 ** platforms. We apply platform specifics to get a name that will
90 ** work (e.g. libACE, ACEd.dll, ACE.dll, etc.) We rely on the
91 ** underlying dlopen() implementation to "Do The Right Thing" in
92 ** terms of using relative paths, LD_LIBRARY_PATH, system security
93 ** rules, etc. except when ACE_MUST_HELP_DLOPEN_SEARCH_PATH is set.
94 ** If it is set, then ACE::ldfind() scans the configured path
95 ** looking for a match on the name and prefix/suffix applications.
96 ** NOTE: having ACE scan for a file and then pass a fully-qualified
97 ** pathname to dlopen() is a potential security hole; therefore,
98 ** do not use ACE_MUST_HELP_DLOPEN_SEARCH_PATH unless necessary
99 ** and only after considering the risks.
101 ACE_Array
<ACE_TString
> dll_names
;
102 dll_names
.max_size (10); // Decent guess to avoid realloc later
104 #if defined (ACE_MUST_HELP_DLOPEN_SEARCH_PATH)
105 // Find out where the library is
106 ACE_TCHAR dll_pathname
[MAXPATHLEN
+ 1];
108 // Transform the pathname into the appropriate dynamic link library
109 // by searching the ACE_LD_SEARCH_PATH.
110 ACE::ldfind (dll_name
,
112 (sizeof dll_pathname
/ sizeof (ACE_TCHAR
)));
113 ACE_TString
dll_str (dll_pathname
);
115 dll_names
.set (dll_str
, 0);
117 this->get_dll_names (dll_name
, dll_names
);
120 ACE_TString
*name
= 0;
121 for (ACE_Array_Iterator
<ACE_TString
> name_iter (dll_names
);
122 name_iter
.next (name
); name_iter
.advance ())
124 if (this->open_i (name
->c_str (), open_mode
, errors
))
128 if (this->handle_
== ACE_SHLIB_INVALID_HANDLE
)
133 this->error (errtmp
);
134 ACELIB_ERROR ((LM_ERROR
,
135 ACE_TEXT ("ACE (%P|%t) DLL_Handle::open (\"%s\"): ")
136 ACE_TEXT ("Invalid handle error: %s\n"),
148 ACELIB_DEBUG ((LM_DEBUG
,
149 ACE_TEXT ("ACE (%P|%t) DLL_Handle::open - <%s> (%d), refcount=%d\n"),
158 ACE_DLL_Handle::close (int unload
)
160 ACE_TRACE ("ACE_DLL_Handle::close");
163 ACE_SHLIB_HANDLE h
= ACE_SHLIB_INVALID_HANDLE
;
165 // Only hold the lock until it comes time to dlclose() the DLL. Closing
166 // the DLL can cause further shutdowns as DLLs and their dependents are
169 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, 0));
171 // Since we don't actually unload the dll as soon as the refcount
172 // reaches zero, we need to make sure we don't decrement it below
174 if (this->refcount_
> 0)
180 ACELIB_DEBUG ((LM_DEBUG
,
181 ACE_TEXT ("ACE (%P|%t) DLL_Handle::close - ")
182 ACE_TEXT ("<%s> (handle=%d, refcount=%d)\n"),
187 if (this->refcount_
== 0 &&
188 this->handle_
!= ACE_SHLIB_INVALID_HANDLE
&&
192 ACELIB_DEBUG ((LM_DEBUG
,
193 ACE_TEXT ("ACE (%P|%t) DLL_Handle::close: ")
194 ACE_TEXT ("Unloading <%s> (handle=%d)\n"),
198 // First remove any associated Framework Components.
199 ACE_Framework_Repository
*frPtr
= ACE_Framework_Repository::instance ();
202 frPtr
->remove_dll_components (this->dll_name_
);
206 this->handle_
= ACE_SHLIB_INVALID_HANDLE
;
208 } // Release lock_ here
210 if (h
!= ACE_SHLIB_INVALID_HANDLE
)
212 retval
= ACE_OS::dlclose (h
);
214 if (retval
!= 0 && ACE::debug ())
217 ACELIB_ERROR ((LM_ERROR
,
218 ACE_TEXT ("ACE (%P|%t) DLL_Handle::close - ")
219 ACE_TEXT ("Failed with: <%s>\n"),
220 this->error (err
).c_str ()));
228 ACE_DLL_Handle::refcount () const
230 return this->refcount_
;
234 ACE_DLL_Handle::symbol (const ACE_TCHAR
*sym_name
, bool ignore_errors
)
237 return this->symbol (sym_name
, ignore_errors
, error
);
241 ACE_DLL_Handle::symbol (const ACE_TCHAR
*sym_name
, bool ignore_errors
, ACE_TString
&error
)
243 ACE_TRACE ("ACE_DLL_Handle::symbol");
244 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, 0));
246 ACE_Auto_Array_Ptr
<ACE_TCHAR
> auto_name (ACE::ldname (sym_name
));
247 // handle_ can be invalid especially when ACE_DLL_Handle resigned ownership
248 // BTW. Handle lifecycle management is a little crazy in ACE
249 if (this->handle_
!= ACE_SHLIB_INVALID_HANDLE
)
251 void *sym
= ACE_OS::dlsym (this->handle_
, auto_name
.get ());
253 // Linux says that the symbol could be null and that it isn't an
254 // error. So you should check the error message also, but since
255 // null symbols won't do us much good anyway, let's still report
257 if (!sym
&& !ignore_errors
)
262 ACELIB_ERROR ((LM_ERROR
,
263 ACE_TEXT ("ACE (%P|%t) DLL_Handle::symbol <%s>")
264 ACE_TEXT (" failed with <%s>\n"),
276 ACE_DLL_Handle::get_handle (bool become_owner
)
278 ACE_TRACE ("ACE_DLL_Handle::get_handle");
279 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, 0));
281 if (this->refcount_
== 0 && become_owner
)
284 ACELIB_ERROR ((LM_ERROR
,
285 ACE_TEXT ("ACE (%P|%t) DLL_Handle::get_handle: ")
286 ACE_TEXT ("cannot become owner, refcount == 0.\n")));
288 return ACE_SHLIB_INVALID_HANDLE
;
291 ACE_SHLIB_HANDLE handle
= this->handle_
;
295 if (--this->refcount_
== 0)
296 this->handle_
= ACE_SHLIB_INVALID_HANDLE
;
300 ACELIB_DEBUG ((LM_DEBUG
,
301 ACE_TEXT ("ACE (%P|%t) DLL_Handle::get_handle: ")
302 ACE_TEXT ("post call: handle %s, refcount %d\n"),
303 this->handle_
== ACE_SHLIB_INVALID_HANDLE
?
304 ACE_TEXT ("invalid") : ACE_TEXT ("valid"),
310 // This method is used return the last error of a library operation.
312 ACE_DLL_Handle::error (ACE_TString
&err
)
314 ACE_TRACE ("ACE_DLL_Handle::error");
315 const ACE_TCHAR
*error
= ACE_OS::dlerror ();
324 ACE_DLL_Handle::get_dll_names (const ACE_TCHAR
*dll_name
,
325 ACE_Array
<ACE_TString
> &try_names
)
327 // Build the array of DLL names to try on this platform by applying the
328 // proper prefixes and/or suffixes to the specified dll_name.
329 ACE_TString
base (dll_name
);
330 ACE_TString base_dir
, base_file
, base_suffix
;
332 // 1. Separate the dll_name into the dir part and the file part. We
333 // only decorate the file part to determine the names to try loading.
334 ACE_TString::size_type pos
= base
.rfind (ACE_DIRECTORY_SEPARATOR_CHAR
);
335 if (pos
!= ACE_TString::npos
)
337 base_dir
= base
.substr (0, pos
+ 1);
338 base_file
= base
.substr (pos
+ 1);
343 // 2. Locate the file suffix, if there is one. Move the '.' and the
344 // suffix to base_suffix.
345 if ((pos
= base_file
.rfind (ACE_TEXT ('.'))) != ACE_TString::npos
)
347 base_suffix
= base_file
.substr (pos
);
348 base_file
= base_file
.substr (0, pos
);
351 // 3. Build the combinations to try for this platform.
352 // Try these combinations:
353 // - name with platform's dll prefix (if it has one) and suffix
354 // - name with platform's dll prefix, decorator, and suffix.
355 // - name with decorator and platform's suffix appended (if not supplied)
356 // - name with platform's suffix appended (if not supplied)
357 // - name as originally given
358 // We first try to find the file using the decorator so that when a
359 // filename with and without decorator is used, we get the file with
360 // the same decorator as the ACE dll has and then as last resort
361 // the one without. For example with msvc, the debug build has a "d"
362 // decorator, but the release build has none and we really want to get
363 // the debug version of the library in a debug application instead
364 // of the release one.
365 // So we need room for 5 entries in try_names.
367 if ((try_names
.max_size () - try_names
.size ()) < 5)
368 try_names
.max_size (try_names
.max_size () + 5);
369 #if defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
370 ACE_TString
decorator (ACE_LD_DECORATOR_STR
);
372 ACE_TString
suffix (ACE_DLL_SUFFIX
);
373 ACE_TString
prefix (ACE_DLL_PREFIX
);
375 for (size_t i
= 0; i
< 5 && try_names
.size () < try_names
.max_size (); ++i
)
377 ACE_TString try_this
;
378 size_t const j
= try_names
.size ();
381 case 0: // Prefix + name + decorator + suffix
382 case 1: // Prefix + name + suffix
383 case 2: // Name + decorator + suffix
384 case 3: // Name + suffix
386 base_suffix
.length () > 0
387 #if !(defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK))
388 || (i
== 1 || i
== 3) // No decorator desired; skip
395 try_this
+= base_file
;
396 if (base_suffix
.length () > 0)
397 try_this
+= base_suffix
;
400 #if defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
401 try_this
+= decorator
;
411 if (try_this
.length ())
413 try_names
.size (j
+ 1);
414 try_names
.set (try_this
, j
);
421 ACE_DLL_Handle::open_i (const ACE_TCHAR
*dll_name
, int open_mode
, ERROR_STACK
* errors
)
423 // The ACE_SHLIB_HANDLE object is obtained.
424 this->handle_
= ACE_OS::dlopen (dll_name
, open_mode
);
426 if (errors
|| ACE::debug ())
430 if (errors
&& err
.length () > 0)
436 ACELIB_DEBUG ((LM_DEBUG
,
437 ACE_TEXT ("ACE (%P|%t) DLL_Handle::open_i ")
438 ACE_TEXT ("<%s>, 0x%x) -> <%s>: <%s>\n"),
441 ((this->handle_
!= ACE_SHLIB_INVALID_HANDLE
)
442 ? ACE_TEXT ("succeeded")
443 : ACE_TEXT ("failed")),
448 return this->handle_
!= ACE_SHLIB_INVALID_HANDLE
;
451 /******************************************************************/
453 // Pointer to the Singleton instance.
454 ACE_DLL_Manager
*ACE_DLL_Manager::instance_
= 0;
458 ACE_DLL_Manager::instance (int size
)
460 ACE_TRACE ("ACE_DLL_Manager::instance");
462 if (ACE_DLL_Manager::instance_
== 0)
464 // Perform Double-Checked Locking Optimization.
465 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex
, ace_mon
,
466 *ACE_Static_Object_Lock::instance (), 0));
467 if (ACE_DLL_Manager::instance_
== 0)
469 ACE_NEW_RETURN (ACE_DLL_Manager::instance_
,
470 ACE_DLL_Manager (size
),
475 return ACE_DLL_Manager::instance_
;
479 ACE_DLL_Manager::close_singleton ()
481 ACE_TRACE ("ACE_DLL_Manager::close_singleton");
483 ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex
, ace_mon
,
484 *ACE_Static_Object_Lock::instance ()));
486 delete ACE_DLL_Manager::instance_
;
487 ACE_DLL_Manager::instance_
= 0;
490 ACE_DLL_Manager::ACE_DLL_Manager (int size
)
491 : handle_vector_ (0),
494 unload_policy_ (ACE_DLL_UNLOAD_POLICY_PER_DLL
)
496 ACE_TRACE ("ACE_DLL_Manager::ACE_DLL_Manager");
498 if (this->open (size
) != 0 && ACE::debug ())
499 ACELIB_ERROR ((LM_ERROR
,
500 ACE_TEXT ("ACE (%P|%t) DLL_Manager ctor failed to allocate ")
501 ACE_TEXT ("handle_vector_.\n")));
504 ACE_DLL_Manager::~ACE_DLL_Manager ()
506 ACE_TRACE ("ACE_DLL_Manager::~ACE_DLL_Manager");
508 if (this->close () != 0 && ACE::debug ())
509 ACELIB_ERROR ((LM_ERROR
,
510 ACE_TEXT ("ACE (%P|%t) DLL_Manager dtor failed to close ")
511 ACE_TEXT ("properly.\n")));
514 ACE_ALLOC_HOOK_DEFINE(ACE_DLL_Manager
)
517 ACE_DLL_Manager::open_dll (const ACE_TCHAR
*dll_name
,
519 ACE_SHLIB_HANDLE handle
,
520 ACE_DLL_Handle::ERROR_STACK
*errors
)
522 ACE_TRACE ("ACE_DLL_Manager::open_dll");
524 ACE_DLL_Handle
*temp_handle
= 0;
525 ACE_DLL_Handle
*dll_handle
= 0;
527 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, 0));
528 dll_handle
= this->find_dll (dll_name
);
531 if (this->current_size_
< this->total_size_
)
533 ACE_NEW_RETURN (temp_handle
,
537 dll_handle
= temp_handle
;
544 if (dll_handle
->open (dll_name
, open_mode
, handle
, errors
) != 0)
546 // Error while opening dll. Free temp handle
548 ACELIB_ERROR ((LM_ERROR
,
549 ACE_TEXT ("ACE (%P|%t) DLL_Manager::open_dll: Could not ")
550 ACE_TEXT ("open dll <%s>\n"),
557 // Add the handle to the vector only if the dll is successfully
559 if (temp_handle
!= 0)
561 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, 0));
562 this->handle_vector_
[this->current_size_
] = dll_handle
;
563 ++this->current_size_
;
571 ACE_DLL_Manager::close_dll (const ACE_TCHAR
*dll_name
)
573 ACE_TRACE ("ACE_DLL_Manager::close_dll");
574 ACE_DLL_Handle
*handle
= 0;
577 ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, 0));
578 handle
= this->find_dll (dll_name
);
583 return this->unload_dll (handle
, 0);
590 ACE_DLL_Manager::unload_policy () const
592 ACE_TRACE ("ACE_DLL_Manager::unload_policy");
593 return this->unload_policy_
;
597 ACE_DLL_Manager::unload_policy (u_long unload_policy
)
599 ACE_TRACE ("ACE_DLL_Manager::unload_policy");
600 ACE_MT (ACE_GUARD (ACE_Thread_Mutex
, ace_mon
, this->lock_
));
602 u_long old_policy
= this->unload_policy_
;
603 this->unload_policy_
= unload_policy
;
605 // If going from LAZY to EAGER or from PER_DLL to PER_PROCESS|EAGER,
606 // call close(1) on all the ACE_DLL_Handle objects with refcount == 0
607 // which will force those that are still loaded to be unloaded.
608 if (this->handle_vector_
)
609 if (( ACE_BIT_ENABLED (old_policy
, ACE_DLL_UNLOAD_POLICY_LAZY
) &&
610 ACE_BIT_DISABLED (this->unload_policy_
, ACE_DLL_UNLOAD_POLICY_LAZY
) ) ||
611 ( ACE_BIT_DISABLED (this->unload_policy_
, ACE_DLL_UNLOAD_POLICY_LAZY
) &&
612 ACE_BIT_ENABLED (old_policy
, ACE_DLL_UNLOAD_POLICY_PER_DLL
) &&
613 ACE_BIT_DISABLED (this->unload_policy_
, ACE_DLL_UNLOAD_POLICY_PER_DLL
) ))
615 for (int i
= this->current_size_
- 1; i
>= 0; i
--)
617 if (this->handle_vector_
[i
] &&
618 this->handle_vector_
[i
]->refcount () == 0)
619 this->handle_vector_
[i
]->close (1);
625 ACE_DLL_Manager::open (int size
)
627 ACE_TRACE ("ACE_DLL_Manager::open");
629 ACE_DLL_Handle
**temp
= 0;
631 #if defined (ACE_HAS_ALLOC_HOOKS)
632 ACE_ALLOCATOR_RETURN (temp
,
633 static_cast<ACE_DLL_Handle
**> (ACE_Allocator::instance()->malloc(sizeof (ACE_DLL_Handle
*) * size
)),
636 ACE_NEW_RETURN (temp
,
637 ACE_DLL_Handle
*[size
],
639 #endif /* ACE_HAS_ALLOC_HOOKS */
641 this->handle_vector_
= temp
;
642 this->total_size_
= size
;
647 ACE_DLL_Manager::close ()
649 ACE_TRACE ("ACE_DLL_Manager::close");
653 if (this->handle_vector_
!= 0)
655 // Delete components in reverse order.
656 for (int i
= this->current_size_
- 1; i
>= 0; i
--)
658 if (this->handle_vector_
[i
])
661 const_cast<ACE_DLL_Handle
*> (this->handle_vector_
[i
]);
662 this->handle_vector_
[i
] = 0;
663 this->unload_dll (s
, force_close
);
668 #if defined (ACE_HAS_ALLOC_HOOKS)
669 ACE_Allocator::instance()->free(this->handle_vector_
);
671 delete [] this->handle_vector_
;
672 #endif /* ACE_HAS_ALLOC_HOOKS */
674 this->handle_vector_
= 0;
675 this->current_size_
= 0;
681 ACE_DLL_Manager::find_dll (const ACE_TCHAR
*dll_name
) const
683 ACE_TRACE ("ACE_DLL_Manager::find_dll");
685 for (int i
= 0; i
< this->current_size_
; i
++)
686 if (this->handle_vector_
[i
] &&
687 ACE_OS::strcmp (this->handle_vector_
[i
]->dll_name (), dll_name
) == 0)
689 return this->handle_vector_
[i
];
696 ACE_DLL_Manager::unload_dll (ACE_DLL_Handle
*dll_handle
, int force_unload
)
698 ACE_TRACE ("ACE_DLL_Manager::unload_dll");
702 int unload
= force_unload
;
706 if (ACE_BIT_DISABLED (this->unload_policy_
,
707 ACE_DLL_UNLOAD_POLICY_PER_DLL
))
709 unload
= ACE_BIT_DISABLED (this->unload_policy_
,
710 ACE_DLL_UNLOAD_POLICY_LAZY
);
714 // Declare the type of the symbol:
715 using dll_unload_policy
= int (*)();
717 void * const unload_policy_ptr
=
718 dll_handle
->symbol (ACE_TEXT ("_get_dll_unload_policy"), 1);
719 intptr_t const temp_p
= reinterpret_cast<intptr_t> (unload_policy_ptr
);
721 dll_unload_policy
const the_policy
=
722 reinterpret_cast<dll_unload_policy
> (temp_p
);
725 unload
= ACE_BIT_DISABLED (the_policy (),
726 ACE_DLL_UNLOAD_POLICY_LAZY
);
728 unload
= ACE_BIT_DISABLED (this->unload_policy_
,
729 ACE_DLL_UNLOAD_POLICY_LAZY
);
733 if (dll_handle
->close (unload
) != 0)
736 ACELIB_ERROR ((LM_ERROR
,
737 ACE_TEXT ("ACE (%P|%t) DLL_Manager::unload error.\n")));
745 ACELIB_ERROR ((LM_ERROR
,
746 ACE_TEXT ("ACE (%P|%t) DLL_Manager::unload_dll called with ")
747 ACE_TEXT ("null pointer.\n")));
755 ACE_END_VERSIONED_NAMESPACE_DECL