source-engine/tier0/dynfunction.cpp

149 lines
3.3 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared library loading and symbol lookup.
//
// $NoKeywords: $
//=============================================================================//
#include "pch_tier0.h"
#include "tier0/dynfunction.h"
#if defined(WIN32)
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
#if 1
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;
}