added a quick experimental system for overriding core natives

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401695
This commit is contained in:
David Anderson 2007-11-17 04:31:01 +00:00
parent dfa007081b
commit a79a169384
8 changed files with 141 additions and 3 deletions

View File

@ -285,7 +285,22 @@ void CExtension::RemovePlugin(IPlugin *pPlugin)
if ((*iter).pl == pPlugin)
{
iter = m_WeakNatives.erase(iter);
} else {
}
else
{
iter++;
}
}
iter = m_ReplacedNatives.begin();
while (iter != m_ReplacedNatives.end())
{
if ((*iter).pl == pPlugin)
{
iter = m_ReplacedNatives.erase(iter);
}
else
{
iter++;
}
}
@ -703,6 +718,7 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
uint32_t natives = pContext->GetNativesNum();
sp_native_t *native;
sm_extnative_t *x_native;
sm_repnative_t *r_native;
for (uint32_t i=0; i<natives; i++)
{
/* Make sure the native is valid */
@ -710,11 +726,26 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
{
continue;
}
/* Make sure the native is not already bound */
if (native->status == SP_NATIVE_BOUND)
{
/* If it is bound, see if there is a replacement. */
if ((r_native = m_RepNatives.retrieve(native->name)) == NULL)
{
continue;
}
/* Rewrite the address. Whee! */
native->pfn = r_native->info.func;
/* Make sure this will unload safely */
WeakNative wn((CPlugin *)pPlugin, i);
r_native->owner->m_ReplacedNatives.push_back(wn);
continue;
}
/* See if we've got this native in our cache */
if ((x_native = m_ExtNatives.retrieve(native->name)) == NULL)
{
@ -789,7 +820,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
}
/* Unbound weak natives */
/* Unbind weak natives */
List<WeakNative>::iterator wkn_iter;
for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++)
{
@ -798,6 +829,21 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND;
}
/* Unbind replacement natives, link them back to their originals */
for (wkn_iter = pExt->m_ReplacedNatives.begin();
wkn_iter != pExt->m_ReplacedNatives.end();
wkn_iter++)
{
WeakNative & wkn = (*wkn_iter);
sp_context_t *ctx = wkn.pl->GetContext();
sm_repnative_t *r_native = m_RepNatives.retrieve(ctx->natives[wkn.idx].name);
if (r_native == NULL || ctx->natives[wkn.idx].pfn != r_native->info.func)
{
continue;
}
ctx->natives[wkn.idx].pfn = r_native->original;
}
/* Notify and/or unload all dependencies */
List<CExtension *>::iterator c_iter;
CExtension *pDep;
@ -871,6 +917,22 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
}
}
/* Unbind our replacement natives */
List<sm_repnative_t>::iterator rep_iter = m_RepNativeList.begin();
while (rep_iter != m_RepNativeList.end())
{
sm_repnative_t & r_native = (*rep_iter);
if (r_native.owner == pExt)
{
m_RepNatives.remove(r_native.info.name);
rep_iter = m_RepNativeList.erase(rep_iter);
}
else
{
rep_iter++;
}
}
/* Tell it to unload */
pAPI = pExt->GetAPI();
pAPI->OnExtensionUnload();
@ -919,6 +981,25 @@ void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *na
}
}
void CExtensionManager::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
{
SPVM_NATIVE_FUNC orig;
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
{
if ((orig = g_PluginSys.FindCoreNative(natives[i].name)) == NULL)
{
continue;
}
sm_repnative_t rep;
rep.info = natives[i];
rep.owner = (CExtension *)myself;
rep.original = orig;
m_RepNativeList.push_back(rep);
m_RepNatives.insert(natives[i].name, rep);
}
}
void CExtensionManager::MarkAllLoaded()
{
List<CExtension *>::iterator iter;

View File

@ -55,6 +55,14 @@ struct sm_extnative_t
const sp_nativeinfo_t *info;
};
/* Replacement native */
struct sm_repnative_t
{
CExtension *owner;
sp_nativeinfo_t info;
SPVM_NATIVE_FUNC original;
};
class CExtension : public IExtension
{
friend class CExtensionManager;
@ -98,6 +106,7 @@ protected:
List<IPlugin *> m_Plugins;
List<const sp_nativeinfo_t *> m_Natives;
List<WeakNative> m_WeakNatives;
List<WeakNative> m_ReplacedNatives;
List<String> m_Libraries;
unsigned int unload_code;
bool m_bFullyLoaded;
@ -168,6 +177,7 @@ public:
void TryAutoload();
void AddLibrary(IExtension *pSource, const char *library);
bool LibraryExists(const char *library);
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
public:
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
void Shutdown();
@ -175,6 +185,8 @@ private:
CExtension *FindByOrder(unsigned int num);
private:
List<CExtension *> m_Libs;
List<sm_repnative_t> m_RepNativeList;
KTrie<sm_repnative_t> m_RepNatives;
KTrie<sm_extnative_t> m_ExtNatives;
};

View File

@ -1440,6 +1440,18 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
}
}
SPVM_NATIVE_FUNC CPluginManager::FindCoreNative(const char *name)
{
SPVM_NATIVE_FUNC pfn;
if (!sm_trie_retrieve(m_pCoreNatives, name, (void **)&pfn))
{
return NULL;
}
return pfn;
}
void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
{
assert(pPlugin->GetBaseContext() != NULL);

View File

@ -489,6 +489,7 @@ public:
}
public:
bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
SPVM_NATIVE_FUNC FindCoreNative(const char *name);
private:
void AddFakeNativesToPlugin(CPlugin *pPlugin);
void TryRefreshDependencies(CPlugin *pOther);

View File

@ -243,3 +243,8 @@ void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
{
g_Extensions.AddLibrary(myself, name);
}
void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
{
g_Extensions.OverrideNatives(myself, natives);
}

View File

@ -81,6 +81,7 @@ public: //IShareSys
void DestroyIdentity(IdentityToken_t *identity);
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
void RegisterLibrary(IExtension *myself, const char *name);
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
public: //SMGlobalClass
/* Pre-empt in case anything tries to register idents early */
void OnSourceModStartup(bool late);

View File

@ -127,8 +127,11 @@ namespace SourceMod
/**
* @brief Version code of the IExtensionInterface API itself.
*
* Note: This is bumped when IShareSys is changed, because IShareSys
* itself is not versioned.
*/
#define SMINTERFACE_EXTENSIONAPI_VERSION 2
#define SMINTERFACE_EXTENSIONAPI_VERSION 3
/**
* @brief The interface an extension must expose.

View File

@ -200,6 +200,29 @@ namespace SourceMod
* @param name Library name.
*/
virtual void RegisterLibrary(IExtension *myself, const char *name) =0;
/**
* @brief Adds a list of natives to the global native pool, to be
* bound on plugin load.
*
* Unlike AddNatives(), this function implements natives that are
* ALWAYS bound, regardless of whether a previous function is bound.
* That means extensions can override Core natives.
*
* A Core version of each native must exist. If one does not, then
* Core will simply ignore that entry.
*
* Override natives represent a weak coupling. If the extension is
* unloaded, the native will be re-bound to the Core version.
*
* @param myself Identity token of parent object.
* @param natives Array of natives to add. The last entry in
* the array must be filled with NULLs to
* terminate the array. The array must be static
* as Core will cache the pointer for the
* lifetime of the extension.
*/
virtual void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0;
};
}