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