summaryrefslogtreecommitdiff
path: root/ACE/ace/DLL_Manager.h
blob: 23a4150f20653e7aa72caad5ab80ac871b6a4a78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
// -*- C++ -*-

//=============================================================================
/**
 *  @file    DLL_Manager.h
 *
 *  @author Don Hinton <dhinton@ieee.org>
 */
//=============================================================================

#ifndef ACE_DLL_MANAGER_H
#define ACE_DLL_MANAGER_H
#include /**/ "ace/pre.h"

#include /**/ "ace/ACE_export.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include "ace/Containers_T.h"
#include "ace/SString.h"
#include "ace/os_include/os_dlfcn.h"

#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
#  include "ace/Thread_Mutex.h"
#endif /* ACE_MT_SAFE */

#define ACE_DEFAULT_DLL_MANAGER_SIZE 1024

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

/**
 * @class ACE_DLL_Handle
 *
 * @brief 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.
 */
class ACE_Export ACE_DLL_Handle
{
public:
  /// Error stack. Fixed size should suffice. Ignores any errors exceeding the size.
  typedef ACE_Fixed_Stack <ACE_TString, 10> ERROR_STACK;

  /// Default constructor.
  ACE_DLL_Handle ();

  /// Destructor.
  ~ACE_DLL_Handle ();

  /// Returns the name of the shared library (without prefixes or suffixes).
  const ACE_TCHAR *dll_name () const;

  /**
   * This method opens and dynamically links a library/DLL.
   * @param dll_name  The filename or path of the DLL to load. ACE will
   *        attempt to apply the platform's standard library/DLL prefixes
   *        and suffixes, allowing a simple, unadorned name to be passed
   *        regardless of platform. The set of name transforms is listed
   *        below. A @i decorator is a platform's name designator for a debug
   *        vs release build. For example, on Windows it is usually "d".
   *        @li Prefix + name + decorator + suffix
   *        @li Prefix + name + suffix
   *        @li Name + decorator + suffix
   *        @li Name + suffix
   *        @li Name
   *        Note that the transforms with @i decorator will be avoided if
   *        ACE is built with the @c ACE_DISABLE_DEBUG_DLL_CHECK config macro.
   *
   *        @Note There is another mode for locating library/DLL files that
   *        was used in old versions of ACE. The alternate method builds
   *        more combinations of pathname by combining the names transforms
   *        above with locations listed in the platform's standard "path"
   *        locations (e.g., @c LD_LIBRARY_PATH). It can be enabled by building
   *        ACE with the @c ACE_MUST_HELP_DLOPEN_SEARCH_PATH config macro.
   *        Use of this option is discouraged since it avoids the standard
   *        platform search options and security mechanisms.
   *
   * @param open_mode  Flags to alter the actions taken when loading the DLL.
   *        The possible values are:
   *        @li @c RTLD_LAZY (this the default): loads identifier symbols but
   *            not the symbols for functions, which are loaded dynamically
   *            on demand.
   *        @li @c RTLD_NOW: performs all necessary relocations when
   *            @a dll_name is first loaded
   *        @li @c RTLD_GLOBAL: makes symbols available for relocation
   *            processing of any other DLLs.
   * @param handle If a value other than @c ACE_INVALID_HANDLE is supplied,
   *        this object is assigned the specified handle instead of attempting
   *        to open the specified @a dll_name.
   * @param errors Optional address of an error stack to collect any errors
   *        encountered.
   * @retval -1 On failure
   * @retval 0 On success.
   */
  int open (const ACE_TCHAR *dll_name,
            int open_mode,
            ACE_SHLIB_HANDLE handle,
            ERROR_STACK *errors = 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;
  int close (int unload = 0);

  /// Return the current refcount.
  sig_atomic_t refcount () const;

  /// If @a symbol_name is in the symbol table of the DLL a pointer to
  /// the @a symbol_name is returned.  Otherwise, returns 0.  Set the
  /// @a ignore_errors flag to suppress logging errors if @a 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.
  void *symbol (const ACE_TCHAR *symbol_name, bool ignore_errors = false);

  /// Resolves and returns any error encountered.
  void *symbol (const ACE_TCHAR *symbol_name, bool ignore_errors,
                ACE_TString &error);

  /**
   * Return the handle to the caller.  If @a become_owner is true then
   * caller assumes ownership of the handle so we decrement the retcount.
   */
  ACE_SHLIB_HANDLE get_handle (bool become_owner = false);

  ACE_ALLOC_HOOK_DECLARE;

private:
  /// Returns a string explaining why <symbol> or <open>
  /// failed in @a err.  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.
  ACE_TString& error (ACE_TString& err);

  /// 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 @a try_names.
  void get_dll_names (const ACE_TCHAR *dll_name,
                      ACE_Array<ACE_TString> &try_names);

  /**
   * This method opens and dynamically links a library/DLL.
   * @param dll_name  The filename or path of the DLL to load.
   * @param open_mode  Flags to alter the actions taken when loading the DLL.
   *        The possible values are:
   *        @li @c RTLD_LAZY (this the default): loads identifier symbols but
   *            not the symbols for functions, which are loaded dynamically
   *            on demand.
   *        @li @c RTLD_NOW: performs all necessary relocations when
   *            @a dll_name is first loaded
   *        @li @c RTLD_GLOBAL: makes symbols available for relocation
   *            processing of any other DLLs.
   * @param errors Optional address of an error stack to collect any errors
   *        encountered.
   * @retval false On failure
   * @retval true On success
   */
  bool open_i (const ACE_TCHAR *dll_name, int open_mode, ERROR_STACK* errors);

  ACE_DLL_Handle (const ACE_DLL_Handle &) = delete;
  void operator= (const ACE_DLL_Handle &) = delete;
  ACE_DLL_Handle (ACE_DLL_Handle &&) = delete;
  void operator= (ACE_DLL_Handle &&) = delete;

private:
  /// Keep track of how many ACE_DLL objects have a reference to this
  /// dll.
  sig_atomic_t refcount_;

  /// Name of the shared library.
  ACE_TCHAR *dll_name_;

  /// Handle to the actual library loaded by the OS.
  ACE_SHLIB_HANDLE handle_;

  /// 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().
  static sig_atomic_t open_called_;

#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
  /// Synchronization variable for the MT_SAFE Repository
  ACE_Thread_Mutex lock_;
#endif /* ACE_MT_SAFE */
};

class ACE_Framework_Repository;

/**
 * @class ACE_DLL_Manager
 *
 * @brief This class is a singleton and serves as a factory and
 * repository for instances of ACE_DLL_Handle.
 *
 * This class is a singleton whose lifetime is managed by the
 * ACE_Framework_Repository.  Although it is normally meant to be
 * used directly only by ACE_DLL, applications can call the unload_policy()
 * methods in order get/set the the dll unload policy.  Unload policies include
 * per_process/per-dll and eager/lazy.  Dlls can export set their own policy
 * by using the ACE_DLL_UNLOAD_POLICY macro found in config-all.h.  If a dll
 * choses to set an unload policy, it will be used when the per-dll policy
 * (the default) is in effect.  If the per-dll policy is in effect and a dll
 * has not chosen to set a policy, the current per-process policy will be
 * used.
 *
 * The following policy macros are provided in config-all.h:
 *
 *  ACE_DLL_UNLOAD_POLICY_PER_PROCESS - Per-process policy that unloads dlls
 *  eagerly.
 *
 *  ACE_DLL_UNLOAD_POLICY_PER_DLL - Apply policy on a per-dll basis.  If the
 *  dll doesn't use one of the macros below, the current per-process policy
 *  will be used.
 *
 *  ACE_DLL_UNLOAD_POLICY_LAZY - Don't unload dll when refcount reaches
 *  zero, i.e., wait for either an explicit unload request or program exit.
 *
 *  ACE_DLL_UNLOAD_POLICY_DEFAULT - Default policy allows dlls to control
 *  their own destinies, but will unload those that don't make a choice eagerly.
 */
class ACE_Export ACE_DLL_Manager
{
public:
  friend class ACE_Framework_Repository;
  friend class ACE_Object_Manager;

