summaryrefslogtreecommitdiff
path: root/ace/DLL_Manager.h
blob: 856fbe4e861b5400bddfe6b7a7219d2608158182 (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
/* -*- C++ -*- */

//=============================================================================
/**
 *  @file    DLL_Manager.h
 *
 *  $Id$
 *
 *  @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/Auto_Ptr.h"
#include "ace/Containers_T.h"
#include "ace/SStringfwd.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

/**
 * @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:

  /// Default construtor.
  ACE_DLL_Handle (void);

  /// Destructor.
  ~ACE_DLL_Handle (void);

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

  /**
   * 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.
   */
  int open (const ACE_TCHAR *dll_name, 
            int open_mode,
            ACE_SHLIB_HANDLE handle);

  /// 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 (void) const;

  /// 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.
  void *symbol (const ACE_TCHAR *symbol_name, int ignore_errors = 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.
   */
  ACE_SHLIB_HANDLE get_handle (int become_owner = 0);
 
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.
  auto_ptr <ACE_TString> error (void);

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

  // 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 */

  // = Disallow copying and assignment since we don't handle these.
  ACE_UNIMPLEMENTED_FUNC (ACE_DLL_Handle (const ACE_DLL_Handle &))
  ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_DLL_Handle &))

};

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:
  // This if to silence the compiler warnings, even though ACE_Framework_Repository 
  // always uses the instance method.
  friend class ACE_Framework_Repository;

  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);

  /// 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 (void) 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);

protected:
  // 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:
  /// Default constructor.
  ACE_DLL_Manager (int size = ACE_DLL_Manager::DEFAULT_SIZE);

  /// Destructor.
  ~ACE_DLL_Manager (void);

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

  /// 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 */

 // = Disallow copying and assignment since we don't handle these.
  ACE_UNIMPLEMENTED_FUNC (ACE_DLL_Manager (const ACE_DLL_Manager &))
  ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_DLL_Manager &))
};

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