Home | History | Annotate | Download | only in linux
      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 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 "webrtc/base/constructormagic.h"
     36 #include "webrtc/system_wrappers/interface/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 
     43 namespace webrtc_adm_linux {
     44 
     45 #ifdef WEBRTC_LINUX
     46 typedef void *DllHandle;
     47 
     48 const DllHandle kInvalidDllHandle = NULL;
     49 #else
     50 #error Not implemented
     51 #endif
     52 
     53 // These are helpers for use only by the class below.
     54 DllHandle InternalLoadDll(const char dll_name[]);
     55 
     56 void InternalUnloadDll(DllHandle handle);
     57 
     58 bool InternalLoadSymbols(DllHandle handle,
     59                          int num_symbols,
     60                          const char *const symbol_names[],
     61                          void *symbols[]);
     62 
     63 template <int SYMBOL_TABLE_SIZE,
     64           const char kDllName[],
     65           const char *const kSymbolNames[]>
     66 class 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) \
    144 enum {
    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 \
    159 extern const char ClassName##_kDllName[]; \
    160 extern const char *const \
    161     ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \
    162 \
    163 typedef ::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) \
    171 const char ClassName##_kDllName[] = dllName; \
    172 const 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
    196