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: 68 LateBindingSymbolTable() 69 : handle_(kInvalidDllHandle), 70 undefined_symbols_(false) { 71 memset(symbols_, 0, sizeof(symbols_)); 72 } 73 74 ~LateBindingSymbolTable() { 75 Unload(); 76 } 77 78 static int NumSymbols() { 79 return SYMBOL_TABLE_SIZE; 80 } 81 82 // We do not use this, but we offer it for theoretical convenience. 83 static const char *GetSymbolName(int index) { 84 assert(index < NumSymbols()); 85 return kSymbolNames[index]; 86 } 87 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. 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 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. 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