  enum
  {
    DEFAULT_SIZE = ACE_DEFAULT_DLL_MANAGER_SIZE
  };

  /// Return a unique instance
  static ACE_DLL_Manager *instance (int size = ACE_DLL_Manager::DEFAULT_SIZE);

  /// Factory for ACE_DLL_Handle objects.  If one already exits,
  /// its refcount is incremented.
  ACE_DLL_Handle *open_dll (const ACE_TCHAR *dll_name,
                            int openmode,
                            ACE_SHLIB_HANDLE handle,
                            ACE_DLL_Handle::ERROR_STACK *errors = 0);

  /// Close the underlying dll.  Decrements the refcount.
  int close_dll (const ACE_TCHAR *dll_name);

  /// Returns the current per-process UNLOAD_POLICY.
  u_long unload_policy () const;

  /// Set the per-process UNLOAD_POLICY.  If the policy is changed from
  /// LAZY to EAGER, then it will also unload any dlls with zero
  /// refcounts.
  void unload_policy (u_long unload_policy);

  ACE_ALLOC_HOOK_DECLARE;

protected:
  /// Default constructor.
  ACE_DLL_Manager (int size = ACE_DLL_Manager::DEFAULT_SIZE);

  /// Destructor.
  ~ACE_DLL_Manager (void);

  /// Allocate handle_vector_.
  int open (int size);

  /// Close all open dlls and deallocate memory.
  int close (void);

  /// Find dll in handle_vector_.
  ACE_DLL_Handle *find_dll (const ACE_TCHAR *dll_name) const;

  /// Applies strategy for unloading dll.
  int unload_dll (ACE_DLL_Handle *dll_handle, int force_unload = 0);

private:
  /// Close the singleton instance.
  static void close_singleton (void);

  ACE_DLL_Manager (const ACE_DLL_Manager &) = delete;
  void operator= (const ACE_DLL_Manager &) = delete;
  ACE_DLL_Manager (ACE_DLL_Manager &&) = delete;
  void operator= (ACE_DLL_Manager &&) = delete;

private:
  /// Vector containing all loaded handle objects.
  ACE_DLL_Handle **handle_vector_;

  /// Current number of handles.
  int current_size_;

  /// Maximum number of handles.
  int total_size_;

  /// Unload strategy.
  u_long unload_policy_;

  /// Pointer to a process-wide ACE_DLL_Manager.
  static ACE_DLL_Manager *instance_;

#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
  /// Synchronization variable for the MT_SAFE Repository
  ACE_Thread_Mutex lock_;
#endif /* ACE_MT_SAFE */

};

ACE_END_VERSIONED_NAMESPACE_DECL

#include /**/ "ace/post.h"
#endif /* ACE_DLL_MANAGER_H */