blob: 91d25aa2dc8d951e1e158ebe738408882220f44d [file] [log] [blame]
xians@google.com68efa212011-08-11 12:41:56 +00001/*
2 * libjingle
3 * Copyright 2004--2010, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H
29#define WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H
30
31#include <assert.h>
32#include <stddef.h> // for NULL
33#include <string.h>
34
35#include "constructor_magic.h"
36#include "trace.h"
37
38// This file provides macros for creating "symbol table" classes to simplify the
39// dynamic loading of symbols from DLLs. Currently the implementation only
40// supports Linux and pure C symbols.
41// See talk/sound/pulseaudiosymboltable.(h|cc) for an example.
42
43namespace webrtc_adm_linux {
44
45#ifdef WEBRTC_LINUX
46typedef void *DllHandle;
47
48const DllHandle kInvalidDllHandle = NULL;
49#else
50#error Not implemented
51#endif
52
53// These are helpers for use only by the class below.
54DllHandle InternalLoadDll(const char dll_name[]);
55
56void InternalUnloadDll(DllHandle handle);
57
58bool InternalLoadSymbols(DllHandle handle,
59 int num_symbols,
60 const char *const symbol_names[],
61 void *symbols[]);
62
63template <int SYMBOL_TABLE_SIZE,
64 const char kDllName[],
65 const char *const kSymbolNames[]>
66class LateBindingSymbolTable {
67 public:
68 LateBindingSymbolTable()
69 : handle_(kInvalidDllHandle),
70 undefined_symbols_(false) {
71 memset(symbols_, 0, sizeof(symbols_));
72 }
73
74 ~LateBindingSymbolTable() {
75 Unload();
76 }
77
78 static int NumSymbols() {
79 return SYMBOL_TABLE_SIZE;
80 }
81
82 // We do not use this, but we offer it for theoretical convenience.
83 static const char *GetSymbolName(int index) {
84 assert(index < NumSymbols());
85 return kSymbolNames[index];
86 }
87
88 bool IsLoaded() const {
89 return handle_ != kInvalidDllHandle;
90 }
91
92 // Loads the DLL and the symbol table. Returns true iff the DLL and symbol
93 // table loaded successfully.
94 bool Load() {
95 if (IsLoaded()) {
96 return true;
97 }
98 if (undefined_symbols_) {
99 // We do not attempt to load again because repeated attempts are not
100 // likely to succeed and DLL loading is costly.
101 //WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
102 // "We know there are undefined symbols");
103 return false;
104 }
105 handle_ = InternalLoadDll(kDllName);
106 if (!IsLoaded()) {
107 return false;
108 }
109 if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) {
110 undefined_symbols_ = true;
111 Unload();
112 return false;
113 }
114 return true;
115 }
116
117 void Unload() {
118 if (!IsLoaded()) {
119 return;
120 }
121 InternalUnloadDll(handle_);
122 handle_ = kInvalidDllHandle;
123 memset(symbols_, 0, sizeof(symbols_));
124 }
125
126 // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below
127 // instead of this.
128 void *GetSymbol(int index) const {
129 assert(IsLoaded());
130 assert(index < NumSymbols());
131 return symbols_[index];
132 }
133
134 private:
135 DllHandle handle_;
136 bool undefined_symbols_;
137 void *symbols_[SYMBOL_TABLE_SIZE];
138
139 DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable);
140};
141
142// This macro must be invoked in a header to declare a symbol table class.
143#define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) \
144enum {
145
146// This macro must be invoked in the header declaration once for each symbol
147// (recommended to use an X-Macro to avoid duplication).
148// This macro defines an enum with names built from the symbols, which
149// essentially creates a hash table in the compiler from symbol names to their
150// indices in the symbol table class.
151#define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \
152 ClassName##_SYMBOL_TABLE_INDEX_##sym,
153
154// This macro completes the header declaration.
155#define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \
156 ClassName##_SYMBOL_TABLE_SIZE \
157}; \
158\
159extern const char ClassName##_kDllName[]; \
160extern const char *const \
161 ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \
162\
163typedef ::webrtc_adm_linux::LateBindingSymbolTable<ClassName##_SYMBOL_TABLE_SIZE, \
164 ClassName##_kDllName, \
165 ClassName##_kSymbolNames> \
166 ClassName;
167
168// This macro must be invoked in a .cc file to define a previously-declared
169// symbol table class.
170#define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \
171const char ClassName##_kDllName[] = dllName; \
172const char *const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = {
173
174// This macro must be invoked in the .cc definition once for each symbol
175// (recommended to use an X-Macro to avoid duplication).
176// This would have to use the mangled name if we were to ever support C++
177// symbols.
178#define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) \
179 #sym,
180
181#define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \
182};
183
184// Index of a given symbol in the given symbol table class.
185#define LATESYM_INDEXOF(ClassName, sym) \
186 (ClassName##_SYMBOL_TABLE_INDEX_##sym)
187
188// Returns a reference to the given late-binded symbol, with the correct type.
189#define LATESYM_GET(ClassName, inst, sym) \
190 (*reinterpret_cast<typeof(&sym)>( \
191 (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym))))
192
193} // namespace webrtc_adm_linux
194
195#endif // WEBRTC_ADM_LATEBINDINGSYMBOLTABLE_LINUX_H