diff --git a/core/sm_autonatives.cpp b/core/sm_autonatives.cpp index 09fd2881..21522e22 100644 --- a/core/sm_autonatives.cpp +++ b/core/sm_autonatives.cpp @@ -31,8 +31,13 @@ #include "sm_autonatives.h" #include "PluginSys.h" +#include "NativeOwner.h" + +CNativeOwner g_CoreNatives; + +CNativeOwner *g_pCoreNatives = &g_CoreNatives; void CoreNativesToAdd::OnSourceModAllInitialized() { - g_PluginSys.RegisterNativesFromCore(m_NativeList); + g_CoreNatives.AddNatives(m_NativeList); } diff --git a/core/sm_autonatives.h b/core/sm_autonatives.h index c3b0d22b..7545442a 100644 --- a/core/sm_autonatives.h +++ b/core/sm_autonatives.h @@ -50,4 +50,8 @@ public: sp_nativeinfo_t *m_NativeList; }; +class CNativeOwner; + +extern CNativeOwner *g_pCoreNatives; + #endif //_INCLUDE_SOURCEMOD_CORE_AUTONATIVES_H_ diff --git a/core/smn_database.cpp b/core/smn_database.cpp index 5327cb8d..fb903052 100644 --- a/core/smn_database.cpp +++ b/core/smn_database.cpp @@ -333,7 +333,7 @@ static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params) CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); if (pExt) { - g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext())); + g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext())); } return hndl; @@ -391,7 +391,7 @@ static cell_t SQL_TConnect(IPluginContext *pContext, const cell_t *params) CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); if (pExt) { - g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext())); + g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext())); } /* Finally, add to the thread if we can */ @@ -462,7 +462,7 @@ static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params) CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity()); if (pExt) { - g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext())); + g_Extensions.BindChildPlugin(pExt, g_PluginSys.GetPluginByCtx(pContext->GetContext())); } return hndl; diff --git a/core/smn_fakenatives.cpp b/core/smn_fakenatives.cpp index 76f865f3..5e1fd71b 100644 --- a/core/smn_fakenatives.cpp +++ b/core/smn_fakenatives.cpp @@ -113,6 +113,8 @@ cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pD static cell_t CreateNative(IPluginContext *pContext, const cell_t *params) { char *name; + CPlugin *pPlugin; + pContext->LocalToString(params[1], &name); IPluginFunction *pFunction = pContext->GetFunctionById(params[2]); @@ -121,7 +123,9 @@ static cell_t CreateNative(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Function %x is not a valid function", params[2]); } - if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter)) + pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); + + if (!pPlugin->AddFakeNative(pFunction, name, FakeNativeRouter)) { return pContext->ThrowNativeError("Fatal error creating dynamic native!"); } diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 4aea3619..8cf5fbbd 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -190,7 +190,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late } return false; } - } else { + } + else + { /* On version bumps, we should check for older versions as well, if the new version fails. * We can then check the exports to see if any VM versions will be sufficient. */ @@ -240,10 +242,11 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late continue; } /* Refuse any API that we might not be able to deal with. - * Also refuse anything < 3 because we need fake natives. + * Also refuse anything < 3 because we need fake natives. + * Also refuse anything < 7 because we need the new sp_native definition. */ api_version = g_pVM->GetAPIVersion(); - if (api_version < 3 || api_version > SOURCEPAWN_VM_API_VERSION) + if (api_version < 7 || api_version > SOURCEPAWN_VM_API_VERSION) { if (error && maxlength) { diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index 03230ab7..14229452 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -266,43 +266,12 @@ void CExtension::MarkAllLoaded() } } -void CExtension::AddPlugin(IPlugin *pPlugin) +void CExtension::AddPlugin(CPlugin *pPlugin) { /* Unfortunately we have to do this :( */ - if (m_Plugins.find(pPlugin) != m_Plugins.end()) + if (m_Dependents.find(pPlugin) != m_Dependents.end()) { - m_Plugins.push_back(pPlugin); - } -} - -void CExtension::RemovePlugin(IPlugin *pPlugin) -{ - m_Plugins.remove(pPlugin); - - List::iterator iter = m_WeakNatives.begin(); - while (iter != m_WeakNatives.end()) - { - if ((*iter).pl == pPlugin) - { - iter = m_WeakNatives.erase(iter); - } - else - { - iter++; - } - } - - iter = m_ReplacedNatives.begin(); - while (iter != m_ReplacedNatives.end()) - { - if ((*iter).pl == pPlugin) - { - iter = m_ReplacedNatives.erase(iter); - } - else - { - iter++; - } + m_Dependents.push_back(pPlugin); } } @@ -671,7 +640,7 @@ void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface pExt->AddInterface(pInterface); } -void CExtensionManager::BindChildPlugin(IExtension *pParent, IPlugin *pPlugin) +void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin ) { CExtension *pExt = (CExtension *)pParent; @@ -684,7 +653,7 @@ void CExtensionManager::OnPluginDestroyed(IPlugin *plugin) for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) { - (*iter)->RemovePlugin(plugin); + (*iter)->DropRefsTo((CPlugin *)plugin); } } @@ -709,77 +678,6 @@ CExtension *CExtensionManager::FindByOrder(unsigned int num) return NULL; } -void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin) -{ - IPluginContext *pContext = pPlugin->GetBaseContext(); - - List exts; - - uint32_t natives = pContext->GetNativesNum(); - sp_native_t *native; - sm_extnative_t *x_native; - sm_repnative_t *r_native; - for (uint32_t i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE) - { - 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) - { - continue; - } - /* Try and bind it */ - if (pContext->BindNativeToIndex(i, x_native->info->func) != SP_ERROR_NONE) - { - continue; - } - /* See if it's optional */ - if (native->flags & SP_NTVFLAG_OPTIONAL) - { - WeakNative wkn = WeakNative((CPlugin *)pPlugin, i); - x_native->owner->m_WeakNatives.push_back(wkn); - } - else if (exts.find(x_native->owner) == exts.end()) - { - exts.push_back(x_native->owner); - } - } - - List::iterator iter; - for (iter = exts.begin(); iter != exts.end(); iter++) - { - CExtension *pExt = (*iter); - if (pExt->m_Plugins.find(pPlugin) != pExt->m_Plugins.end()) - { - continue; - } - pExt->m_Plugins.push_back(pPlugin); - } -} - bool CExtensionManager::UnloadExtension(IExtension *_pExt) { if (!_pExt) @@ -804,12 +702,12 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) if (pExt->IsLoaded()) { /* Unload any dependent plugins */ - List::iterator p_iter = pExt->m_Plugins.begin(); - while (p_iter != pExt->m_Plugins.end()) + List::iterator p_iter = pExt->m_Dependents.begin(); + while (p_iter != pExt->m_Dependents.end()) { /* We have to manually unlink ourselves here, since we're no longer being managed */ g_PluginSys.UnloadPlugin((*p_iter)); - p_iter = pExt->m_Plugins.erase(p_iter); + p_iter = pExt->m_Dependents.erase(p_iter); } List::iterator s_iter; @@ -820,30 +718,6 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true); } - /* Unbind weak natives */ - List::iterator wkn_iter; - for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++) - { - WeakNative & wkn = (*wkn_iter); - sp_context_t *ctx = wkn.pl->GetContext(); - 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::iterator c_iter; CExtension *pDep; @@ -898,40 +772,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) } /* Unbind our natives from Core */ - List::iterator native_iter; - for (native_iter = pExt->m_Natives.begin(); - native_iter != pExt->m_Natives.end(); - native_iter++) - { - const sp_nativeinfo_t *natives = (*native_iter); - sm_extnative_t *x_native; - for (unsigned int n = 0; - natives[n].name != NULL && natives[n].func != NULL; - n++) - { - x_native = m_ExtNatives.retrieve(natives[n].name); - if (x_native && x_native->owner == pExt) - { - m_ExtNatives.remove(natives[n].name); - } - } - } - - /* Unbind our replacement natives */ - List::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++; - } - } + pExt->DropEverything(); /* Tell it to unload */ pAPI = pExt->GetAPI(); @@ -962,44 +803,6 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt) return true; } -void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives) -{ - CExtension *pExt = (CExtension *)pOwner; - - pExt->m_Natives.push_back(natives); - - for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++) - { - if (m_ExtNatives.retrieve(natives[i].name) != NULL) - { - continue; - } - sm_extnative_t x_native; - x_native.info = &natives[i]; - x_native.owner = pExt; - m_ExtNatives.insert(natives[i].name, x_native); - } -} - -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::iterator iter; @@ -1206,7 +1009,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand } if (!pExt->IsLoaded() - || (!pExt->m_ChildDeps.size() && !pExt->m_Plugins.size())) + || (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size())) { char filename[PLATFORM_MAX_PATH]; snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); @@ -1216,7 +1019,7 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand } else { - List plugins; + List plugins; if (pExt->m_ChildDeps.size()) { g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename()); @@ -1246,9 +1049,9 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand { g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename()); /* Add to plugin unload list */ - List::iterator p_iter; - for (p_iter=pOther->m_Plugins.begin(); - p_iter!=pOther->m_Plugins.end(); + List::iterator p_iter; + for (p_iter=pOther->m_Dependents.begin(); + p_iter!=pOther->m_Dependents.end(); p_iter++) { if (plugins.find((*p_iter)) == plugins.end()) @@ -1260,12 +1063,12 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand } } } - if (pExt->m_Plugins.size()) + if (pExt->m_Dependents.size()) { g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename()); - List::iterator iter; - IPlugin *pPlugin; - for (iter = pExt->m_Plugins.begin(); iter != pExt->m_Plugins.end(); iter++) + List::iterator iter; + CPlugin *pPlugin; + for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++) { pPlugin = (*iter); if (plugins.find(pPlugin) == plugins.end()) diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index ffa79e1d..2f6894a3 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -43,6 +43,7 @@ #include #include #include "PluginSys.h" +#include "NativeOwner.h" using namespace SourceMod; using namespace SourceHook; @@ -55,15 +56,9 @@ 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 +class CExtension : + public IExtension, + public CNativeOwner { friend class CExtensionManager; public: @@ -81,8 +76,7 @@ public: void AddDependency(IfaceInfo *pInfo); void AddChildDependent(CExtension *pOther, SMInterface *iface); void AddInterface(SMInterface *pInterface); - void AddPlugin(IPlugin *pPlugin); - void RemovePlugin(IPlugin *pPlugin); + void AddPlugin(CPlugin *pPlugin); void MarkAllLoaded(); void AddLibrary(const char *library); public: @@ -103,10 +97,6 @@ protected: List m_Deps; /** Dependencies */ List m_ChildDeps; /** Children who might depend on us */ List m_Interfaces; - List m_Plugins; - List m_Natives; - List m_WeakNatives; - List m_ReplacedNatives; List m_Libraries; unsigned int unload_code; bool m_bFullyLoaded; @@ -169,26 +159,25 @@ public: IExtension *LoadAutoExtension(const char *path); void BindDependency(IExtension *pOwner, IfaceInfo *pInfo); void AddInterface(IExtension *pOwner, SMInterface *pInterface); - void BindChildPlugin(IExtension *pParent, IPlugin *pPlugin); - void AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives); - void BindAllNativesToPlugin(IPlugin *pPlugin); + void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin); void MarkAllLoaded(); void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload); void TryAutoload(); void AddLibrary(IExtension *pSource, const char *library); bool LibraryExists(const char *library); - void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives); void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax); public: CExtension *GetExtensionFromIdent(IdentityToken_t *ptr); void Shutdown(); + CNativeOwner *GetNativeOwner(IExtension *pExt) + { + CExtension *p = (CExtension *)pExt; + return p; + } private: CExtension *FindByOrder(unsigned int num); private: List m_Libs; - List m_RepNativeList; - KTrie m_RepNatives; - KTrie m_ExtNatives; }; extern CExtensionManager g_Extensions; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 30b3bf6f..c6177c3c 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -134,10 +134,6 @@ unsigned int CPlugin::CalcMemUsage() unsigned int base_size = sizeof(CPlugin) + sizeof(IdentityToken_t) - + (m_dependents.size() * sizeof(CPlugin *)) - + (m_dependsOn.size() * sizeof(CPlugin *)) - + (m_fakeNatives.size() * (sizeof(FakeNative *) + sizeof(FakeNative))) - + (m_WeakNatives.size() * sizeof(WeakNative)) + (m_configs.size() * (sizeof(AutoConfig *) + sizeof(AutoConfig))) + sm_trie_mem_usage(m_pProps); @@ -161,13 +157,6 @@ unsigned int CPlugin::CalcMemUsage() base_size += (*i).size(); } - for (List::iterator i = m_fakeNatives.begin(); - i != m_fakeNatives.end(); - i++) - { - base_size += (*i)->name.size(); - } - if (m_plugin != NULL) { base_size += sizeof(sp_plugin_t); @@ -740,19 +729,19 @@ void CPlugin::DependencyDropped(CPlugin *pOwner) } } - List::iterator iter; - FakeNative *pNative; + List::iterator iter; + NativeEntry *pNative; sp_native_t *native; uint32_t idx; unsigned int unbound = 0; - for (iter = pOwner->m_fakeNatives.begin(); - iter != pOwner->m_fakeNatives.end(); + for (iter = pOwner->m_Natives.begin(); + iter != pOwner->m_Natives.end(); iter++) { pNative = (*iter); /* Find this native! */ - if (m_ctx.base->FindNativeByName(pNative->name.c_str(), &idx) != SP_ERROR_NONE) + if (m_ctx.base->FindNativeByName(pNative->name, &idx) != SP_ERROR_NONE) { continue; } @@ -773,8 +762,6 @@ void CPlugin::DependencyDropped(CPlugin *pOwner) { SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename()); } - - m_dependsOn.remove(pOwner); } unsigned int CPlugin::GetConfigCount() @@ -814,6 +801,56 @@ void CPlugin::AddConfig(bool autoCreate, const char *cfg, const char *folder) m_configs.push_back(c); } +void CPlugin::DropEverything() +{ + CPlugin *pOther; + List::iterator iter; + List::iterator wk_iter; + + /* Tell everyone that depends on us that we're about to drop */ + for (iter = m_Dependents.begin(); + iter != m_Dependents.end(); + iter++) + { + pOther = (*iter); + pOther->DependencyDropped(this); + } + + /* Note: we don't care about things we depend on. + * The reason is that extensions have their own cleanup + * code for plugins. Although the "right" design would be + * to centralize that here, i'm omitting it for now. Thus, + * the code below to walk the plugins list will suffice. + */ + + /* Other plugins could be holding weak references that were + * added by us. We need to clean all of those up now. + */ + for (iter = g_PluginSys.m_plugins.begin(); + iter != g_PluginSys.m_plugins.end(); + iter++) + { + (*iter)->DropRefsTo(this); + } + + /* Proceed with the rest of the necessities. */ + CNativeOwner::DropEverything(); +} + +bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func) +{ + NativeEntry *pEntry; + + if ((pEntry = g_ShareSys.AddFakeNative(pFunc, name, func)) == NULL) + { + return false; + } + + m_Natives.push_back(pEntry); + + return true; +} + /******************* * PLUGIN ITERATOR * *******************/ @@ -862,8 +899,6 @@ CPluginManager::CPluginManager() m_LoadLookup = sm_trie_create(); m_AllPluginsLoaded = false; m_MyIdent = NULL; - m_pNativeLookup = sm_trie_create(); - m_pCoreNatives = sm_trie_create(); m_LoadingLocked = false; } @@ -875,8 +910,6 @@ CPluginManager::~CPluginManager() * will crash anyway. YAY */ sm_trie_destroy(m_LoadLookup); - sm_trie_destroy(m_pNativeLookup); - sm_trie_destroy(m_pCoreNatives); CStack::iterator iter; for (iter=m_iters.begin(); iter!=m_iters.end(); iter++) @@ -1083,7 +1116,8 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de /* Get the status */ if (pPlugin->GetStatus() == Plugin_Created) { - AddCoreNativesToPlugin(pPlugin); + /* First native pass - add anything from Core */ + g_ShareSys.BindNativesToPlugin(pPlugin, true); pPlugin->InitIdentity(); if (pPlugin->Call_AskPluginLoad(error, maxlength)) { @@ -1409,19 +1443,15 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng return false; } - /* Bind all extra natives */ - g_Extensions.BindAllNativesToPlugin(pPlugin); - if (!FindOrRequirePluginDeps(pPlugin, error, maxlength)) { return false; } - AddFakeNativesToPlugin(pPlugin); + /* Run another binding pass */ + g_ShareSys.BindNativesToPlugin(pPlugin, false); - /* Find any unbound natives - * Right now, these are not allowed - */ + /* Find any unbound natives. Right now, these are not allowed. */ IPluginContext *pContext = pPlugin->GetBaseContext(); uint32_t num = pContext->GetNativesNum(); sp_native_t *native; @@ -1456,7 +1486,7 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng pPlugin->Call_OnPluginStart(); /* Now, if we have fake natives, go through all plugins that might need rebinding */ - if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_fakeNatives.size()) + if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_Natives.size()) { List::iterator pl_iter; CPlugin *pOther; @@ -1471,6 +1501,18 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng { TryRefreshDependencies(pOther); } + else if ((pOther->GetStatus() == Plugin_Running + || pOther->GetStatus() == Plugin_Paused) + && pOther != pPlugin) + { + List::iterator nv_iter; + for (nv_iter = pPlugin->m_Natives.begin(); + nv_iter != pPlugin->m_Natives.end(); + nv_iter++) + { + g_ShareSys.BindNativeToPlugin(pOther, (*nv_iter)); + } + } } } @@ -1489,49 +1531,11 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng return true; } -void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin) -{ - IPluginContext *pContext = pPlugin->GetBaseContext(); - - - uint32_t natives = pContext->GetNativesNum(); - sp_native_t *native; - SPVM_NATIVE_FUNC pfn; - for (uint32_t i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE) - { - continue; - } - if (native->status == SP_NATIVE_BOUND) - { - continue; - } - if (!sm_trie_retrieve(m_pCoreNatives, native->name, (void **)&pfn)) - { - continue; - } - pContext->BindNativeToIndex(i, pfn); - } -} - -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); - AddFakeNativesToPlugin(pPlugin); + g_ShareSys.BindNativesToPlugin(pPlugin, false); List::iterator lib_iter; List::iterator req_iter; @@ -1589,52 +1593,6 @@ void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin) } } -void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin) -{ - IPluginContext *pContext = pPlugin->GetBaseContext(); - sp_nativeinfo_t native; - - List::iterator iter; - FakeNative *pNative; - sp_context_t *ctx; - for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++) - { - pNative = (*iter); - ctx = pNative->ctx->GetContext(); - if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) - { - /* Ignore natives in paused plugins */ - continue; - } - native.name = pNative->name.c_str(); - native.func = pNative->func; - if (pContext->BindNative(&native) == SP_ERROR_NONE) - { - uint32_t idx; - pContext->FindNativeByName(native.name, &idx); - if (pPlugin->GetContext()->natives[idx].flags & SP_NTVFLAG_OPTIONAL) - { - WeakNative wkn(pPlugin, idx); - GetPluginByCtx(ctx)->m_WeakNatives.push_back(wkn); - continue; - } - /* Add us as a dependency, but we're careful not to do this circularly! */ - if (pNative->ctx != pContext) - { - CPlugin *pOther = GetPluginByCtx(ctx); - if (pOther->m_dependents.find(pPlugin) == pOther->m_dependents.end()) - { - pOther->m_dependents.push_back(pPlugin); - } - if (pPlugin->m_dependsOn.find(pOther) == pPlugin->m_dependsOn.end()) - { - pPlugin->m_dependsOn.push_back(pOther); - } - } - } - } -} - bool CPluginManager::UnloadPlugin(IPlugin *plugin) { CPlugin *pPlugin = (CPlugin *)plugin; @@ -1667,44 +1625,6 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) OnLibraryAction((*s_iter).c_str(), true, true); } - /* Go through all dependent plugins and tell them this plugin is now gone */ - List::iterator pl_iter; - CPlugin *pOther; - for (pl_iter = pPlugin->m_dependents.begin(); - pl_iter != pPlugin->m_dependents.end(); - pl_iter++) - { - pOther = (*pl_iter); - pOther->DependencyDropped(pPlugin); - } - - /* Tell everyone we depend on that we no longer exist */ - for (pl_iter = pPlugin->m_dependsOn.begin(); - pl_iter != pPlugin->m_dependsOn.end(); - pl_iter++) - { - pOther = (*pl_iter); - pOther->m_dependents.remove(pPlugin); - } - - /* Remove weak references to us */ - for (pl_iter = m_plugins.begin(); - pl_iter != m_plugins.end(); - pl_iter++) - { - pOther = (*pl_iter); - List::iterator wk_iter = pOther->m_WeakNatives.begin(); - while (wk_iter != pOther->m_WeakNatives.end()) - { - if ((*wk_iter).pl == pPlugin) - { - wk_iter = pOther->m_WeakNatives.erase(wk_iter); - } else { - wk_iter++; - } - } - } - List::iterator iter; IPluginsListener *pListener; @@ -1720,29 +1640,7 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) pPlugin->Call_OnPluginEnd(); } - /* Unbound weak natives */ - List::iterator wk_iter; - for (wk_iter=pPlugin->m_WeakNatives.begin(); wk_iter!=pPlugin->m_WeakNatives.end(); wk_iter++) - { - WeakNative & wkn = (*wk_iter); - sp_context_t *ctx = wkn.pl->GetContext(); - ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND; - wkn.pl->m_FakeNativesMissing = true; - } - - /* Remove all of our native functions */ - List::iterator fn_iter; - FakeNative *pNative; - for (fn_iter = pPlugin->m_fakeNatives.begin(); - fn_iter != pPlugin->m_fakeNatives.end(); - fn_iter++) - { - pNative = (*fn_iter); - m_Natives.remove(pNative); - sm_trie_delete(m_pNativeLookup, pNative->name.c_str()); - g_pVM->DestroyFakeNative(pNative->func); - delete pNative; - } + pPlugin->DropEverything(); for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) { @@ -2050,14 +1948,6 @@ bool CPluginManager::GetHandleApproxSize(HandleType_t type, void *object, unsign return true; } -void CPluginManager::RegisterNativesFromCore(sp_nativeinfo_t *natives) -{ - for (unsigned int i = 0; natives[i].func != NULL; i++) - { - sm_trie_insert(m_pCoreNatives, natives[i].name, (void *)natives[i].func); - } -} - IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err) { IPlugin *pPlugin; @@ -2657,35 +2547,6 @@ void CPluginManager::_SetPauseState(CPlugin *pl, bool paused) } } -bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func) -{ - if (sm_trie_retrieve(m_pNativeLookup, name, NULL)) - { - return false; - } - - FakeNative *pNative = new FakeNative; - - pNative->func = g_pVM->CreateFakeNative(func, pNative); - if (!pNative->func) - { - delete pNative; - return false; - } - - pNative->call = pFunction; - pNative->name.assign(name); - pNative->ctx = pFunction->GetParentContext(); - - m_Natives.push_back(pNative); - sm_trie_insert(m_pNativeLookup, name,pNative); - - CPlugin *pPlugin = GetPluginByCtx(pNative->ctx->GetContext()); - pPlugin->m_fakeNatives.push_back(pNative); - - return true; -} - void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward *pForward) { List::iterator iter; diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index a1aee68a..ff0bca9d 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -54,6 +54,8 @@ #include "convar_sm.h" #endif #include "ITranslator.h" +#include "NativeOwner.h" +#include "ShareSys.h" using namespace SourceHook; @@ -120,14 +122,6 @@ struct ContextPair IVirtualMachine *vm; }; -struct FakeNative -{ - IPluginContext *ctx; - IPluginFunction *call; - String name; - SPVM_NATIVE_FUNC func; -}; - enum LoadRes { LoadRes_Successful, @@ -144,18 +138,10 @@ struct AutoConfig }; class CPlugin; -struct WeakNative -{ - WeakNative(CPlugin *plugin, uint32_t index) - { - pl = plugin; - idx = index; - } - CPlugin *pl; - uint32_t idx; -}; -class CPlugin : public IPlugin +class CPlugin : + public IPlugin, + public CNativeOwner { friend class CPluginManager; friend class CFunction; @@ -177,6 +163,7 @@ public: unsigned int CalcMemUsage(); bool SetProperty(const char *prop, void *ptr); bool GetProperty(const char *prop, void **ptr, bool remove=false); + void DropEverything(); public: /** * Creates a plugin object with default values. @@ -266,6 +253,7 @@ public: Handle_t GetMyHandle(); + bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func); void AddConfig(bool autoCreate, const char *cfg, const char *folder); unsigned int GetConfigCount(); AutoConfig *GetConfig(unsigned int i); @@ -292,10 +280,6 @@ private: Handle_t m_handle; bool m_WasRunning; IPhraseCollection *m_pPhrases; - List m_dependents; - List m_dependsOn; - List m_fakeNatives; - List m_WeakNatives; List m_RequiredLibs; List m_Libraries; Trie *m_pProps; @@ -381,11 +365,6 @@ public: */ bool IsLateLoadTime() const; - /** - * Adds natives from core into the native pool. - */ - void RegisterNativesFromCore(sp_nativeinfo_t *natives); - /** * Converts a Handle to an IPlugin if possible. */ @@ -460,11 +439,6 @@ private: */ bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength); - /** - * Adds any globally registered natives to a plugin - */ - void AddCoreNativesToPlugin(CPlugin *pPlugin); - /** * Runs an extension pass on a plugin. */ @@ -486,11 +460,7 @@ public: { return m_MyIdent; } -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); private: List m_listeners; @@ -500,11 +470,9 @@ private: Trie *m_LoadLookup; bool m_AllPluginsLoaded; IdentityToken_t *m_MyIdent; - Trie *m_pCoreNatives; /* Dynamic native stuff */ List m_Natives; - Trie *m_pNativeLookup; bool m_LoadingLocked; }; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 213a4e2f..391a9c7c 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -33,8 +33,11 @@ #include "HandleSys.h" #include "ExtensionSys.h" #include "LibrarySys.h" +#include "PluginSys.h" +#include "sm_stringutil.h" ShareSystem g_ShareSys; +static unsigned int g_mark_serial = 0; ShareSystem::ShareSystem() { @@ -200,7 +203,11 @@ bool ShareSystem::RequestInterface(const char *iface_name, void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) { - g_Extensions.AddNatives(myself, natives); + CNativeOwner *pOwner; + + pOwner = g_Extensions.GetNativeOwner(myself); + + pOwner->AddNatives(natives); } void ShareSystem::DestroyIdentity(IdentityToken_t *identity) @@ -228,7 +235,9 @@ void ShareSystem::RemoveInterfaces(IExtension *pExtension) if ((*iter).owner == pExtension) { iter = m_Interfaces.erase(iter); - } else { + } + else + { iter++; } } @@ -246,5 +255,261 @@ void ShareSystem::RegisterLibrary(IExtension *myself, const char *name) void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives) { - g_Extensions.OverrideNatives(myself, natives); + unsigned int i; + NativeEntry *pEntry; + CNativeOwner *pOwner; + + pOwner = g_Extensions.GetNativeOwner(myself); + + for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++) + { + if ((pEntry = FindNative(natives[i].name)) == NULL) + { + continue; + } + + if (pEntry->owner != g_pCoreNatives) + { + continue; + } + + if (pEntry->replacement.owner != NULL) + { + continue; + } + + /* Now it's safe to add the override */ + pEntry->replacement.func = natives[i].func; + pEntry->replacement.owner = pOwner; + pOwner->AddReplacedNative(pEntry); + } +} + +NativeEntry *ShareSystem::FindNative(const char *name) +{ + NativeEntry **ppEntry; + + if ((ppEntry = m_NtvCache.retrieve(name)) == NULL) + { + return NULL; + } + + return *ppEntry; +} + +void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly) +{ + NativeEntry *pEntry; + sp_native_t *native; + uint32_t i, native_count; + IPluginContext *pContext; + + pContext = pPlugin->GetBaseContext(); + + /* Generate a new serial ID, mark our dependencies with it. */ + g_mark_serial++; + pPlugin->PropogateMarkSerial(g_mark_serial); + + native_count = pContext->GetNativesNum(); + for (i = 0; i < native_count; i++) + { + if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE) + { + continue; + } + + /* If we're bound, check if there is a replacement available. + * If not, this native is totally finalized. + */ + if (native->status == SP_NATIVE_BOUND) + { + pEntry = (NativeEntry *)native->user; + assert(pEntry != NULL); + if (pEntry->replacement.owner == NULL + || (pEntry->replacement.owner != NULL + && pEntry->replacement.func == native->pfn)) + { + continue; + } + } + /* Otherwise, the native must be in our cache. */ + else if ((pEntry = FindNative(native->name)) == NULL) + { + continue; + } + + if (bCoreOnly && pEntry->owner != g_pCoreNatives) + { + continue; + } + + BindNativeToPlugin(pPlugin, native, i, pEntry); + } +} + +void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry) +{ + uint32_t i; + sp_native_t *native; + IPluginContext *pContext; + + pContext = pPlugin->GetBaseContext(); + + if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE) + { + return; + } + if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE) + { + return; + } + + if (native->status == SP_NATIVE_BOUND) + { + return; + } + + BindNativeToPlugin(pPlugin, native, i, pEntry); +} + +void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, + sp_native_t *native, + uint32_t index, + NativeEntry *pEntry) +{ + /* Mark as bound... we do the rest next. */ + native->status = SP_NATIVE_BOUND; + native->user = pEntry; + + /* See if a replacement is available. */ + if (pEntry->replacement.owner != NULL) + { + /* Perform a replacement bind. */ + native->pfn = pEntry->replacement.func; + pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry)); + } + else + { + /* Perform a normal bind. */ + native->pfn = pEntry->func; + + /* We don't bother with dependency crap if the owner is Core. */ + if (pEntry->owner != g_pCoreNatives) + { + /* The native is optional, this is a special case */ + if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL) + { + pEntry->owner->AddWeakRef(WeakNative(pPlugin, index)); + } + /* Otherwise, we're a strong dependent and not a weak one */ + else + { + /* See if this has already been marked as a dependent. + * If it has, it means this relationship has already occurred, + * and there is no reason to do it again. + */ + if (pEntry->owner != pPlugin + && pEntry->owner->GetMarkSerial() != g_mark_serial) + { + /* This has not been marked as a dependency yet */ + //pPlugin->AddDependency(pEntry->owner); + pEntry->owner->AddDependent(pPlugin); + pEntry->owner->SetMarkSerial(g_mark_serial); + } + } + } + } +} + +NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv) +{ + NativeEntry *pEntry; + + if ((pEntry = FindNative(ntv->name)) == NULL) + { + pEntry = new NativeEntry; + + pEntry->owner = pOwner; + pEntry->name = ntv->name; + pEntry->func = ntv->func; + pEntry->replacement.func = NULL; + pEntry->replacement.owner = NULL; + pEntry->fake = NULL; + + m_NtvCache.insert(ntv->name, pEntry); + + return pEntry; + } + + if (pEntry->owner != NULL) + { + return NULL; + } + + pEntry->owner = pOwner; + pEntry->func = ntv->func; + pEntry->name = ntv->name; + pEntry->func = NULL; + + return pEntry; +} + +void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name) +{ + NativeEntry *pEntry; + + if ((pEntry = FindNative(name)) == NULL) + { + return; + } + + if (pEntry->owner != pOwner) + { + return; + } + + pEntry->func = NULL; + pEntry->name = NULL; + pEntry->owner = NULL; + pEntry->replacement.func = NULL; + pEntry->replacement.owner = NULL; +} + +NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func) +{ + FakeNative *pFake; + NativeEntry *pEntry; + SPVM_NATIVE_FUNC gate; + + if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL) + { + return NULL; + } + + pFake = new FakeNative; + + if ((gate = g_pVM->CreateFakeNative(func, pFake)) == NULL) + { + delete pFake; + return NULL; + } + + if (pEntry == NULL) + { + pEntry = new NativeEntry; + m_NtvCache.insert(name, pEntry); + } + + pFake->call = pFunc; + pFake->ctx = pFunc->GetParentContext(); + strncopy(pFake->name, name, sizeof(pFake->name)); + + pEntry->fake = pFake; + pEntry->func = gate; + pEntry->name = pFake->name; + pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext()); + pEntry->replacement.func = NULL; + pEntry->replacement.owner = NULL; + + return pEntry; } diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index b26b9ea2..ffba6b56 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -35,6 +35,7 @@ #include #include #include +#include #include "sm_globals.h" #include "sourcemod.h" @@ -60,11 +61,38 @@ struct IfaceInfo IExtension *owner; }; +class CNativeOwner; +class CPlugin; +struct NativeEntry; + +struct ReplaceNative +{ + CNativeOwner *owner; + SPVM_NATIVE_FUNC func; +}; + +struct FakeNative +{ + char name[64]; + IPluginContext *ctx; + IPluginFunction *call; +}; + +struct NativeEntry +{ + CNativeOwner *owner; + SPVM_NATIVE_FUNC func; + const char *name; + ReplaceNative replacement; + FakeNative *fake; +}; + class ShareSystem : public IShareSys, public SMGlobalClass, public IHandleTypeDispatch { + friend class CNativeOwner; public: ShareSystem(); public: //IShareSys @@ -96,12 +124,25 @@ public: { return &m_IdentRoot; } +public: + void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly); + void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry); + NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func); +private: + NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv); + void ClearNativeFromCache(CNativeOwner *pOwner, const char *name); + NativeEntry *FindNative(const char *name); + void BindNativeToPlugin(CPlugin *pPlugin, + sp_native_t *ntv, + uint32_t index, + NativeEntry *pEntry); private: List m_Interfaces; HandleType_t m_TypeRoot; IdentityToken_t m_IdentRoot; HandleType_t m_IfaceType; IdentityType_t m_CoreType; + KTrie m_NtvCache; }; extern ShareSystem g_ShareSys; diff --git a/public/IShareSys.h b/public/IShareSys.h index 8c73ab46..e097f6f2 100644 --- a/public/IShareSys.h +++ b/public/IShareSys.h @@ -202,18 +202,16 @@ namespace SourceMod 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. + * @brief Adds natives that will override Core natives when called. * * A Core version of each native must exist. If one does not, then - * Core will simply ignore that entry. + * Core will simply ignore that entry. No more than one override + * can exist on a given native. * * Override natives represent a weak coupling. If the extension is - * unloaded, the native will be re-bound to the Core version. + * unloaded, the native will be re-bound to the Core version. If + * the extension is loaded after plugins are loaded, the override + * will not take effect until those plugins are reloaded. * * @param myself Identity token of parent object. * @param natives Array of natives to add. The last entry in diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 8c780c43..ee9db35a 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -44,7 +44,7 @@ #define SOURCEPAWN_ENGINE_API_VERSION 3 /** SourcePawn VM API Version */ -#define SOURCEPAWN_VM_API_VERSION 6 +#define SOURCEPAWN_VM_API_VERSION 7 #if !defined SOURCEMOD_BUILD #define SOURCEMOD_BUILD @@ -500,22 +500,18 @@ namespace SourcePawn virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; /** - * @brief Binds a list of native names and their function pointers to a context. - * If num is 0, the list is read until an entry with a NULL name is reached. - * If overwrite is non-zero, already registered natives will be overwritten. + * @brief Deprecated; do not use. * - * @param natives Array of natives. - * @param num Number of natives in array. - * @param overwrite Toggles overwrite. + * @param natives Deprecated; do not use. + * @param num Deprecated; do not use. + * @param overwrite Deprecated; do not use. */ virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; /** - * @brief Binds a single native. Overwrites any existing bind. - * If the context does not contain the native that will be binded the function will return - * with a SP_ERROR_NOT_FOUND error. + * @brief Deprecated; do not use. * - * @param native Pointer to native. + * @param native Deprecated; do not use. */ virtual int BindNative(const sp_nativeinfo_t *native) =0; @@ -599,10 +595,10 @@ namespace SourcePawn #endif /** - * @brief Binds a single native to a given native index. + * @brief Deprecated; do not use. * - * @param index Index to bind at. - * @param native Native function to bind. + * @param index Deprecated; do not use. + * @param native Deprecated; do not use. */ virtual int BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC native) =0; diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 165fbcb4..4eb57fd6 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -203,6 +203,7 @@ typedef struct sp_native_s const char * name; /**< Name of function */ uint32_t status; /**< Status flags */ uint32_t flags; /**< Native flags */ + void * user; /**< Host-specific data */ } sp_native_t; /**