You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
3.3 KiB
148 lines
3.3 KiB
//========= 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; |
|
} |
|
|
|
|