blob: be2803ce796e0d7baa14fce143c720f78045b1d2 [file] [log] [blame]
/*
* Copyright (c) 2010 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H
#define WEBRTC_AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H
#include <assert.h>
#include <stddef.h> // for NULL
#include <string.h>
#include "webrtc/base/constructormagic.h"
#include "webrtc/system_wrappers/include/trace.h"
// This file provides macros for creating "symbol table" classes to simplify the
// dynamic loading of symbols from DLLs. Currently the implementation only
// supports Linux and pure C symbols.
// See talk/sound/pulseaudiosymboltable.(h|cc) for an example.
namespace webrtc_adm_linux {
#ifdef WEBRTC_LINUX
typedef void *DllHandle;
const DllHandle kInvalidDllHandle = NULL;
#else
#error Not implemented
#endif
// These are helpers for use only by the class below.
DllHandle InternalLoadDll(const char dll_name[]);
void InternalUnloadDll(DllHandle handle);
bool InternalLoadSymbols(DllHandle handle,
int num_symbols,
const char *const symbol_names[],
void *symbols[]);
template <int SYMBOL_TABLE_SIZE,
const char kDllName[],
const char *const kSymbolNames[]>
class LateBindingSymbolTable {
public:
LateBindingSymbolTable()
: handle_(kInvalidDllHandle),
undefined_symbols_(false) {
memset(symbols_, 0, sizeof(symbols_));
}
~LateBindingSymbolTable() {
Unload();
}
static int NumSymbols() {
return SYMBOL_TABLE_SIZE;
}
// We do not use this, but we offer it for theoretical convenience.
static const char *GetSymbolName(int index) {
assert(index < NumSymbols());
return kSymbolNames[index];
}
bool IsLoaded() const {
return handle_ != kInvalidDllHandle;
}
// Loads the DLL and the symbol table. Returns true iff the DLL and symbol
// table loaded successfully.
bool Load() {
if (IsLoaded()) {
return true;
}
if (undefined_symbols_) {
// We do not attempt to load again because repeated attempts are not
// likely to succeed and DLL loading is costly.
//WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
// "We know there are undefined symbols");
return false;
}
handle_ = InternalLoadDll(kDllName);
if (!IsLoaded()) {
return false;
}
if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) {
undefined_symbols_ = true;
Unload();
return false;
}
return true;
}
void Unload() {
if (!IsLoaded()) {
return;
}
InternalUnloadDll(handle_);
handle_ = kInvalidDllHandle;
memset(symbols_, 0, sizeof(symbols_));
}
// Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below
// instead of this.
void *GetSymbol(int index) const {
assert(IsLoaded());
assert(index < NumSymbols());
return symbols_[index];
}
private:
DllHandle handle_;
bool undefined_symbols_;
void *symbols_[SYMBOL_TABLE_SIZE];
RTC_DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable);
};
// This macro must be invoked in a header to declare a symbol table class.
#define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) \
enum {
// This macro must be invoked in the header declaration once for each symbol
// (recommended to use an X-Macro to avoid duplication).
// This macro defines an enum with names built from the symbols, which
// essentially creates a hash table in the compiler from symbol names to their
// indices in the symbol table class.
#define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \
ClassName##_SYMBOL_TABLE_INDEX_##sym,
// This macro completes the header declaration.
#define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \
ClassName##_SYMBOL_TABLE_SIZE \
}; \
\
extern const char ClassName##_kDllName[]; \
extern const char *const \
ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \
\
typedef ::webrtc_adm_linux::LateBindingSymbolTable<ClassName##_SYMBOL_TABLE_SIZE, \
ClassName##_kDllName, \
ClassName##_kSymbolNames> \
ClassName;
// This macro must be invoked in a .cc file to define a previously-declared
// symbol table class.
#define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \
const char ClassName##_kDllName[] = dllName; \
const char *const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = {
// This macro must be invoked in the .cc definition once for each symbol
// (recommended to use an X-Macro to avoid duplication).
// This would have to use the mangled name if we were to ever support C++
// symbols.
#define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) \
#sym,
#define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \
};
// Index of a given symbol in the given symbol table class.
#define LATESYM_INDEXOF(ClassName, sym) \
(ClassName##_SYMBOL_TABLE_INDEX_##sym)
// Returns a reference to the given late-binded symbol, with the correct type.
#define LATESYM_GET(ClassName, inst, sym) \
(*reinterpret_cast<typeof(&sym)>( \
(inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym))))
} // namespace webrtc_adm_linux
#endif // WEBRTC_ADM_LATEBINDINGSYMBOLTABLE_LINUX_H