blob: b834f5c76e432fc2727e1b73e5c2736a50815458 [file] [log] [blame]
xians@google.com68efa212011-08-11 12:41:56 +00001/*
kjellander@webrtc.orga9e363e2014-10-07 12:49:34 +00002 * Copyright (c) 2010 The WebRTC project authors. All Rights Reserved.
xians@google.com68efa212011-08-11 12:41:56 +00003 *
kjellander@webrtc.orga9e363e2014-10-07 12:49:34 +00004 * 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.
xians@google.com68efa212011-08-11 12:41:56 +00009 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#ifndef AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H_
12#define AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H_
xians@google.com68efa212011-08-11 12:41:56 +000013
14#include <assert.h>
15#include <stddef.h> // for NULL
16#include <string.h>
17
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/constructormagic.h"
xians@google.com68efa212011-08-11 12:41:56 +000019
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
kwiberg6daffe22017-04-18 01:26:40 -070025namespace webrtc {
26namespace adm_linux {
xians@google.com68efa212011-08-11 12:41:56 +000027
28#ifdef WEBRTC_LINUX
29typedef void *DllHandle;
30
31const DllHandle kInvalidDllHandle = NULL;
32#else
33#error Not implemented
34#endif
35
36// These are helpers for use only by the class below.
37DllHandle InternalLoadDll(const char dll_name[]);
38
39void InternalUnloadDll(DllHandle handle);
40
41bool InternalLoadSymbols(DllHandle handle,
42 int num_symbols,
43 const char *const symbol_names[],
44 void *symbols[]);
45
46template <int SYMBOL_TABLE_SIZE,
47 const char kDllName[],
48 const char *const kSymbolNames[]>
49class LateBindingSymbolTable {
50 public:
51 LateBindingSymbolTable()
52 : handle_(kInvalidDllHandle),
53 undefined_symbols_(false) {
54 memset(symbols_, 0, sizeof(symbols_));
55 }
56
57 ~LateBindingSymbolTable() {
58 Unload();
59 }
60
61 static int NumSymbols() {
62 return SYMBOL_TABLE_SIZE;
63 }
64
65 // We do not use this, but we offer it for theoretical convenience.
66 static const char *GetSymbolName(int index) {
67 assert(index < NumSymbols());
68 return kSymbolNames[index];
69 }
70
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.
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.
xians@google.com68efa212011-08-11 12:41:56 +000084 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
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.
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
henrikg3c089d72015-09-16 05:37:44 -0700120 RTC_DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable);
xians@google.com68efa212011-08-11 12:41:56 +0000121};
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) \
125enum {
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.
kwiberg6daffe22017-04-18 01:26:40 -0700136#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;
xians@google.com68efa212011-08-11 12:41:56 +0000149
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) \
153const char ClassName##_kDllName[] = dllName; \
154const 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
kwiberg6daffe22017-04-18 01:26:40 -0700175} // namespace adm_linux
176} // namespace webrtc
xians@google.com68efa212011-08-11 12:41:56 +0000177
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200178#endif // ADM_LATEBINDINGSYMBOLTABLE_LINUX_H_