latebindingsymboltable_linux.h (5890B)
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 <cstddef> 15 16 #include "absl/strings/string_view.h" 17 #include "rtc_base/checks.h" 18 19 // This file provides macros for creating "symbol table" classes to simplify the 20 // dynamic loading of symbols from DLLs. Currently the implementation only 21 // supports Linux and pure C symbols. 22 // See talk/sound/pulseaudiosymboltable.(h|cc) for an example. 23 24 namespace webrtc { 25 namespace adm_linux { 26 27 #ifdef WEBRTC_LINUX 28 typedef void* DllHandle; 29 30 const DllHandle kInvalidDllHandle = NULL; 31 #else 32 #error Not implemented 33 #endif 34 35 // These are helpers for use only by the class below. 36 DllHandle InternalLoadDll(absl::string_view); 37 38 void InternalUnloadDll(DllHandle handle); 39 40 bool InternalLoadSymbols(DllHandle handle, 41 int num_symbols, 42 const char* const symbol_names[], 43 void* symbols[]); 44 45 template <int SYMBOL_TABLE_SIZE, 46 const char kDllName[], 47 const char* const kSymbolNames[]> 48 class LateBindingSymbolTable { 49 public: 50 LateBindingSymbolTable() 51 : handle_(kInvalidDllHandle), undefined_symbols_(false) { 52 memset(symbols_, 0, sizeof(symbols_)); 53 } 54 55 ~LateBindingSymbolTable() { Unload(); } 56 57 LateBindingSymbolTable(const LateBindingSymbolTable&) = delete; 58 LateBindingSymbolTable& operator=(LateBindingSymbolTable&) = delete; 59 60 static int NumSymbols() { return SYMBOL_TABLE_SIZE; } 61 62 // We do not use this, but we offer it for theoretical convenience. 63 static const char* GetSymbolName(int index) { 64 RTC_DCHECK_LT(index, NumSymbols()); 65 return kSymbolNames[index]; 66 } 67 68 bool IsLoaded() const { return handle_ != kInvalidDllHandle; } 69 70 // Loads the DLL and the symbol table. Returns true iff the DLL and symbol 71 // table loaded successfully. 72 bool Load() { 73 if (IsLoaded()) { 74 return true; 75 } 76 if (undefined_symbols_) { 77 // We do not attempt to load again because repeated attempts are not 78 // likely to succeed and DLL loading is costly. 79 return false; 80 } 81 handle_ = InternalLoadDll(kDllName); 82 if (!IsLoaded()) { 83 return false; 84 } 85 if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) { 86 undefined_symbols_ = true; 87 Unload(); 88 return false; 89 } 90 return true; 91 } 92 93 void Unload() { 94 if (!IsLoaded()) { 95 return; 96 } 97 InternalUnloadDll(handle_); 98 handle_ = kInvalidDllHandle; 99 memset(symbols_, 0, sizeof(symbols_)); 100 } 101 102 // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below 103 // instead of this. 104 void* GetSymbol(int index) const { 105 RTC_DCHECK(IsLoaded()); 106 RTC_DCHECK_LT(index, NumSymbols()); 107 return symbols_[index]; 108 } 109 110 private: 111 DllHandle handle_; 112 bool undefined_symbols_; 113 void* symbols_[SYMBOL_TABLE_SIZE]; 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_