• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 TALK_BASE_LATEBINDINGSYMBOLTABLE_H_
29 #define TALK_BASE_LATEBINDINGSYMBOLTABLE_H_
30 
31 #include <stddef.h>  // for NULL
32 #include <string.h>
33 
34 #include "talk/base/common.h"
35 #include "talk/base/logging.h"
36 
37 // This file provides macros for creating "symbol table" classes to simplify the
38 // dynamic loading of symbols from DLLs. Currently the implementation only
39 // supports Linux and pure C symbols.
40 // See talk/sound/pulseaudiosymboltable.(h|cc) for an example.
41 
42 namespace talk_base {
43 
44 #ifdef LINUX
45 typedef void *DllHandle;
46 
47 const DllHandle kInvalidDllHandle = NULL;
48 #else
49 #error Not implemented
50 #endif
51 
52 // These are helpers for use only by the class below.
53 DllHandle InternalLoadDll(const char dll_name[]);
54 
55 void InternalUnloadDll(DllHandle handle);
56 
57 bool InternalLoadSymbols(DllHandle handle,
58                          int num_symbols,
59                          const char *const symbol_names[],
60                          void *symbols[]);
61 
62 template <int SYMBOL_TABLE_SIZE,
63           const char kDllName[],
64           const char *const kSymbolNames[]>
65 class LateBindingSymbolTable {
66  public:
LateBindingSymbolTable()67   LateBindingSymbolTable()
68       : handle_(kInvalidDllHandle),
69         undefined_symbols_(false) {
70     memset(symbols_, 0, sizeof(symbols_));
71   }
72 
~LateBindingSymbolTable()73   ~LateBindingSymbolTable() {
74     Unload();
75   }
76 
NumSymbols()77   static int NumSymbols() {
78     return SYMBOL_TABLE_SIZE;
79   }
80 
81   // We do not use this, but we offer it for theoretical convenience.
GetSymbolName(int index)82   static const char *GetSymbolName(int index) {
83     ASSERT(index < NumSymbols());
84     return kSymbolNames[index];
85   }
86 
IsLoaded()87   bool IsLoaded() const {
88     return handle_ != kInvalidDllHandle;
89   }
90 
91   // Loads the DLL and the symbol table. Returns true iff the DLL and symbol
92   // table loaded successfully.
Load()93   bool Load() {
94     if (IsLoaded()) {
95       return true;
96     }
97     if (undefined_symbols_) {
98       // We do not attempt to load again because repeated attempts are not
99       // likely to succeed and DLL loading is costly.
100       LOG(LS_ERROR) << "We know there are undefined symbols";
101       return false;
102     }
103     handle_ = InternalLoadDll(kDllName);
104     if (!IsLoaded()) {
105       return false;
106     }
107     if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) {
108       undefined_symbols_ = true;
109       Unload();
110       return false;
111     }
112     return true;
113   }
114 
Unload()115   void Unload() {
116     if (!IsLoaded()) {
117       return;
118     }
119     InternalUnloadDll(handle_);
120     handle_ = kInvalidDllHandle;
121     memset(symbols_, 0, sizeof(symbols_));
122   }
123 
124   // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below
125   // instead of this.
GetSymbol(int index)126   void *GetSymbol(int index) const {
127     ASSERT(IsLoaded());
128     ASSERT(index < NumSymbols());
129     return symbols_[index];
130   }
131 
132  private:
133   DllHandle handle_;
134   bool undefined_symbols_;
135   void *symbols_[SYMBOL_TABLE_SIZE];
136 
137   DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable);
138 };
139 
140 // This macro must be invoked in a header to declare a symbol table class.
141 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) \
142 enum {
143 
144 // This macro must be invoked in the header declaration once for each symbol
145 // (recommended to use an X-Macro to avoid duplication).
146 // This macro defines an enum with names built from the symbols, which
147 // essentially creates a hash table in the compiler from symbol names to their
148 // indices in the symbol table class.
149 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \
150   ClassName##_SYMBOL_TABLE_INDEX_##sym,
151 
152 // This macro completes the header declaration.
153 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \
154   ClassName##_SYMBOL_TABLE_SIZE \
155 }; \
156 \
157 extern const char ClassName##_kDllName[]; \
158 extern const char *const \
159     ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \
160 \
161 typedef ::talk_base::LateBindingSymbolTable<ClassName##_SYMBOL_TABLE_SIZE, \
162                                             ClassName##_kDllName, \
163                                             ClassName##_kSymbolNames> \
164     ClassName;
165 
166 // This macro must be invoked in a .cc file to define a previously-declared
167 // symbol table class.
168 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \
169 const char ClassName##_kDllName[] = dllName; \
170 const char *const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = {
171 
172 // This macro must be invoked in the .cc definition once for each symbol
173 // (recommended to use an X-Macro to avoid duplication).
174 // This would have to use the mangled name if we were to ever support C++
175 // symbols.
176 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) \
177   #sym,
178 
179 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \
180 };
181 
182 // Index of a given symbol in the given symbol table class.
183 #define LATESYM_INDEXOF(ClassName, sym) \
184   (ClassName##_SYMBOL_TABLE_INDEX_##sym)
185 
186 // Returns a reference to the given late-binded symbol, with the correct type.
187 #define LATESYM_GET(ClassName, inst, sym) \
188   (*reinterpret_cast<typeof(&sym)>( \
189       (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym))))
190 
191 }  // namespace talk_base
192 
193 #endif  // TALK_BASE_LATEBINDINGSYMBOLTABLE_H_
194