-
Notifications
You must be signed in to change notification settings - Fork 270
/
Copy pathdynfunction.cpp
148 lines (129 loc) · 3.29 KB
/
dynfunction.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//========= 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;
}