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 AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H_ 12 #define AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H_ 13 14 #include <assert.h> 15 #include <stddef.h> // for NULL 16 #include <string.h> 17 18 #include "rtc_base/constructormagic.h" 19 20 // This file provides macros for creating "symbol table" classes to simplify the 21 // dynamic loading of symbols from DLLs. Currently the implementation only 22 // supports Linux and pure C symbols. 23 // See talk/sound/pulseaudiosymboltable.(h|cc) for an example. 24 25 namespace webrtc { 26 namespace 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 return false; 85 } 86 handle_ = InternalLoadDll(kDllName); 87 if (!IsLoaded()) { 88 return false; 89 } 90 if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) { 91 undefined_symbols_ = true; 92 Unload(); 93 return false; 94 } 95 return true; 96 } 97 Unload()98 void Unload() { 99 if (!IsLoaded()) { 100 return; 101 } 102 InternalUnloadDll(handle_); 103 handle_ = kInvalidDllHandle; 104 memset(symbols_, 0, sizeof(symbols_)); 105 } 106 107 // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below 108 // instead of this. GetSymbol(int index)109 void *GetSymbol(int index) const { 110 assert(IsLoaded()); 111 assert(index < NumSymbols()); 112 return symbols_[index]; 113 } 114 115 private: 116 DllHandle handle_; 117 bool undefined_symbols_; 118 void *symbols_[SYMBOL_TABLE_SIZE]; 119 120 RTC_DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable); 121 }; 122 123 // This macro must be invoked in a header to declare a symbol table class. 124 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) \ 125 enum { 126 127 // This macro must be invoked in the header declaration once for each symbol 128 // (recommended to use an X-Macro to avoid duplication). 129 // This macro defines an enum with names built from the symbols, which 130 // essentially creates a hash table in the compiler from symbol names to their 131 // indices in the symbol table class. 132 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \ 133 ClassName##_SYMBOL_TABLE_INDEX_##sym, 134 135 // This macro completes the header declaration. 136 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \ 137 ClassName##_SYMBOL_TABLE_SIZE \ 138 } \ 139 ; \ 140 \ 141 extern const char ClassName##_kDllName[]; \ 142 extern const char* const \ 143 ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \ 144 \ 145 typedef ::webrtc::adm_linux::LateBindingSymbolTable< \ 146 ClassName##_SYMBOL_TABLE_SIZE, ClassName##_kDllName, \ 147 ClassName##_kSymbolNames> \ 148 ClassName; 149 150 // This macro must be invoked in a .cc file to define a previously-declared 151 // symbol table class. 152 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \ 153 const char ClassName##_kDllName[] = dllName; \ 154 const char *const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = { 155 156 // This macro must be invoked in the .cc definition once for each symbol 157 // (recommended to use an X-Macro to avoid duplication). 158 // This would have to use the mangled name if we were to ever support C++ 159 // symbols. 160 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) \ 161 #sym, 162 163 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \ 164 }; 165 166 // Index of a given symbol in the given symbol table class. 167 #define LATESYM_INDEXOF(ClassName, sym) \ 168 (ClassName##_SYMBOL_TABLE_INDEX_##sym) 169 170 // Returns a reference to the given late-binded symbol, with the correct type. 171 #define LATESYM_GET(ClassName, inst, sym) \ 172 (*reinterpret_cast<typeof(&sym)>( \ 173 (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym)))) 174 175 } // namespace adm_linux 176 } // namespace webrtc 177 178 #endif // ADM_LATEBINDINGSYMBOLTABLE_LINUX_H_ 179