Home | History | Annotate | Download | only in linux
      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 WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H
     12 #define WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H
     13 
     14 #include <assert.h>
     15 #include <stddef.h>  // for NULL
     16 #include <string.h>
     17 
     18 #include "webrtc/base/constructormagic.h"
     19 #include "webrtc/system_wrappers/include/trace.h"
     20 
     21 // This file provides macros for creating "symbol table" classes to simplify the
     22 // dynamic loading of symbols from DLLs. Currently the implementation only
     23 // supports Linux and pure C symbols.
     24 // See talk/sound/pulseaudiosymboltable.(h|cc) for an example.
     25 
     26 namespace webrtc_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(const char dll_name[]);
     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:
     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.
     84       //WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
     85       //           "We know there are undefined symbols");
     86       return false;
     87     }
     88     handle_ = InternalLoadDll(kDllName);
     89     if (!IsLoaded()) {
     90       return false;
     91     }
     92     if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) {
     93       undefined_symbols_ = true;
     94       Unload();
     95       return false;
     96     }
     97     return true;
     98   }
     99 
    100   void Unload() {
    101     if (!IsLoaded()) {
    102       return;
    103     }
    104     InternalUnloadDll(handle_);
    105     handle_ = kInvalidDllHandle;
    106     memset(symbols_, 0, sizeof(symbols_));
    107   }
    108 
    109   // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below
    110   // instead of this.
    111   void *GetSymbol(int index) const {
    112     assert(IsLoaded());
    113     assert(index < NumSymbols());
    114     return symbols_[index];
    115   }
    116 
    117  private:
    118   DllHandle handle_;
    119   bool undefined_symbols_;
    120   void *symbols_[SYMBOL_TABLE_SIZE];
    121 
    122   RTC_DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable);
    123 };
    124 
    125 // This macro must be invoked in a header to declare a symbol table class.
    126 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) \
    127 enum {
    128 
    129 // This macro must be invoked in the header declaration once for each symbol
    130 // (recommended to use an X-Macro to avoid duplication).
    131 // This macro defines an enum with names built from the symbols, which
    132 // essentially creates a hash table in the compiler from symbol names to their
    133 // indices in the symbol table class.
    134 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \
    135   ClassName##_SYMBOL_TABLE_INDEX_##sym,
    136 
    137 // This macro completes the header declaration.
    138 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \
    139   ClassName##_SYMBOL_TABLE_SIZE \
    140 }; \
    141 \
    142 extern const char ClassName##_kDllName[]; \
    143 extern const char *const \
    144     ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \
    145 \
    146 typedef ::webrtc_adm_linux::LateBindingSymbolTable<ClassName##_SYMBOL_TABLE_SIZE, \
    147                                             ClassName##_kDllName, \
    148                                             ClassName##_kSymbolNames> \
    149     ClassName;
    150 
    151 // This macro must be invoked in a .cc file to define a previously-declared
    152 // symbol table class.
    153 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \
    154 const char ClassName##_kDllName[] = dllName; \
    155 const char *const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = {
    156 
    157 // This macro must be invoked in the .cc definition once for each symbol
    158 // (recommended to use an X-Macro to avoid duplication).
    159 // This would have to use the mangled name if we were to ever support C++
    160 // symbols.
    161 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) \
    162   #sym,
    163 
    164 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \
    165 };
    166 
    167 // Index of a given symbol in the given symbol table class.
    168 #define LATESYM_INDEXOF(ClassName, sym) \
    169   (ClassName##_SYMBOL_TABLE_INDEX_##sym)
    170 
    171 // Returns a reference to the given late-binded symbol, with the correct type.
    172 #define LATESYM_GET(ClassName, inst, sym) \
    173   (*reinterpret_cast<typeof(&sym)>( \
    174       (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym))))
    175 
    176 }  // namespace webrtc_adm_linux
    177 
    178 #endif  // WEBRTC_ADM_LATEBINDINGSYMBOLTABLE_LINUX_H
    179