Fix various problems with unloading ClientPrefs and SourceMod (bug 5874, r=ds).
authorDavid Anderson <dvander@alliedmods.net>
Thu Aug 22 14:05:44 2013 -0700 (2013-08-22)
changeset 4029cf8bdfcf6503
parent 4028 4b3d32330007
child 4030 eb4df1f7ff3c
Fix various problems with unloading ClientPrefs and SourceMod (bug 5874, r=ds).
core/logic/ExtensionSys.cpp
core/logic/common_logic.cpp
core/logic/intercom.h
core/logic_bridge.cpp
core/sourcemod.cpp
core/sourcemod.h
extensions/clientprefs/cookie.cpp
extensions/clientprefs/cookie.h
extensions/clientprefs/extension.cpp
extensions/clientprefs/extension.h
extensions/clientprefs/query.cpp
extensions/clientprefs/sdk/smsdk_config.h
extensions/clientprefs/sdk/smsdk_ext.cpp
extensions/clientprefs/sdk/smsdk_ext.h
public/IExtensionSys.h
public/sample_ext/sdk/smsdk_ext.cpp
public/sample_ext/sdk/smsdk_ext.h
     1.1 --- a/core/logic/ExtensionSys.cpp	Wed Aug 21 10:55:12 2013 -0400
     1.2 +++ b/core/logic/ExtensionSys.cpp	Thu Aug 22 14:05:44 2013 -0700
     1.3 @@ -775,25 +775,21 @@
     1.4  bool CExtensionManager::UnloadExtension(IExtension *_pExt)
     1.5  {
     1.6  	if (!_pExt)
     1.7 -	{
     1.8  		return false;
     1.9 -	}
    1.10  
    1.11  	CExtension *pExt = (CExtension *)_pExt;
    1.12  
    1.13  	if (m_Libs.find(pExt) == m_Libs.end())
    1.14 -	{
    1.15  		return false;
    1.16 -	}
    1.17  
    1.18  	/* Tell it to unload */
    1.19  	if (pExt->IsLoaded())
    1.20 -	{
    1.21 -		IExtensionInterface *pAPI = pExt->GetAPI();
    1.22 -		pAPI->OnExtensionUnload();
    1.23 -	}
    1.24 +		pExt->GetAPI()->OnExtensionUnload();
    1.25  
    1.26 -	/* First remove us from internal lists */
    1.27 +	// Remove us from internal lists. Note that because we do this, it's
    1.28 +	// possible that our extension could be added back if another plugin
    1.29 +	// tries to load during this process. If we ever find this to happen,
    1.30 +	// we can just block plugin loading.
    1.31  	g_ShareSys.RemoveInterfaces(_pExt);
    1.32  	m_Libs.remove(pExt);
    1.33  
    1.34 @@ -827,13 +823,9 @@
    1.35  		{
    1.36  			pDep = (*c_iter);
    1.37  			if ((pAPI=pDep->GetAPI()) == NULL)
    1.38 -			{
    1.39  				continue;
    1.40 -			}
    1.41  			if (pDep == pExt)
    1.42 -			{
    1.43  				continue;
    1.44 -			}
    1.45  			/* Now, get its dependency list */
    1.46  			bool dropped = false;
    1.47  			List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
    1.48 @@ -862,13 +854,9 @@
    1.49  			while (i_iter != pDep->m_ChildDeps.end())
    1.50  			{
    1.51  				if ((*i_iter).owner == pExt)
    1.52 -				{
    1.53  					i_iter = pDep->m_ChildDeps.erase(i_iter);
    1.54 -				}
    1.55  				else
    1.56 -				{
    1.57  					i_iter++;
    1.58 -				}
    1.59  			}
    1.60  		}
    1.61  
    1.62 @@ -887,6 +875,11 @@
    1.63  		}
    1.64  	}
    1.65  
    1.66 +	// Everything has been informed that we're unloading, so give the
    1.67 +	// extension one last notification.
    1.68 +	if (pExt->IsLoaded() && pExt->GetAPI()->GetExtensionVersion() >= 7)
    1.69 +		pExt->GetAPI()->OnDependenciesDropped();
    1.70 +
    1.71  	pExt->Unload();
    1.72  	delete pExt;
    1.73  
     2.1 --- a/core/logic/common_logic.cpp	Wed Aug 21 10:55:12 2013 -0400
     2.2 +++ b/core/logic/common_logic.cpp	Thu Aug 22 14:05:44 2013 -0700
     2.3 @@ -1,5 +1,5 @@
     2.4  /**
     2.5 - * vim: set ts=4 sw=4 :
     2.6 + * vim: set ts=4 sw=4 tw=99 noet:
     2.7   * =============================================================================
     2.8   * SourceMod
     2.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    2.10 @@ -147,6 +147,7 @@
    2.11  	gamehelpers = core->gamehelpers;
    2.12  	g_pSourcePawn = *core->spe1;
    2.13  	g_pSourcePawn2 = *core->spe2;
    2.14 +	SMGlobalClass::head = core->listeners;
    2.15  
    2.16  	g_ShareSys.Initialize();
    2.17  	g_pCoreIdent = g_ShareSys.CreateCoreIdentity();
     3.1 --- a/core/logic/intercom.h	Wed Aug 21 10:55:12 2013 -0400
     3.2 +++ b/core/logic/intercom.h	Thu Aug 22 14:05:44 2013 -0700
     3.3 @@ -49,7 +49,7 @@
     3.4   * Add 1 to the RHS of this expression to bump the intercom file
     3.5   * This is to prevent mismatching core/logic binaries
     3.6   */
     3.7 -#define SM_LOGIC_MAGIC		(0x0F47C0DE - 22)
     3.8 +#define SM_LOGIC_MAGIC		(0x0F47C0DE - 23)
     3.9  
    3.10  #if defined SM_LOGIC
    3.11  class IVEngineServer
    3.12 @@ -270,6 +270,7 @@
    3.13  	void *          serverFactory;
    3.14  	void *          engineFactory;
    3.15  	void *          matchmakingDSFactory;
    3.16 +	SMGlobalClass *	listeners;
    3.17  };
    3.18  
    3.19  struct sm_logic_t
     4.1 --- a/core/logic_bridge.cpp	Wed Aug 21 10:55:12 2013 -0400
     4.2 +++ b/core/logic_bridge.cpp	Thu Aug 22 14:05:44 2013 -0700
     4.3 @@ -1,5 +1,5 @@
     4.4  /**
     4.5 - * vim: set ts=4 sw=4 :
     4.6 + * vim: set ts=4 sw=4 tw=99 noet:
     4.7   * =============================================================================
     4.8   * SourceMod
     4.9   * Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
    4.10 @@ -406,6 +406,7 @@
    4.11  
    4.12  	core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
    4.13  	core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false);
    4.14 +	core_bridge.listeners = SMGlobalClass::head;
    4.15  
    4.16  	ILibrary *mmlib;
    4.17  	char path[PLATFORM_MAX_PATH];
     5.1 --- a/core/sourcemod.cpp	Wed Aug 21 10:55:12 2013 -0400
     5.2 +++ b/core/sourcemod.cpp	Thu Aug 22 14:05:44 2013 -0700
     5.3 @@ -129,6 +129,8 @@
     5.4  	return ConfigResult_Ignore;
     5.5  }
     5.6  
     5.7 +static bool sSourceModInitialized = false;
     5.8 +
     5.9  bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late)
    5.10  {
    5.11  	const char *gamepath = g_SMAPI->GetBaseDir();
    5.12 @@ -240,6 +242,8 @@
    5.13  
    5.14  	g_pSourcePawn2->SetDebugListener(logicore.debugger);
    5.15  
    5.16 +	sSourceModInitialized = true;
    5.17 +
    5.18  	/* Hook this now so we can detect startup without calling StartSourceMod() */
    5.19  	SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
    5.20  
    5.21 @@ -475,69 +479,74 @@
    5.22  
    5.23  void SourceModBase::CloseSourceMod()
    5.24  {
    5.25 -	/* Force a level end */
    5.26 -	LevelShutdown();
    5.27 +	if (!sSourceModInitialized)
    5.28 +		return;
    5.29 +
    5.30 +	SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
    5.31  
    5.32 +	if (g_Loaded)
    5.33 +	{
    5.34 +		/* Force a level end */
    5.35 +		LevelShutdown();
    5.36 +		ShutdownServices();
    5.37 +	}
    5.38 +
    5.39 +	/* Rest In Peace */
    5.40 +	ShutdownLogicBridge();
    5.41 +	ShutdownJIT();
    5.42 +}
    5.43 +
    5.44 +void SourceModBase::ShutdownServices()
    5.45 +{
    5.46  	/* Unload plugins */
    5.47  	scripts->Shutdown();
    5.48  
    5.49  	/* Unload extensions */
    5.50  	extsys->Shutdown();
    5.51  
    5.52 -	SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
    5.53 +	if (g_pOnMapEnd)
    5.54 +		g_Forwards.ReleaseForward(g_pOnMapEnd);
    5.55  
    5.56 -	if (g_Loaded)
    5.57 +	/* Notify! */
    5.58 +	SMGlobalClass *pBase = SMGlobalClass::head;
    5.59 +	while (pBase)
    5.60  	{
    5.61 -		if (g_pOnMapEnd)
    5.62 -		{
    5.63 -			g_Forwards.ReleaseForward(g_pOnMapEnd);
    5.64 -		}
    5.65 -	
    5.66 -		/* Notify! */
    5.67 -		SMGlobalClass *pBase = SMGlobalClass::head;
    5.68 -		while (pBase)
    5.69 -		{
    5.70 -			pBase->OnSourceModShutdown();
    5.71 -			pBase = pBase->m_pGlobalClassNext;
    5.72 -		}
    5.73 -	
    5.74 -		/* Delete all data packs */
    5.75 -		CStack<CDataPack *>::iterator iter;
    5.76 -		CDataPack *pd;
    5.77 -		for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++)
    5.78 -		{
    5.79 -			pd = (*iter);
    5.80 -			delete pd;
    5.81 -		}
    5.82 -		m_freepacks.popall();
    5.83 -	
    5.84 -		/* Notify! */
    5.85 -		pBase = SMGlobalClass::head;
    5.86 -		while (pBase)
    5.87 -		{
    5.88 -			pBase->OnSourceModAllShutdown();
    5.89 -			pBase = pBase->m_pGlobalClassNext;
    5.90 -		}
    5.91 -	
    5.92 -		if (enginePatch)
    5.93 -		{
    5.94 -			SH_RELEASE_CALLCLASS(enginePatch);
    5.95 -			enginePatch = NULL;
    5.96 -		}
    5.97 -	
    5.98 -		if (gamedllPatch)
    5.99 -		{
   5.100 -			SH_RELEASE_CALLCLASS(gamedllPatch);
   5.101 -			gamedllPatch = NULL;
   5.102 -		}
   5.103 -
   5.104 -		SH_REMOVE_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false);
   5.105 -		SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
   5.106 +		pBase->OnSourceModShutdown();
   5.107 +		pBase = pBase->m_pGlobalClassNext;
   5.108  	}
   5.109  
   5.110 -	/* Rest In Peace */
   5.111 -	ShutdownLogicBridge();
   5.112 -	ShutdownJIT();
   5.113 +	/* Delete all data packs */
   5.114 +	CStack<CDataPack *>::iterator iter;
   5.115 +	CDataPack *pd;
   5.116 +	for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++)
   5.117 +	{
   5.118 +		pd = (*iter);
   5.119 +		delete pd;
   5.120 +	}
   5.121 +	m_freepacks.popall();
   5.122 +
   5.123 +	/* Notify! */
   5.124 +	pBase = SMGlobalClass::head;
   5.125 +	while (pBase)
   5.126 +	{
   5.127 +		pBase->OnSourceModAllShutdown();
   5.128 +		pBase = pBase->m_pGlobalClassNext;
   5.129 +	}
   5.130 +
   5.131 +	if (enginePatch)
   5.132 +	{
   5.133 +		SH_RELEASE_CALLCLASS(enginePatch);
   5.134 +		enginePatch = NULL;
   5.135 +	}
   5.136 +
   5.137 +	if (gamedllPatch)
   5.138 +	{
   5.139 +		SH_RELEASE_CALLCLASS(gamedllPatch);
   5.140 +		gamedllPatch = NULL;
   5.141 +	}
   5.142 +
   5.143 +	SH_REMOVE_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false);
   5.144 +	SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
   5.145  }
   5.146  
   5.147  void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...)
     6.1 --- a/core/sourcemod.h	Wed Aug 21 10:55:12 2013 -0400
     6.2 +++ b/core/sourcemod.h	Thu Aug 22 14:05:44 2013 -0700
     6.3 @@ -1,5 +1,5 @@
     6.4  /**
     6.5 - * vim: set ts=4 :
     6.6 + * vim: set ts=4 sw=4 tw=99 noet:
     6.7   * =============================================================================
     6.8   * SourceMod
     6.9   * Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
    6.10 @@ -137,6 +137,8 @@
    6.11  	int GetShApiVersion();
    6.12  	bool IsMapRunning();
    6.13  private:
    6.14 +	void ShutdownServices();
    6.15 +private:
    6.16  	CStack<CDataPack *> m_freepacks;
    6.17  	char m_SMBaseDir[PLATFORM_MAX_PATH];
    6.18  	char m_SMRelDir[PLATFORM_MAX_PATH];
     7.1 --- a/extensions/clientprefs/cookie.cpp	Wed Aug 21 10:55:12 2013 -0400
     7.2 +++ b/extensions/clientprefs/cookie.cpp	Thu Aug 22 14:05:44 2013 -0700
     7.3 @@ -1,5 +1,5 @@
     7.4  /**
     7.5 - * vim: set ts=4 :
     7.6 + * vim: set ts=4 sw=4 tw=99 noet:
     7.7   * =============================================================================
     7.8   * SourceMod Client Preferences Extension
     7.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    7.10 @@ -55,35 +55,12 @@
    7.11  	for (int i = playerhelpers->GetMaxClients()+1; --i > 0;)
    7.12  	{
    7.13  		if (connected[i])
    7.14 -		{
    7.15  			OnClientDisconnecting(i);
    7.16 -		}
    7.17  	}
    7.18  
    7.19  	/* Find all cookies and delete them */
    7.20 -	Cookie *current;
    7.21 -
    7.22  	for (SourceHook::List<Cookie *>::iterator _iter = cookieList.begin(); _iter != cookieList.end(); _iter++)
    7.23 -	{
    7.24 -		current = (Cookie *)*_iter;
    7.25 -
    7.26 -		if (current == NULL)
    7.27 -		{
    7.28 -			continue;
    7.29 -		}
    7.30 -
    7.31 -		g_ClientPrefs.cookieMutex->Lock();
    7.32 -		if (current->usedInQuery)
    7.33 -		{
    7.34 -			current->shouldDelete = true;
    7.35 -			g_ClientPrefs.cookieMutex->Unlock();
    7.36 -		}
    7.37 -		else
    7.38 -		{
    7.39 -			g_ClientPrefs.cookieMutex->Unlock();
    7.40 -			delete current;
    7.41 -		}
    7.42 -	}
    7.43 +		delete (*_iter);
    7.44  	
    7.45  	cookieList.clear();
    7.46  }
    7.47 @@ -93,9 +70,7 @@
    7.48  	Cookie **pCookie = cookieTrie.retrieve(name);
    7.49  
    7.50  	if (pCookie == NULL)
    7.51 -	{
    7.52  		return NULL;
    7.53 -	}
    7.54  
    7.55  	return *pCookie;
    7.56  }
    7.57 @@ -116,7 +91,6 @@
    7.58  
    7.59  	/* First time cookie - Create from scratch */
    7.60  	pCookie = new Cookie(name, description, access);
    7.61 -	pCookie->usedInQuery++;
    7.62  	
    7.63  	/* Attempt to insert cookie into the db and get its ID num */
    7.64  	TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie);
     8.1 --- a/extensions/clientprefs/cookie.h	Wed Aug 21 10:55:12 2013 -0400
     8.2 +++ b/extensions/clientprefs/cookie.h	Thu Aug 22 14:05:44 2013 -0700
     8.3 @@ -75,12 +75,7 @@
     8.4  		dbid = -1;
     8.5  
     8.6  		for (int i=0; i<=MAXCLIENTS; i++)
     8.7 -		{
     8.8  			data[i] = NULL;
     8.9 -		}
    8.10 -
    8.11 -		shouldDelete = false;
    8.12 -		usedInQuery = 0;
    8.13  	}
    8.14  
    8.15  	~Cookie()
    8.16 @@ -88,9 +83,7 @@
    8.17  		for (int i=0; i<=MAXCLIENTS; i++)
    8.18  		{
    8.19  			if (data[i] != NULL)
    8.20 -			{
    8.21  				delete data[i];
    8.22 -			}
    8.23  		}
    8.24  	}
    8.25  
    8.26 @@ -99,10 +92,6 @@
    8.27  	int dbid;
    8.28  	CookieData *data[MAXCLIENTS+1];
    8.29  	CookieAccess access;
    8.30 -
    8.31 -	/* Reference counting stuff */
    8.32 -	bool shouldDelete;
    8.33 -	int usedInQuery;
    8.34  };
    8.35  
    8.36  class CookieManager : public IClientListener, public IPluginsListener
     9.1 --- a/extensions/clientprefs/extension.cpp	Wed Aug 21 10:55:12 2013 -0400
     9.2 +++ b/extensions/clientprefs/extension.cpp	Thu Aug 22 14:05:44 2013 -0700
     9.3 @@ -1,5 +1,5 @@
     9.4  /**
     9.5 - * vim: set ts=4 :
     9.6 + * vim: set ts=4 sw=4 tw=99 noet:
     9.7   * =============================================================================
     9.8   * SourceMod Client Preferences Extension
     9.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    9.10 @@ -50,9 +50,6 @@
    9.11  
    9.12  bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
    9.13  {
    9.14 -	queryMutex = threader->MakeMutex();
    9.15 -	cookieMutex = threader->MakeMutex();
    9.16 -
    9.17  	DBInfo = dbi->FindDatabaseConf("clientprefs");
    9.18  
    9.19  	if (DBInfo == NULL)
    9.20 @@ -155,13 +152,15 @@
    9.21  	}
    9.22  }
    9.23  
    9.24 -void ClientPrefs::SDK_OnUnload()
    9.25 +void ClientPrefs::SDK_OnDependenciesDropped()
    9.26  {
    9.27 +	// At this point, we're guaranteed that DBI has flushed the worker thread
    9.28 +	// for us, so no cookies should have outstanding queries.
    9.29 +	g_CookieManager.Unload();
    9.30 +
    9.31  	handlesys->RemoveType(g_CookieType, myself->GetIdentity());
    9.32  	handlesys->RemoveType(g_CookieIterator, myself->GetIdentity());
    9.33  
    9.34 -	g_CookieManager.Unload();
    9.35 -
    9.36  	if (Database != NULL)
    9.37  	{
    9.38  		Database->Close();
    9.39 @@ -199,9 +198,6 @@
    9.40  
    9.41  	plsys->RemovePluginsListener(&g_CookieManager);
    9.42  	playerhelpers->RemoveClientListener(&g_CookieManager);
    9.43 -
    9.44 -	queryMutex->DestroyThis();
    9.45 -	cookieMutex->DestroyThis();
    9.46  }
    9.47  
    9.48  void ClientPrefs::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
    9.49 @@ -312,7 +308,11 @@
    9.50  
    9.51  	databaseLoading = false;
    9.52  
    9.53 -	this->ProcessQueryCache();	
    9.54 +	// Need a new scope because of the goto above.
    9.55 +	{
    9.56 +		ke::AutoLock lock(&queryLock);
    9.57 +		this->ProcessQueryCache();	
    9.58 +	}
    9.59  	return;
    9.60  
    9.61  fatal_fail:
    9.62 @@ -321,24 +321,18 @@
    9.63  	databaseLoading = false;
    9.64  }
    9.65  
    9.66 -bool ClientPrefs::AddQueryToQueue( TQueryOp *query )
    9.67 +bool ClientPrefs::AddQueryToQueue(TQueryOp *query)
    9.68  {
    9.69 -	queryMutex->Lock();
    9.70 -	if (Database == NULL)
    9.71  	{
    9.72 -		cachedQueries.push_back(query);
    9.73 -		queryMutex->Unlock();
    9.74 -		return false;
    9.75 -	}
    9.76 -	
    9.77 -	if (!cachedQueries.empty())
    9.78 -	{
    9.79 -		queryMutex->Unlock();
    9.80 -		this->ProcessQueryCache();
    9.81 -	}
    9.82 -	else
    9.83 -	{
    9.84 -		queryMutex->Unlock();
    9.85 +		ke::AutoLock lock(&queryLock);
    9.86 +		if (Database == NULL)
    9.87 +		{
    9.88 +			cachedQueries.push_back(query);
    9.89 +			return false;
    9.90 +		}
    9.91 +		
    9.92 +		if (!cachedQueries.empty())
    9.93 +			this->ProcessQueryCache();
    9.94  	}
    9.95  
    9.96  	query->SetDatabase(Database);
    9.97 @@ -348,12 +342,11 @@
    9.98  
    9.99  void ClientPrefs::ProcessQueryCache()
   9.100  {
   9.101 +	queryLock.AssertCurrentThreadOwns();
   9.102 +
   9.103  	if (Database == NULL)
   9.104 -	{
   9.105  		return;
   9.106 -	}
   9.107  
   9.108 -	queryMutex->Lock();
   9.109  	TQueryOp *op;
   9.110  	for (SourceHook::List<TQueryOp *>::iterator iter = cachedQueries.begin(); iter != cachedQueries.end(); iter++)
   9.111  	{
   9.112 @@ -363,7 +356,6 @@
   9.113  	}
   9.114  
   9.115  	cachedQueries.clear();
   9.116 -	queryMutex->Unlock();
   9.117  }
   9.118  
   9.119  size_t IsAuthIdConnected(char *authID)
   9.120 @@ -417,8 +409,7 @@
   9.121  
   9.122  void ClientPrefs::ClearQueryCache(int serial)
   9.123  {
   9.124 -	queryMutex->Lock();
   9.125 -
   9.126 +	ke::AutoLock lock(&queryLock);
   9.127  	for (SourceHook::List<TQueryOp *>::iterator iter = cachedQueries.begin(); iter != cachedQueries.end();)
   9.128  	{
   9.129  		TQueryOp *op = *iter;
   9.130 @@ -432,7 +423,6 @@
   9.131  			iter++;
   9.132   		}
   9.133   	}
   9.134 -	queryMutex->Unlock();
   9.135  }
   9.136  
   9.137  bool Translate(char *buffer, 
   9.138 @@ -530,7 +520,5 @@
   9.139  	phrases = NULL;
   9.140  	DBInfo = NULL;
   9.141  
   9.142 -	cookieMutex = NULL;
   9.143 -	queryMutex = NULL;
   9.144  	identity = NULL;
   9.145  }
    10.1 --- a/extensions/clientprefs/extension.h	Wed Aug 21 10:55:12 2013 -0400
    10.2 +++ b/extensions/clientprefs/extension.h	Thu Aug 22 14:05:44 2013 -0700
    10.3 @@ -1,5 +1,5 @@
    10.4  /**
    10.5 - * vim: set ts=4 :
    10.6 + * vim: set ts=4 sw=4 tw=99 noet:
    10.7   * =============================================================================
    10.8   * SourceMod Client Preferences Extension
    10.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
   10.10 @@ -39,6 +39,8 @@
   10.11  #include "smsdk_ext.h"
   10.12  #include "sh_list.h"
   10.13  
   10.14 +#include <ke_thread_utils.h>
   10.15 +
   10.16  char * UTIL_strncpy(char * destination, const char * source, size_t num);
   10.17  
   10.18  #include "cookie.h"
   10.19 @@ -73,11 +75,8 @@
   10.20  	 * @return			True to succeed loading, false to fail.
   10.21  	 */
   10.22  	virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
   10.23 -	
   10.24 -	/**
   10.25 -	 * @brief This is called right before the extension is unloaded.
   10.26 -	 */
   10.27 -	virtual void SDK_OnUnload();
   10.28 +
   10.29 +	virtual void SDK_OnDependenciesDropped();
   10.30  
   10.31  	/**
   10.32  	 * @brief This is called once all known extensions have been loaded.
   10.33 @@ -162,7 +161,7 @@
   10.34  
   10.35  private:
   10.36  	SourceHook::List<TQueryOp *> cachedQueries;
   10.37 -	IMutex *queryMutex;
   10.38 +	ke::Mutex queryLock;
   10.39  	IdentityToken_t *identity;
   10.40  };
   10.41  
    11.1 --- a/extensions/clientprefs/query.cpp	Wed Aug 21 10:55:12 2013 -0400
    11.2 +++ b/extensions/clientprefs/query.cpp	Thu Aug 22 14:05:44 2013 -0700
    11.3 @@ -303,23 +303,6 @@
    11.4  
    11.5  ParamData::~ParamData()
    11.6  {
    11.7 -	if (cookie)
    11.8 -	{
    11.9 -		g_ClientPrefs.cookieMutex->Lock();
   11.10 -		cookie->usedInQuery--;
   11.11 -
   11.12 -		if (cookie->shouldDelete && cookie->usedInQuery <= 0)
   11.13 -		{
   11.14 -			g_ClientPrefs.cookieMutex->Unlock();
   11.15 -			delete cookie;
   11.16 -			cookie = NULL;
   11.17 -		}
   11.18 -		else
   11.19 -		{
   11.20 -			g_ClientPrefs.cookieMutex->Unlock();
   11.21 -		}
   11.22 -	}
   11.23 -
   11.24  	if (data)
   11.25  	{
   11.26  		/* Data is only ever passed in a client disconnect query and always needs to be deleted */
    12.1 --- a/extensions/clientprefs/sdk/smsdk_config.h	Wed Aug 21 10:55:12 2013 -0400
    12.2 +++ b/extensions/clientprefs/sdk/smsdk_config.h	Thu Aug 22 14:05:44 2013 -0700
    12.3 @@ -67,7 +67,7 @@
    12.4  //#define SMEXT_ENABLE_MEMUTILS
    12.5  #define SMEXT_ENABLE_GAMEHELPERS
    12.6  //#define SMEXT_ENABLE_TIMERSYS
    12.7 -#define SMEXT_ENABLE_THREADER
    12.8 +//#define SMEXT_ENABLE_THREADER
    12.9  //#define SMEXT_ENABLE_LIBSYS
   12.10  #define SMEXT_ENABLE_MENUS
   12.11  //#define SMEXT_ENABLE_ADTFACTORY
    13.1 --- a/extensions/clientprefs/sdk/smsdk_ext.cpp	Wed Aug 21 10:55:12 2013 -0400
    13.2 +++ b/extensions/clientprefs/sdk/smsdk_ext.cpp	Thu Aug 22 14:05:44 2013 -0700
    13.3 @@ -1,5 +1,5 @@
    13.4  /**
    13.5 - * vim: set ts=4 :
    13.6 + * vim: set ts=4 sw=4 tw=99 noet:
    13.7   * =============================================================================
    13.8   * SourceMod Base Extension Code
    13.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
   13.10 @@ -97,6 +97,12 @@
   13.11  #if defined SMEXT_ENABLE_TRANSLATOR
   13.12  ITranslator *translator = NULL;
   13.13  #endif
   13.14 +#if defined SMEXT_ENABLE_NINVOKE
   13.15 +INativeInterface *ninvoke = NULL;
   13.16 +#endif
   13.17 +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU
   13.18 +IRootConsole *rootconsole = NULL;
   13.19 +#endif
   13.20  
   13.21  /** Exports the main interface */
   13.22  PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
   13.23 @@ -185,6 +191,12 @@
   13.24  #if defined SMEXT_ENABLE_TRANSLATOR
   13.25  	SM_GET_IFACE(TRANSLATOR, translator);
   13.26  #endif
   13.27 +#if defined SMEXT_ENABLE_NINVOKE
   13.28 +	SM_GET_IFACE(NINVOKE, ninvoke);
   13.29 +#endif
   13.30 +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU
   13.31 +	SM_GET_IFACE(ROOTCONSOLE, rootconsole);
   13.32 +#endif
   13.33  
   13.34  	if (SDK_OnLoad(error, maxlength, late))
   13.35  	{
   13.36 @@ -227,6 +239,11 @@
   13.37  	SDK_OnUnload();
   13.38  }
   13.39  
   13.40 +void SDKExtension::OnDependenciesDropped()
   13.41 +{
   13.42 +	SDK_OnDependenciesDropped();
   13.43 +}
   13.44 +
   13.45  const char *SDKExtension::GetExtensionAuthor()
   13.46  {
   13.47  	return SMEXT_CONF_AUTHOR;
   13.48 @@ -279,6 +296,10 @@
   13.49  {
   13.50  }
   13.51  
   13.52 +void SDKExtension::SDK_OnDependenciesDropped()
   13.53 +{
   13.54 +}
   13.55 +
   13.56  #if defined SMEXT_CONF_METAMOD
   13.57  
   13.58  PluginId g_PLID = 0;						/**< Metamod plugin ID */
    14.1 --- a/extensions/clientprefs/sdk/smsdk_ext.h	Wed Aug 21 10:55:12 2013 -0400
    14.2 +++ b/extensions/clientprefs/sdk/smsdk_ext.h	Thu Aug 22 14:05:44 2013 -0700
    14.3 @@ -1,5 +1,5 @@
    14.4  /**
    14.5 - * vim: set ts=4 :
    14.6 + * vim: set ts=4 sw=4 tw=99 noet:
    14.7   * =============================================================================
    14.8   * SourceMod Base Extension Code
    14.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
   14.10 @@ -91,6 +91,12 @@
   14.11  #if defined SMEXT_ENABLE_TRANSLATOR
   14.12  #include <ITranslator.h>
   14.13  #endif
   14.14 +#if defined SMEXT_ENABLE_NINVOKE
   14.15 +#include <INativeInvoker.h>
   14.16 +#endif
   14.17 +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU
   14.18 +#include <IRootConsoleMenu.h>
   14.19 +#endif
   14.20  
   14.21  #if defined SMEXT_CONF_METAMOD
   14.22  #include <ISmmPlugin.h>
   14.23 @@ -121,7 +127,7 @@
   14.24  	virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
   14.25  	
   14.26  	/**
   14.27 -	 * @brief This is called right before the extension is unloaded.
   14.28 +	 * @brief This is called once the extension unloading process begins.
   14.29  	 */
   14.30  	virtual void SDK_OnUnload();
   14.31  
   14.32 @@ -135,6 +141,12 @@
   14.33  	 */
   14.34  	virtual void SDK_OnPauseChange(bool paused);
   14.35  
   14.36 +	/**
   14.37 +	 * @brief Called after SDK_OnUnload, once all dependencies have been
   14.38 +	 * removed, and the extension is about to be removed from memory.
   14.39 +	 */
   14.40 +	virtual void SDK_OnDependenciesDropped();
   14.41 +
   14.42  #if defined SMEXT_CONF_METAMOD
   14.43  	/**
   14.44  	 * @brief Called when Metamod is attached, before the extension version is called.
   14.45 @@ -197,6 +209,9 @@
   14.46  	virtual const char *GetExtensionDescription();
   14.47  	/** Returns date string */
   14.48  	virtual const char *GetExtensionDateString();
   14.49 +
   14.50 +	/** Called after OnExtensionUnload, once dependencies have been dropped. */
   14.51 +	virtual void OnDependenciesDropped();
   14.52  #if defined SMEXT_CONF_METAMOD
   14.53  public: //ISmmPlugin
   14.54  	/** Called when the extension is attached to Metamod. */
   14.55 @@ -289,6 +304,12 @@
   14.56  #if defined SMEXT_ENABLE_TRANSLATOR
   14.57  extern ITranslator *translator;
   14.58  #endif
   14.59 +#if defined SMEXT_ENABLE_NINVOKE
   14.60 +extern INativeInterface *ninvoke;
   14.61 +#endif
   14.62 +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU
   14.63 +extern IRootConsole *rootconsole;
   14.64 +#endif
   14.65  
   14.66  #if defined SMEXT_CONF_METAMOD
   14.67  PLUGIN_GLOBALVARS();
    15.1 --- a/public/IExtensionSys.h	Wed Aug 21 10:55:12 2013 -0400
    15.2 +++ b/public/IExtensionSys.h	Thu Aug 22 14:05:44 2013 -0700
    15.3 @@ -1,5 +1,5 @@
    15.4  /**
    15.5 - * vim: set ts=4 :
    15.6 + * vim: set ts=4 sw=4 tw=99 noet:
    15.7   * =============================================================================
    15.8   * SourceMod
    15.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
   15.10 @@ -134,8 +134,9 @@
   15.11  	 * itself is not versioned.
   15.12  	 *
   15.13  	 * V6 - added TestFeature() to IShareSys.
   15.14 +	 * V7 - added OnDependenciesDropped() to IExtensionInterface.
   15.15  	 */
   15.16 -	#define SMINTERFACE_EXTENSIONAPI_VERSION	6
   15.17 +	#define SMINTERFACE_EXTENSIONAPI_VERSION	7
   15.18  
   15.19  	/**
   15.20  	 * @brief The interface an extension must expose.
   15.21 @@ -313,6 +314,17 @@
   15.22  		virtual void OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
   15.23  		{
   15.24  		}
   15.25 +
   15.26 +		/**
   15.27 +		 * @brief Called once all dependencies have been unloaded. This is
   15.28 +		 * called AFTER OnExtensionUnload(), but before the extension library
   15.29 +		 * has been unloaded. It can be used as an alternate unload hook for
   15.30 +		 * cases where having no dependent plugins would make shutdown much
   15.31 +		 * simplier.
   15.32 +		 */
   15.33 +		virtual void OnDependenciesDropped()
   15.34 +		{
   15.35 +		}
   15.36  	};
   15.37  
   15.38  	/**
    16.1 --- a/public/sample_ext/sdk/smsdk_ext.cpp	Wed Aug 21 10:55:12 2013 -0400
    16.2 +++ b/public/sample_ext/sdk/smsdk_ext.cpp	Thu Aug 22 14:05:44 2013 -0700
    16.3 @@ -1,5 +1,5 @@
    16.4  /**
    16.5 - * vim: set ts=4 :
    16.6 + * vim: set ts=4 sw=4 tw=99 noet:
    16.7   * =============================================================================
    16.8   * SourceMod Base Extension Code
    16.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
   16.10 @@ -239,6 +239,11 @@
   16.11  	SDK_OnUnload();
   16.12  }
   16.13  
   16.14 +void SDKExtension::OnDependenciesDropped()
   16.15 +{
   16.16 +	SDK_OnDependenciesDropped();
   16.17 +}
   16.18 +
   16.19  const char *SDKExtension::GetExtensionAuthor()
   16.20  {
   16.21  	return SMEXT_CONF_AUTHOR;
   16.22 @@ -291,6 +296,10 @@
   16.23  {
   16.24  }
   16.25  
   16.26 +void SDKExtension::SDK_OnDependenciesDropped()
   16.27 +{
   16.28 +}
   16.29 +
   16.30  #if defined SMEXT_CONF_METAMOD
   16.31  
   16.32  PluginId g_PLID = 0;						/**< Metamod plugin ID */
    17.1 --- a/public/sample_ext/sdk/smsdk_ext.h	Wed Aug 21 10:55:12 2013 -0400
    17.2 +++ b/public/sample_ext/sdk/smsdk_ext.h	Thu Aug 22 14:05:44 2013 -0700
    17.3 @@ -1,5 +1,5 @@
    17.4  /**
    17.5 - * vim: set ts=4 :
    17.6 + * vim: set ts=4 sw=4 tw=99 noet:
    17.7   * =============================================================================
    17.8   * SourceMod Base Extension Code
    17.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
   17.10 @@ -127,7 +127,7 @@
   17.11  	virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
   17.12  	
   17.13  	/**
   17.14 -	 * @brief This is called right before the extension is unloaded.
   17.15 +	 * @brief This is called once the extension unloading process begins.
   17.16  	 */
   17.17  	virtual void SDK_OnUnload();
   17.18  
   17.19 @@ -141,6 +141,12 @@
   17.20  	 */
   17.21  	virtual void SDK_OnPauseChange(bool paused);
   17.22  
   17.23 +	/**
   17.24 +	 * @brief Called after SDK_OnUnload, once all dependencies have been
   17.25 +	 * removed, and the extension is about to be removed from memory.
   17.26 +	 */
   17.27 +	virtual void SDK_OnDependenciesDropped();
   17.28 +
   17.29  #if defined SMEXT_CONF_METAMOD
   17.30  	/**
   17.31  	 * @brief Called when Metamod is attached, before the extension version is called.
   17.32 @@ -203,6 +209,9 @@
   17.33  	virtual const char *GetExtensionDescription();
   17.34  	/** Returns date string */
   17.35  	virtual const char *GetExtensionDateString();
   17.36 +
   17.37 +	/** Called after OnExtensionUnload, once dependencies have been dropped. */
   17.38 +	virtual void OnDependenciesDropped();
   17.39  #if defined SMEXT_CONF_METAMOD
   17.40  public: //ISmmPlugin
   17.41  	/** Called when the extension is attached to Metamod. */