• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2010, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifndef WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H
29 #define WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H
30 
31 #include <assert.h>
32 #include <stddef.h>  // for NULL
33 #include <string.h>
34 
35 #include "webrtc/base/constructormagic.h"
36 #include "webrtc/system_wrappers/interface/trace.h"
37 
38 // This file provides macros for creating "symbol table" classes to simplify the
39 // dynamic loading of symbols from DLLs. Currently the implementation only
40 // supports Linux and pure C symbols.
41 // See talk/sound/pulseaudiosymboltable.(h|cc) for an example.
42 
43 namespace webrtc_adm_linux {
44 
45 #ifdef WEBRTC_LINUX
46 typedef void *DllHandle;
47 
48 const DllHandle kInvalidDllHandle = NULL;
49 #else
50 #error Not implemented
51 #endif
52 
53 // These are helpers for use only by the class below.
54 DllHandle InternalLoadDll(const char dll_name[]);
55 
56 void InternalUnloadDll(DllHandle handle);
57 
58 bool InternalLoadSymbols(DllHandle handle,
59                          int num_symbols,
60                          const char *const symbol_names[],
61                          void *symbols[]);
62 
63 template <int SYMBOL_TABLE_SIZE,
64           const char kDllName[],
65           const char *const kSymbolNames[]>
66 class LateBindingSymbolTable {
67  public:
LateBindingSymbolTable()68   LateBindingSymbolTable()
69       : handle_(kInvalidDllHandle),
70         undefined_symbols_(false) {
71     memset(symbols_, 0, sizeof(symbols_));
72   }
73 
~LateBindingSymbolTable()74   ~LateBindingSymbolTable() {
75     Unload();
76   }
77 
NumSymbols()78   static int NumSymbols() {
79     return SYMBOL_TABLE_SIZE;
80   }
81 
82   // We do not use this, but we offer it for theoretical convenience.
GetSymbolName(int index)83   static const char *GetSymbolName(int index) {
84     assert(index < NumSymbols());
85     return kSymbolNames[index];
86   }
87 
IsLoaded()88   bool IsLoaded() const {
89     return handle_ != kInvalidDllHandle;
90   }
91 
92   // Loads the DLL and the symbol table. Returns true iff the DLL and symbol
93   // table loaded successfully.
Load()94   bool Load() {
95     if (IsLoaded()) {
96       return true;
97     }
98     if (undefined_symbols_) {
99       // We do not attempt to load again because repeated attempts are not
100       // likely to succeed and DLL loading is costly.
101       //WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
102       //           "We know there are undefined symbols");
103       return false;
104     }
105     handle_ = InternalLoadDll(kDllName);
106     if (!IsLoaded()) {
107       return false;
108     }
109     if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) {
110       undefined_symbols_ = true;
111       Unload();
112       return false;
113     }
114     return true;
115   }
116 
Unload()117   void Unload() {
118     if (!IsLoaded()) {
119       return;
120     }
121     InternalUnloadDll(handle_);
122     handle_ = kInvalidDllHandle;
123     memset(symbols_, 0, sizeof(symbols_));
124   }
125 
126   // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below
127   // instead of this.
GetSymbol(int index)128   void *GetSymbol(int index) const {
129     assert(IsLoaded());
130     assert(index < NumSymbols());
131     return symbols_[index];
132   }
133 
134  private:
135   DllHandle handle_;
136   bool undefined_symbols_;
137   void *symbols_[SYMBOL_TABLE_SIZE];
138 
139   DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable);
140 };
141 
142 // This macro must be invoked in a header to declare a symbol table class.
143 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) \
144 enum {
145 
146 // This macro must be invoked in the header declaration once for each symbol
147 // (recommended to use an X-Macro to avoid duplication).
148 // This macro defines an enum with names built from the symbols, which
149 // essentially creates a hash table in the compiler from symbol names to their
150 // indices in the symbol table class.
151 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \
152   ClassName##_SYMBOL_TABLE_INDEX_##sym,
153 
154 // This macro completes the header declaration.
155 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \
156   ClassName##_SYMBOL_TABLE_SIZE \
157 }; \
158 \
159 extern const char ClassName##_kDllName[]; \
160 extern const char *const \
161     ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \
162 \
163 typedef ::webrtc_adm_linux::LateBindingSymbolTable<ClassName##_SYMBOL_TABLE_SIZE, \
164                                             ClassName##_kDllName, \
165                                             ClassName##_kSymbolNames> \
166     ClassName;
167 
168 // This macro must be invoked in a .cc file to define a previously-declared
169 // symbol table class.
170 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \
171 const char ClassName##_kDllName[] = dllName; \
172 const char *const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = {
173 
174 // This macro must be invoked in the .cc definition once for each symbol
175 // (recommended to use an X-Macro to avoid duplication).
176 // This would have to use the mangled name if we were to ever support C++
177 // symbols.
178 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) \
179   #sym,
180 
181 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \
182 };
183 
184 // Index of a given symbol in the given symbol table class.
185 #define LATESYM_INDEXOF(ClassName, sym) \
186   (ClassName##_SYMBOL_TABLE_INDEX_##sym)
187 
188 // Returns a reference to the given late-binded symbol, with the correct type.
189 #define LATESYM_GET(ClassName, inst, sym) \
190   (*reinterpret_cast<typeof(&sym)>( \
191       (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym))))
192 
193 }  // namespace webrtc_adm_linux
194 
195 #endif  // WEBRTC_ADM_LATEBINDINGSYMBOLTABLE_LINUX_H
196