dynamic native providers can now be unloaded safely
authorDavid Anderson <dvander@alliedmods.net>
Mon Mar 12 20:40:30 2007 +0000 (2007-03-12)
changeset 6050b7655d87148
parent 604 f373aaca29db
child 606 12d001779969
dynamic native providers can now be unloaded safely
fixed an api naming typo :(
core/systems/PluginSys.cpp
core/systems/PluginSys.h
public/sourcepawn/sp_vm_api.h
sourcepawn/jit/x86/jit_x86.cpp
sourcepawn/jit/x86/jit_x86.h
     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);