1 /* 2 * Copyright (c) 2010 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H 12 #define WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H 13 14 #include <assert.h> 15 #include <stddef.h> // for NULL 16 #include <string.h> 17 18 #include "webrtc/base/constructormagic.h" 19 #include "webrtc/system_wrappers/include/trace.h" 20 21 // This file provides macros for creating "symbol table" classes to simplify the 22 // dynamic loading of symbols from DLLs. Currently the implementation only 23 // supports Linux and pure C symbols. 24 // See talk/sound/pulseaudiosymboltable.(h|cc) for an example. 25 26 namespace webrtc_adm_linux { 27 28 #ifdef WEBRTC_LINUX 29 typedef void *DllHandle; 30 31 const DllHandle kInvalidDllHandle = NULL; 32 #else 33 #error Not implemented 34 #endif 35 36 // These are helpers for use only by the class below. 37 DllHandle InternalLoadDll(const char dll_name[]); 38 39 void InternalUnloadDll(DllHandle handle); 40 41 bool InternalLoadSymbols(DllHandle handle, 42 int num_symbols, 43 const char *const symbol_names[], 44 void *symbols[]); 45 46 template <int SYMBOL_TABLE_SIZE, 47 const char kDllName[], 48 const char *const kSymbolNames[]> 49 class LateBindingSymbolTable { 50 public: LateBindingSymbolTable()51 LateBindingSymbolTable() 52 : handle_(kInvalidDllHandle), 53 undefined_symbols_(false) { 54 memset(symbols_, 0, sizeof(symbols_)); 55 } 56 ~LateBindingSymbolTable()57 ~LateBindingSymbolTable() { 58 Unload(); 59 } 60 NumSymbols()61 static int NumSymbols() { 62 return SYMBOL_TABLE_SIZE; 63 } 64 65 // We do not use this, but we offer it for theoretical convenience. GetSymbolName(int index)66 static const char *GetSymbolName(int index) { 67 assert(index < NumSymbols()); 68 return kSymbolNames[index]; 69 } 70 IsLoaded()71 bool IsLoaded() const { 72 return handle_ != kInvalidDllHandle; 73 } 74 75 // Loads the DLL and the symbol table. Returns true iff the DLL and symbol 76 // table loaded successfully. Load()77 bool Load() { 78 if (IsLoaded()) { 79 return true; 80 } 81 if (undefined_symbols_) { 82 // We do not attempt to load again because repeated attempts are not 83 // likely to succeed and DLL loading is costly. 84 //WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1, 85 // "We know there are undefined symbols"); 86 return false; 87 } 88 handle_ = InternalLoadDll(kDllName); 89 if (!IsLoaded()) { 90 return false; 91 } 92 if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) { 93 undefined_symbols_ = true; 94 Unload(); 95 return false; 96 } 97 return true; 98 } 99 Unload()100 void Unload() { 101 if (!IsLoaded()) { 102 return; 103 } 104 InternalUnloadDll(handle_); 105 handle_ = kInvalidDllHandle; 106 memset(symbols_, 0, sizeof(symbols_)); 107 } 108 109 // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below 110 // instead of this. GetSymbol(int index)111 void *GetSymbol(int index) const { 112 assert(IsLoaded()); 113 assert(index < NumSymbols()); 114 return symbols_[index]; 115 } 116 117 private: 118 DllHandle handle_; 119 bool undefined_symbols_; 120 void *symbols_[SYMBOL_TABLE_SIZE]; 121 122 RTC_DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable); 123 }; 124 125 // This macro must be invoked in a header to declare a symbol table class. 126 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) \ 127 enum { 128 129 // This macro must be invoked in the header declaration once for each symbol 130 // (recommended to use an X-Macro to avoid duplication). 131 // This macro defines an enum with names built from the symbols, which 132 // essentially creates a hash table in the compiler from symbol names to their 133 // indices in the symbol table class. 134 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \ 135 ClassName##_SYMBOL_TABLE_INDEX_##sym, 136 137 // This macro completes the header declaration. 138 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \ 139 ClassName##_SYMBOL_TABLE_SIZE \ 140 }; \ 141 \ 142 extern const char ClassName##_kDllName[]; \ 143 extern const char *const \ 144 ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \ 145 \ 146 typedef ::webrtc_adm_linux::LateBindingSymbolTable<ClassName##_SYMBOL_TABLE_SIZE, \ 147 ClassName##_kDllName, \ 148 ClassName##_kSymbolNames> \ 149 ClassName; 150 151 // This macro must be invoked in a .cc file to define a previously-declared 152 // symbol table class. 153 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \ 154 const char ClassName##_kDllName[] = dllName; \ 155 const char *const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = { 156 157 // This macro must be invoked in the .cc definition once for each symbol 158 // (recommended to use an X-Macro to avoid duplication). 159 // This would have to use the mangled name if we were to ever support C++ 160 // symbols. 161 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) \ 162 #sym, 163 164 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \ 165 }; 166 167 // Index of a given symbol in the given symbol table class. 168 #define LATESYM_INDEXOF(ClassName, sym) \ 169 (ClassName##_SYMBOL_TABLE_INDEX_##sym) 170 171 // Returns a reference to the given late-binded symbol, with the correct type. 172 #define LATESYM_GET(ClassName, inst, sym) \ 173 (*reinterpret_cast<typeof(&sym)>( \ 174 (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym)))) 175 176 } // namespace webrtc_adm_linux 177 178 #endif // WEBRTC_ADM_LATEBINDINGSYMBOLTABLE_LINUX_H 179