1.1 --- a/core/systems/PluginSys.cpp Mon Mar 12 20:11:54 2007 +0000
1.2 +++ b/core/systems/PluginSys.cpp Mon Mar 12 20:40:30 2007 +0000
1.3 @@ -41,6 +41,7 @@
1.4 m_handle = 0;
1.5 m_ident = NULL;
1.6 m_pProps = sm_trie_create();
1.7 + m_FakeNativesMissing = false;
1.8 }
1.9
1.10 CPlugin::~CPlugin()
1.11 @@ -219,8 +220,15 @@
1.12
1.13 void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
1.14 {
1.15 + PluginStatus old_status = m_status;
1.16 m_status = status;
1.17
1.18 + if (old_status == Plugin_Running)
1.19 + {
1.20 + /* Tell everyone we're now paused */
1.21 + g_PluginSys._SetPauseState(this, true);
1.22 + }
1.23 +
1.24 va_list ap;
1.25 va_start(ap, error_fmt);
1.26 vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
1.27 @@ -540,6 +548,47 @@
1.28 return m_PhraseFiles.at(index);
1.29 }
1.30
1.31 +void CPlugin::DependencyDropped(CPlugin *pOwner)
1.32 +{
1.33 + if (!m_ctx.ctx)
1.34 + {
1.35 + return;
1.36 + }
1.37 +
1.38 + IPluginContext *pContext = pOwner->GetBaseContext();
1.39 + List<FakeNative *>::iterator iter;
1.40 + FakeNative *pNative;
1.41 + sp_native_t *native;
1.42 + uint32_t idx;
1.43 + unsigned int unbound = 0;
1.44 +
1.45 + for (iter = pOwner->m_fakeNatives.begin();
1.46 + iter != pOwner->m_fakeNatives.end();
1.47 + iter++)
1.48 + {
1.49 + pNative = (*iter);
1.50 + /* Find this native! */
1.51 + if (m_ctx.base->FindNativeByName(pNative->name.c_str(), &idx) != SP_ERROR_NONE)
1.52 + {
1.53 + continue;
1.54 + }
1.55 + /* Unbind it */
1.56 + m_ctx.base->GetNativeByIndex(idx, &native);
1.57 + native->pfn = NULL;
1.58 + native->status = SP_NATIVE_UNBOUND;
1.59 + unbound++;
1.60 + }
1.61 +
1.62 + /* :IDEA: in the future, add native trapping? */
1.63 + if (unbound)
1.64 + {
1.65 + m_FakeNativesMissing = true;
1.66 + SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename());
1.67 + }
1.68 +
1.69 + m_dependsOn.remove(pOwner);
1.70 +}
1.71 +
1.72 /*******************
1.73 * PLUGIN ITERATOR *
1.74 *******************/
1.75 @@ -995,6 +1044,24 @@
1.76 /* Tell this plugin to finish initializing itself */
1.77 pPlugin->Call_OnPluginStart();
1.78
1.79 + /* Now, if we have fake natives, go through all plugins that might need rebinding */
1.80 + if (pPlugin->m_fakeNatives.size())
1.81 + {
1.82 + List<CPlugin *>::iterator pl_iter;
1.83 + CPlugin *pOther;
1.84 + for (pl_iter = m_plugins.begin();
1.85 + pl_iter != m_plugins.end();
1.86 + pl_iter++)
1.87 + {
1.88 + pOther = (*pl_iter);
1.89 + if (pOther->GetStatus() == Plugin_Error
1.90 + && pOther->m_FakeNativesMissing)
1.91 + {
1.92 + TryRefreshNatives(pOther);
1.93 + }
1.94 + }
1.95 + }
1.96 +
1.97 return true;
1.98 }
1.99
1.100 @@ -1015,6 +1082,40 @@
1.101 }
1.102 }
1.103
1.104 +void CPluginManager::TryRefreshNatives(CPlugin *pPlugin)
1.105 +{
1.106 + assert(pPlugin->GetBaseContext() != NULL);
1.107 +
1.108 + AddFakeNativesToPlugin(pPlugin);
1.109 +
1.110 + /* Find any unbound natives
1.111 + * Right now, these are not allowed
1.112 + */
1.113 + IPluginContext *pContext = pPlugin->GetBaseContext();
1.114 + uint32_t num = pContext->GetNativesNum();
1.115 + sp_native_t *native;
1.116 + for (unsigned int i=0; i<num; i++)
1.117 + {
1.118 + if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
1.119 + {
1.120 + break;
1.121 + }
1.122 + if (native->status == SP_NATIVE_UNBOUND)
1.123 + {
1.124 + pPlugin->SetErrorState(Plugin_Error, "Native not found: %s", native->name);
1.125 + return;
1.126 + }
1.127 + }
1.128 +
1.129 + /* If we got here, all natives are okay again! */
1.130 + pPlugin->m_status = Plugin_Running;
1.131 + if ((pPlugin->m_ctx.ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
1.132 + {
1.133 + pPlugin->m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED;
1.134 + _SetPauseState(pPlugin, false);
1.135 + }
1.136 +}
1.137 +
1.138 void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin)
1.139 {
1.140 IPluginContext *pContext = pPlugin->GetBaseContext();
1.141 @@ -1036,7 +1137,19 @@
1.142 native.func = pNative->func;
1.143 if (pContext->BindNative(&native) == SP_ERROR_NONE)
1.144 {
1.145 - /* :TODO: add to dependency list */
1.146 + /* Add us as a dependency, but we're careful not to do this circularly! */
1.147 + if (pNative->ctx != pContext)
1.148 + {
1.149 + CPlugin *pOther = GetPluginByCtx(ctx);
1.150 + if (pOther->m_dependents.find(pPlugin) == pOther->m_dependents.end())
1.151 + {
1.152 + pOther->m_dependents.push_back(pPlugin);
1.153 + }
1.154 + if (pPlugin->m_dependsOn.find(pOther) == pPlugin->m_dependsOn.end())
1.155 + {
1.156 + pPlugin->m_dependsOn.push_back(pOther);
1.157 + }
1.158 + }
1.159 }
1.160 }
1.161 }
1.162 @@ -1051,6 +1164,44 @@
1.163 return false;
1.164 }
1.165
1.166 + /* Remove us from the lookup table and linked list */
1.167 + m_plugins.remove(pPlugin);
1.168 + sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
1.169 +
1.170 + /* Go through all dependent plugins and tell them this plugin is now gone */
1.171 + List<CPlugin *>::iterator pl_iter;
1.172 + CPlugin *pOther;
1.173 + for (pl_iter = pPlugin->m_dependents.begin();
1.174 + pl_iter != pPlugin->m_dependents.end();
1.175 + pl_iter++)
1.176 + {
1.177 + pOther = (*pl_iter);
1.178 + pOther->DependencyDropped(pPlugin);
1.179 + }
1.180 +
1.181 + /* Tell everyone we depend on that we no longer exist */
1.182 + for (pl_iter = pPlugin->m_dependsOn.begin();
1.183 + pl_iter != pPlugin->m_dependsOn.end();
1.184 + pl_iter++)
1.185 + {
1.186 + pOther = (*pl_iter);
1.187 + pOther->m_dependents.remove(pPlugin);
1.188 + }
1.189 +
1.190 + /* Remove all of our native functions */
1.191 + List<FakeNative *>::iterator fn_iter;
1.192 + FakeNative *pNative;
1.193 + for (fn_iter = pPlugin->m_fakeNatives.begin();
1.194 + fn_iter != pPlugin->m_fakeNatives.end();
1.195 + fn_iter++)
1.196 + {
1.197 + pNative = (*fn_iter);
1.198 + m_Natives.remove(pNative);
1.199 + sm_trie_delete(m_pNativeLookup, pNative->name.c_str());
1.200 + g_pVM->DestroyFakeNative(pNative->func);
1.201 + delete pNative;
1.202 + }
1.203 +
1.204 List<IPluginsListener *>::iterator iter;
1.205 IPluginsListener *pListener;
1.206
1.207 @@ -1072,10 +1223,6 @@
1.208 pListener = (*iter);
1.209 pListener->OnPluginDestroyed(pPlugin);
1.210 }
1.211 -
1.212 - /* Remove us from the lookup table and linked list */
1.213 - m_plugins.remove(pPlugin);
1.214 - sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
1.215
1.216 /* Tell the plugin to delete itself */
1.217 delete pPlugin;
1.218 @@ -1570,7 +1717,16 @@
1.219 {
1.220 if (IS_STR_FILLED(info->name))
1.221 {
1.222 - g_RootMenu.ConsolePrint(" Title: %s", info->name);
1.223 + if (IS_STR_FILLED(info->description))
1.224 + {
1.225 + g_RootMenu.ConsolePrint(" Title: %s (%s)", info->name, info->description);
1.226 + } else {
1.227 + g_RootMenu.ConsolePrint(" Title: %s", info->name);
1.228 + }
1.229 + }
1.230 + if (IS_STR_FILLED(info->author))
1.231 + {
1.232 + g_RootMenu.ConsolePrint(" Author: %s", info->author);
1.233 }
1.234 if (IS_STR_FILLED(info->version))
1.235 {
1.236 @@ -1580,20 +1736,13 @@
1.237 {
1.238 g_RootMenu.ConsolePrint(" URL: %s", info->url);
1.239 }
1.240 - if (IS_STR_FILLED(info->author))
1.241 - {
1.242 - g_RootMenu.ConsolePrint(" Author: %s", info->author);
1.243 - }
1.244 - if (IS_STR_FILLED(info->version))
1.245 + if (pl->GetStatus() == Plugin_Error)
1.246 {
1.247 - g_RootMenu.ConsolePrint(" Version: %s", info->version);
1.248 + g_RootMenu.ConsolePrint(" Error: %s", pl->m_errormsg);
1.249 + } else {
1.250 + g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no");
1.251 + g_RootMenu.ConsolePrint(" Running: %s", pl->GetStatus() == Plugin_Running ? "yes" : "no");
1.252 }
1.253 - if (IS_STR_FILLED(info->description))
1.254 - {
1.255 - g_RootMenu.ConsolePrint(" Description: %s", info->description);
1.256 - }
1.257 - g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "yes" : "no");
1.258 - g_RootMenu.ConsolePrint(" Paused: %s", pl->GetStatus() == Plugin_Running ? "no" : "yes");
1.259 } else {
1.260 g_RootMenu.ConsolePrint(" Load error: %s", pl->m_errormsg);
1.261 g_RootMenu.ConsolePrint(" File info: (title \"%s\") (version \"%s\")",
1.262 @@ -1726,5 +1875,8 @@
1.263 m_Natives.push_back(pNative);
1.264 sm_trie_insert(m_pNativeLookup, name,pNative);
1.265
1.266 + CPlugin *pPlugin = GetPluginByCtx(pNative->ctx->GetContext());
1.267 + pPlugin->m_fakeNatives.push_back(pNative);
1.268 +
1.269 return true;
1.270 }
2.1 --- a/core/systems/PluginSys.h Mon Mar 12 20:11:54 2007 +0000
2.2 +++ b/core/systems/PluginSys.h Mon Mar 12 20:40:30 2007 +0000
2.3 @@ -92,6 +92,14 @@
2.4 IVirtualMachine *vm;
2.5 };
2.6
2.7 +struct FakeNative
2.8 +{
2.9 + IPluginContext *ctx;
2.10 + IPluginFunction *call;
2.11 + String name;
2.12 + SPVM_NATIVE_FUNC func;
2.13 +};
2.14 +
2.15 enum LoadRes
2.16 {
2.17 LoadRes_Successful,
2.18 @@ -216,6 +224,7 @@
2.19 protected:
2.20 void UpdateInfo();
2.21 void SetTimeStamp(time_t t);
2.22 + void DependencyDropped(CPlugin *pOwner);
2.23 private:
2.24 ContextPair m_ctx;
2.25 PluginType m_type;
2.26 @@ -230,15 +239,11 @@
2.27 Handle_t m_handle;
2.28 bool m_WasRunning;
2.29 CVector<unsigned int> m_PhraseFiles;
2.30 + List<CPlugin *> m_dependents;
2.31 + List<CPlugin *> m_dependsOn;
2.32 + List<FakeNative *> m_fakeNatives;
2.33 Trie *m_pProps;
2.34 -};
2.35 -
2.36 -struct FakeNative
2.37 -{
2.38 - IPluginContext *ctx;
2.39 - IPluginFunction *call;
2.40 - String name;
2.41 - SPVM_NATIVE_FUNC func;
2.42 + bool m_FakeNativesMissing;
2.43 };
2.44
2.45 class CPluginManager :
2.46 @@ -393,6 +398,7 @@
2.47 bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
2.48 private:
2.49 void AddFakeNativesToPlugin(CPlugin *pPlugin);
2.50 + void TryRefreshNatives(CPlugin *pOther);
2.51 private:
2.52 List<IPluginsListener *> m_listeners;
2.53 List<CPlugin *> m_plugins;
3.1 --- a/public/sourcepawn/sp_vm_api.h Mon Mar 12 20:11:54 2007 +0000
3.2 +++ b/public/sourcepawn/sp_vm_api.h Mon Mar 12 20:40:30 2007 +0000
3.3 @@ -836,7 +836,7 @@
3.4 * @param function Pointer to the fake native created by CreateFakeNative.
3.5 * @noreturn
3.6 */
3.7 - virtual void DestroyFakenative(SPVM_NATIVE_FUNC func) =0;
3.8 + virtual void DestroyFakeNative(SPVM_NATIVE_FUNC func) =0;
3.9 };
3.10 };
3.11
4.1 --- a/sourcepawn/jit/x86/jit_x86.cpp Mon Mar 12 20:11:54 2007 +0000
4.2 +++ b/sourcepawn/jit/x86/jit_x86.cpp Mon Mar 12 20:40:30 2007 +0000
4.3 @@ -2229,7 +2229,7 @@
4.4 return (SPVM_NATIVE_FUNC)jw.outbase;
4.5 }
4.6
4.7 -void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func)
4.8 +void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
4.9 {
4.10 engine->ExecFree((void *)func);
4.11 }
5.1 --- a/sourcepawn/jit/x86/jit_x86.h Mon Mar 12 20:11:54 2007 +0000
5.2 +++ b/sourcepawn/jit/x86/jit_x86.h Mon Mar 12 20:40:30 2007 +0000
5.3 @@ -99,7 +99,7 @@
5.4 const char *GetVersionString();
5.5 const char *GetCPUOptimizations();
5.6 SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
5.7 - void DestroyFakenative(SPVM_NATIVE_FUNC func);
5.8 + void DestroyFakeNative(SPVM_NATIVE_FUNC func);
5.9 };
5.10
5.11 cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);