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/constructor_magic.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), undefined_symbols_(false) { 53 memset(symbols_, 0, sizeof(symbols_)); 54 } 55 ~LateBindingSymbolTable()56 ~LateBindingSymbolTable() { Unload(); } 57 NumSymbols()58 static int NumSymbols() { return SYMBOL_TABLE_SIZE; } 59 60 // We do not use this, but we offer it for theoretical convenience. GetSymbolName(int index)61 static const char* GetSymbolName(int index) { 62 assert(index < NumSymbols()); 63 return kSymbolNames[index]; 64 } 65 IsLoaded()66 bool IsLoaded() const { return handle_ != kInvalidDllHandle; } 67 68 // Loads the DLL and the symbol table. Returns true iff the DLL and symbol 69 // table loaded successfully. Load()70 bool Load() { 71 if (IsLoaded()) { 72 return true; 73 } 74 if (undefined_symbols_) { 75 // We do not attempt to load again because repeated attempts are not 76 // likely to succeed and DLL loading is costly. 77 return false; 78 } 79 handle_ = InternalLoadDll(kDllName); 80 if (!IsLoaded()) { 81 return false; 82 } 83 if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) { 84 undefined_symbols_ = true; 85 Unload(); 86 return false; 87 } 88 return true; 89 } 90 Unload()91 void Unload() { 92 if (!IsLoaded()) { 93 return; 94 } 95 InternalUnloadDll(handle_); 96 handle_ = kInvalidDllHandle; 97 memset(symbols_, 0, sizeof(symbols_)); 98 } 99 100 // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below 101 // instead of this. GetSymbol(int index)102 void* GetSymbol(int index) const { 103 assert(IsLoaded()); 104 assert(index < NumSymbols()); 105 return symbols_[index]; 106 } 107 108 private: 109 DllHandle handle_; 110 bool undefined_symbols_; 111 void* symbols_[SYMBOL_TABLE_SIZE]; 112 113 RTC_DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable); 114 }; 115 116 // This macro must be invoked in a header to declare a symbol table class. 117 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) enum { 118 // This macro must be invoked in the header declaration once for each symbol 119 // (recommended to use an X-Macro to avoid duplication). 120 // This macro defines an enum with names built from the symbols, which 121 // essentially creates a hash table in the compiler from symbol names to their 122 // indices in the symbol table class. 123 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \ 124 ClassName##_SYMBOL_TABLE_INDEX_##sym, 125 126 // This macro completes the header declaration. 127 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \ 128 ClassName##_SYMBOL_TABLE_SIZE \ 129 } \ 130 ; \ 131 \ 132 extern const char ClassName##_kDllName[]; \ 133 extern const char* const \ 134 ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \ 135 \ 136 typedef ::webrtc::adm_linux::LateBindingSymbolTable< \ 137 ClassName##_SYMBOL_TABLE_SIZE, ClassName##_kDllName, \ 138 ClassName##_kSymbolNames> \ 139 ClassName; 140 141 // This macro must be invoked in a .cc file to define a previously-declared 142 // symbol table class. 143 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \ 144 const char ClassName##_kDllName[] = dllName; \ 145 const char* const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = { 146 // This macro must be invoked in the .cc definition once for each symbol 147 // (recommended to use an X-Macro to avoid duplication). 148 // This would have to use the mangled name if we were to ever support C++ 149 // symbols. 150 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) #sym, 151 152 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \ 153 } \ 154 ; 155 156 // Index of a given symbol in the given symbol table class. 157 #define LATESYM_INDEXOF(ClassName, sym) (ClassName##_SYMBOL_TABLE_INDEX_##sym) 158 159 // Returns a reference to the given late-binded symbol, with the correct type. 160 #define LATESYM_GET(ClassName, inst, sym) \ 161 (*reinterpret_cast<__typeof__(&sym)>( \ 162 (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym)))) 163 164 } // namespace adm_linux 165 } // namespace webrtc 166 167 #endif // ADM_LATEBINDINGSYMBOLTABLE_LINUX_H_ 168