Added extension loading/unloading

Extended SDK for interface sharing
Completed Metamod extension support

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40309
This commit is contained in:
David Anderson
2007-01-17 03:01:38 +00:00
parent b7e10b111f
commit 1857f29efc
11 changed files with 305 additions and 92 deletions
+169 -10
View File
@@ -2,6 +2,7 @@
#include "LibrarySys.h"
#include "ShareSys.h"
#include "CLogger.h"
#include "sourcemm_api.h"
CExtensionManager g_Extensions;
IdentityType_t g_ExtType;
@@ -11,6 +12,7 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
m_File.assign(filename);
m_pAPI = NULL;
m_pIdentToken = NULL;
m_PlId = 0;
char path[PLATFORM_MAX_PATH+1];
g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s/extensions/%s", g_SourceMod.GetSMBaseDir(), filename);
@@ -44,7 +46,8 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
if (m_pAPI->IsMetamodExtension())
{
/* :TODO: STUFF */
bool already;
m_PlId = g_pMMPlugins->Load(path, g_PLID, already, error, err_max);
}
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType);
@@ -53,7 +56,12 @@ CExtension::CExtension(const char *filename, char *error, size_t err_max)
{
if (m_pAPI->IsMetamodExtension())
{
/* :TODO: stuff */
if (m_PlId)
{
char dummy[255];
g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
m_PlId = 0;
}
}
m_pAPI = NULL;
m_pLib->CloseLibrary();
@@ -69,6 +77,10 @@ CExtension::~CExtension()
if (m_pAPI)
{
m_pAPI->OnExtensionUnload();
if (m_PlId)
{
g_pMMPlugins->Unload(m_PlId, true, NULL, 0);
}
}
if (m_pIdentToken)
@@ -107,6 +119,81 @@ bool CExtension::IsLoaded()
return (m_pLib != NULL);
}
void CExtension::AddDependency(IfaceInfo *pInfo)
{
m_Deps.push_back(*pInfo);
}
ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
{
List<IfaceInfo>::iterator iter = m_Deps.begin();
if (iter == m_Deps.end())
{
return NULL;
}
if (pOwner)
{
*pOwner = (*iter).owner;
}
if (pInterface)
{
*pInterface = (*iter).iface;
}
List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
return (ITERATOR *)pIter;
}
bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
{
List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
List<IfaceInfo>::iterator _iter;
if (_iter == m_Deps.end())
{
return false;
}
_iter++;
if (pOwner)
{
*pOwner = (*_iter).owner;
}
if (pInterface)
{
*pInterface = (*_iter).iface;
}
*pIter = _iter;
if (_iter == m_Deps.end())
{
return false;
}
return true;
}
void CExtension::FreeDependencyIterator(ITERATOR *iter)
{
List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
delete pIter;
}
void CExtension::AddInterface(SMInterface *pInterface)
{
m_Interfaces.push_back(pInterface);
}
/*********************
* EXTENSION MANAGER *
*********************/
void CExtensionManager::OnSourceModAllInitialized()
{
g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
@@ -119,6 +206,12 @@ void CExtensionManager::OnSourceModShutdown()
IExtension *CExtensionManager::LoadAutoExtension(const char *path)
{
IExtension *pAlready;
if ((pAlready=FindExtensionByFile(path)) != NULL)
{
return pAlready;
}
char error[256];
CExtension *p = new CExtension(path, error, sizeof(error));
@@ -188,6 +281,12 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t err_max)
{
IExtension *pAlready;
if ((pAlready=FindExtensionByFile(file)) != NULL)
{
return pAlready;
}
CExtension *pExt = new CExtension(file, error, err_max);
/* :NOTE: lifetime is currently ignored */
@@ -203,20 +302,80 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime
return pExt;
}
bool CExtensionManager::UnloadExtension(IExtension *pExt)
void CExtensionManager::BindDependency(IExtension *pOwner, IfaceInfo *pInfo)
{
/* :TODO: implement */
return true;
CExtension *pExt = (CExtension *)pOwner;
pExt->AddDependency(pInfo);
}
unsigned int CExtensionManager::NumberOfPluginDependents(IExtension *pExt, unsigned int *optional)
void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
{
/* :TODO: implement */
return 0;
CExtension *pExt = (CExtension *)pOwner;
pExt->AddInterface(pInterface);
}
bool CExtensionManager::IsExtensionUnloadable(IExtension *pExtension)
bool CExtensionManager::UnloadExtension(IExtension *_pExt)
{
/* :TODO: implement */
if (!_pExt)
{
return false;
}
CExtension *pExt = (CExtension *)_pExt;
if (m_Libs.find(pExt) == m_Libs.end())
{
return false;
}
/* First remove us from internal lists */
g_ShareSys.RemoveInterfaces(_pExt);
m_Libs.remove(pExt);
List<CExtension *> UnloadQueue;
/* Handle dependencies */
if (pExt->IsLoaded())
{
/* Notify and/or unload all dependencies */
List<CExtension *>::iterator c_iter;
CExtension *pDep;
IExtensionInterface *pAPI;
for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++)
{
pDep = (*c_iter);
if ((pAPI=pDep->GetAPI()) == NULL)
{
continue;
}
/* Now, get its dependency list */
bool dropped = false;
List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
while (i_iter != pDep->m_Deps.end())
{
if ((*i_iter).owner == _pExt)
{
if (!dropped && !pAPI->QueryInterfaceDrop((*i_iter).iface))
{
dropped = true;
}
pAPI->NotifyInterfaceDrop((*i_iter).iface);
i_iter = pDep->m_Deps.erase(i_iter);
} else {
i_iter++;
}
}
}
}
List<CExtension *>::iterator iter;
for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++)
{
/* NOTE: This is safe because the unload function backs out of anything not present */
UnloadExtension((*iter));
}
return true;
}
+13 -2
View File
@@ -6,12 +6,15 @@
#include <sh_list.h>
#include <sh_string.h>
#include "sm_globals.h"
#include "ShareSys.h"
#include <ISmmAPI.h>
using namespace SourceMod;
using namespace SourceHook;
class CExtension : public IExtension
{
friend class CExtensionManager;
public:
CExtension(const char *filename, char *error, size_t maxlen);
~CExtension();
@@ -20,14 +23,22 @@ public: //IExtension
const char *GetFilename();
IdentityToken_t *GetIdentity();
bool IsLoaded();
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
void FreeDependencyIterator(ITERATOR *iter);
public:
void SetError(const char *error);
void AddDependency(IfaceInfo *pInfo);
void AddInterface(SMInterface *pInterface);
private:
IdentityToken_t *m_pIdentToken;
IExtensionInterface *m_pAPI;
String m_File;
ILibrary *m_pLib;
String m_Error;
List<IfaceInfo> m_Deps;
List<SMInterface *> m_Interfaces;
PluginId m_PlId;
};
class CExtensionManager :
@@ -42,13 +53,13 @@ public: //IExtensionManager
ExtensionLifetime lifetime,
char *error,
size_t err_max);
unsigned int NumberOfPluginDependents(IExtension *pExt, unsigned int *optional);
bool IsExtensionUnloadable(IExtension *pExtension);
bool UnloadExtension(IExtension *pExt);
IExtension *FindExtensionByFile(const char *file);
IExtension *FindExtensionByName(const char *ext);
public:
IExtension *LoadAutoExtension(const char *path);
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
void AddInterface(IExtension *pOwner, SMInterface *pInterface);
private:
List<CExtension *> m_Libs;
};
+30 -41
View File
@@ -1,5 +1,6 @@
#include "ShareSys.h"
#include "HandleSys.h"
#include "ExtensionSys.h"
ShareSystem g_ShareSys;
@@ -90,7 +91,7 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type)
return pToken;
}
bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token)
bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
{
if (!iface)
{
@@ -99,17 +100,9 @@ bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token)
IfaceInfo info;
info.owner = myself;
info.iface = iface;
info.token = token;
if (token)
{
/* If we're an external object, we have to do this */
info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot(), NULL);
} else {
info.handle = 0;
}
m_Interfaces.push_back(info);
return true;
@@ -117,28 +110,13 @@ bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token)
bool ShareSystem::RequestInterface(const char *iface_name,
unsigned int iface_vers,
IdentityToken_t *token,
IExtension *mysql,
SMInterface **pIface)
{
/* If Some yahoo.... SOME HOOLIGAN... some NO GOOD DIRTY
* HORRIBLE PERSON passed in a token that we don't recognize....
* <b>Punish them.</b>
*/
HandleSecurity sec;
sec.pIdentity = GetIdentRoot();
sec.pOwner = NULL;
if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, &sec, NULL))
{
return false;
}
/* See if the interface exists */
List<IfaceInfo>::iterator iter;
SMInterface *iface;
IdentityToken_t *iface_owner;
Handle_t iface_handle;
IExtension *iface_owner;
bool found = false;
for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
{
@@ -149,8 +127,7 @@ bool ShareSystem::RequestInterface(const char *iface_name,
if (iface->GetInterfaceVersion() == iface_vers
|| iface->IsVersionCompatible(iface_vers))
{
iface_owner = info.token;
iface_handle = info.handle;
iface_owner = info.owner;
found = true;
break;
}
@@ -162,23 +139,21 @@ bool ShareSystem::RequestInterface(const char *iface_name,
return false;
}
/* If something external owns this, we need to track it. */
/* Add a dependency node */
if (iface_owner)
{
Handle_t newhandle;
if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, &sec)
!= HandleError_None)
{
return false;
}
/**
* Now we can deny module loads based on dependencies.
*/
IfaceInfo info;
info.iface = iface;
info.owner = iface_owner;
g_Extensions.BindDependency(iface_owner, &info);
}
/* :TODO: finish */
if (pIface)
{
*pIface = iface;
}
return NULL;
return true;
}
void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[])
@@ -202,3 +177,17 @@ void ShareSystem::DestroyIdentType(IdentityType_t type)
g_HandleSys.RemoveType(type, GetIdentRoot());
}
void ShareSystem::RemoveInterfaces(IExtension *pExtension)
{
List<IfaceInfo>::iterator iter = m_Interfaces.begin();
while (iter != m_Interfaces.end())
{
if ((*iter).owner == pExtension)
{
iter = m_Interfaces.erase(iter);
} else {
iter++;
}
}
}
+4 -4
View File
@@ -20,8 +20,7 @@ namespace SourceMod
struct IfaceInfo
{
SMInterface *iface;
IdentityToken_t *token;
Handle_t handle;
IExtension *owner;
};
class ShareSystem :
@@ -32,10 +31,10 @@ class ShareSystem :
public:
ShareSystem();
public: //IShareSys
bool AddInterface(SMInterface *iface, IdentityToken_t *token);
bool AddInterface(IExtension *myself, SMInterface *pIface);
bool RequestInterface(const char *iface_name,
unsigned int iface_vers,
IdentityToken_t *token,
IExtension *mysql,
SMInterface **pIface);
void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]);
IdentityType_t CreateIdentType(const char *name);
@@ -51,6 +50,7 @@ public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void *object);
public:
IdentityToken_t *CreateCoreIdentity();
void RemoveInterfaces(IExtension *pExtension);
public:
inline IdentityToken_t *GetIdentRoot()
{