|
|
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared library loading and symbol lookup.
//
// $NoKeywords: $
//=============================================================================//
#include "pch_tier0.h"
#include "tier0/dynfunction.h"
#if defined(WIN32)
#include <windows.h>
typedef HMODULE LibraryHandle; #define LoadLibraryHandle(libname) LoadLibrary(libname)
#define CloseLibraryHandle(handle) FreeLibrary(handle)
#define LookupInLibraryHandle(handle, fn) GetProcAddress(handle, fn)
#elif defined(POSIX)
#include <dlfcn.h>
typedef void *LibraryHandle; #define LoadLibraryHandle(libname) dlopen(libname, RTLD_NOW)
#define CloseLibraryHandle(handle) dlclose(handle)
#define LookupInLibraryHandle(handle, fn) dlsym(handle, fn)
#else
#error Please define your platform.
#endif
#ifndef DEBUG
static inline void dbgdynfn(const char *fmt, ...) {} #else
#define dbgdynfn printf
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
class CSharedLibraryCache { public: static CSharedLibraryCache &GetCache() { static CSharedLibraryCache Singleton; return Singleton; }
struct CSharedLibraryItem { CSharedLibraryItem(LibraryHandle handle, const char *name) { m_handle = handle; m_name = new char[strlen(name) + 1]; m_next = NULL; strcpy(m_name, name); }
~CSharedLibraryItem() { dbgdynfn("CDynamicFunction: Closing library '%s' (%p)\n", m_name, (void *) m_handle); CloseLibraryHandle(m_handle); delete[] m_name; delete m_next; }
char *m_name; CSharedLibraryItem *m_next; LibraryHandle m_handle; };
CSharedLibraryCache() : m_pList(NULL) {} ~CSharedLibraryCache() { CloseAllLibraries(); }
LibraryHandle GetHandle(const char *name) { CSharedLibraryItem *item = GetCacheItem(name); if (item == NULL) { LibraryHandle lib = LoadLibraryHandle(name); dbgdynfn("CDynamicFunction: Loading library '%s' (%p)\n", name, (void *) lib); if (lib == NULL) return NULL;
item = new CSharedLibraryItem(lib, name); item->m_next = m_pList; m_pList = item; } return item->m_handle; }
void CloseLibrary(const char *name) { CSharedLibraryItem *item = GetCacheItem(name); if (item) { assert(item == m_pList); m_pList = item->m_next; item->m_next = NULL; delete item; } }
void CloseAllLibraries() { delete m_pList; }
private: CSharedLibraryItem *GetCacheItem(const char *name) { CSharedLibraryItem *prev = NULL; CSharedLibraryItem *item = m_pList; while (item) { if (strcmp(item->m_name, name) == 0) { // move this item to the front of the list, since there will
// probably be a big pile of these lookups in a row
// and then none ever again.
if (prev != NULL) { prev->m_next = item->m_next; item->m_next = m_pList; m_pList = item; } return item; }
prev = item; item = item->m_next; } return NULL; // not found.
}
CSharedLibraryItem *m_pList; };
void *VoidFnPtrLookup_Tier0(const char *libname, const char *fn, void *fallback) { LibraryHandle lib = CSharedLibraryCache::GetCache().GetHandle(libname); void *retval = NULL; if (lib != NULL) { retval = LookupInLibraryHandle(lib, fn); dbgdynfn("CDynamicFunction: Lookup of '%s' in '%s': %p\n", fn, libname, retval); }
if (retval == NULL) retval = fallback; return retval; }
|