core/systems/HandleSys.cpp
changeset 1638 2980312c1c94
parent 1330 ab94316bb52b
child 1639 5c7fffd146ae
     1.1 --- a/core/systems/HandleSys.cpp	Mon Oct 22 07:54:04 2007 +0000
     1.2 +++ b/core/systems/HandleSys.cpp	Mon Oct 22 08:53:15 2007 +0000
     1.3 @@ -33,6 +33,7 @@
     1.4  #include "ShareSys.h"
     1.5  #include "PluginSys.h"
     1.6  #include "ExtensionSys.h"
     1.7 +#include "Logger.h"
     1.8  #include <assert.h>
     1.9  #include <string.h>
    1.10  
    1.11 @@ -260,6 +261,24 @@
    1.12  	return true;
    1.13  }
    1.14  
    1.15 +HandleError HandleSystem::TryAllocHandle(unsigned int *handle)
    1.16 +{
    1.17 +	if (m_FreeHandles == 0)
    1.18 +	{
    1.19 +		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
    1.20 +		{
    1.21 +			return HandleError_Limit;;
    1.22 +		}
    1.23 +		*handle = ++m_HandleTail;
    1.24 +	}
    1.25 +	else
    1.26 +	{
    1.27 +		*handle = m_Handles[m_FreeHandles--].freeID;
    1.28 +	}
    1.29 +
    1.30 +	return HandleError_None;
    1.31 +}
    1.32 +
    1.33  HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
    1.34  						   QHandle **in_pHandle, 
    1.35  						   unsigned int *in_index, 
    1.36 @@ -267,7 +286,9 @@
    1.37  						   IdentityToken_t *owner,
    1.38  						   bool identity)
    1.39  {
    1.40 +	HandleError err;
    1.41  	unsigned int owner_index = 0;
    1.42 +	bool retried_alloc = false;
    1.43  
    1.44  	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
    1.45  	{
    1.46 @@ -275,15 +296,13 @@
    1.47  	}
    1.48  
    1.49  	unsigned int handle;
    1.50 -	if (m_FreeHandles == 0)
    1.51 +	if ((err = TryAllocHandle(&handle)) != HandleError_None)
    1.52  	{
    1.53 -		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
    1.54 +		if (!TryAndFreeSomeHandles()
    1.55 +			|| (err = TryAllocHandle(&handle)) != HandleError_None)
    1.56  		{
    1.57 -			return HandleError_Limit;;
    1.58 +			return err;
    1.59  		}
    1.60 -		handle = ++m_HandleTail;
    1.61 -	} else {
    1.62 -		handle = m_Handles[m_FreeHandles--].freeID;
    1.63  	}
    1.64  
    1.65  	QHandle *pHandle = &m_Handles[handle];
    1.66 @@ -329,7 +348,9 @@
    1.67  			pIdentity->ch_prev = handle;
    1.68  			pIdentity->ch_next = handle;
    1.69  			pHandle->ch_prev = 0;
    1.70 -		} else {
    1.71 +		}
    1.72 +		else
    1.73 +		{
    1.74  			/* Link previous node to us (forward) */
    1.75  			m_Handles[pIdentity->ch_next].ch_next = handle;
    1.76  			/* Link us to previous node (backwards) */
    1.77 @@ -338,7 +359,9 @@
    1.78  			pIdentity->ch_next = handle;
    1.79  		}
    1.80  		pIdentity->refcount++;
    1.81 -	} else {
    1.82 +	}
    1.83 +	else
    1.84 +	{
    1.85  		pHandle->ch_prev = 0;
    1.86  	}
    1.87  
    1.88 @@ -918,11 +941,65 @@
    1.89  	return true;
    1.90  }
    1.91  
    1.92 +bool HandleSystem::TryAndFreeSomeHandles()
    1.93 +{
    1.94 +	IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
    1.95 +	IPlugin *highest_owner = NULL;
    1.96 +	unsigned int highest_handle_count = 0;
    1.97 +
    1.98 +	/* Search all plugins */
    1.99 +	while (pl_iter->MorePlugins())
   1.100 +	{
   1.101 +		IPlugin *plugin = pl_iter->GetPlugin();
   1.102 +		IdentityToken_t *identity = plugin->GetIdentity();
   1.103 +		unsigned int handle_count = 0;
   1.104 +
   1.105 +		if (identity == NULL)
   1.106 +		{
   1.107 +			continue;
   1.108 +		}
   1.109 +
   1.110 +		/* Search all handles */
   1.111 +		for (unsigned int i = 1; i <= m_HandleTail; i++)
   1.112 +		{
   1.113 +			if (m_Handles[i].set != HandleSet_Used)
   1.114 +			{
   1.115 +				continue;
   1.116 +			}
   1.117 +			if (m_Handles[i].owner == identity)
   1.118 +			{
   1.119 +				handle_count++;
   1.120 +			}
   1.121 +		}
   1.122 +
   1.123 +		if (handle_count > highest_handle_count)
   1.124 +		{
   1.125 +			highest_owner = plugin;
   1.126 +			highest_handle_count = handle_count;
   1.127 +		}
   1.128 +
   1.129 +		pl_iter->NextPlugin();
   1.130 +	}
   1.131 +
   1.132 +	if (highest_owner == NULL || highest_handle_count == 0)
   1.133 +	{
   1.134 +		return false;
   1.135 +	}
   1.136 +
   1.137 +	g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
   1.138 +	g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count);
   1.139 +	g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
   1.140 +
   1.141 +	highest_owner->GetContext()->n_err = SP_ERROR_MEMACCESS;
   1.142 +
   1.143 +	return g_PluginSys.UnloadPlugin(highest_owner);
   1.144 +}
   1.145 +
   1.146  void HandleSystem::Dump(FILE *fp)
   1.147  {
   1.148  	fprintf(fp, "%-10.10s\t%-20.20s\t%-20.20s\n", "Handle", "Owner", "Type");
   1.149  	fprintf(fp, "---------------------------------------------\n");
   1.150 -	for (unsigned int i=1; i<=m_HandleTail; i++)
   1.151 +	for (unsigned int i = 1; i <= m_HandleTail; i++)
   1.152  	{
   1.153  		if (m_Handles[i].set != HandleSet_Used)
   1.154  		{
   1.155 @@ -938,14 +1015,20 @@
   1.156  			if (pOwner == g_pCoreIdent)
   1.157  			{
   1.158  				owner = "CORE";
   1.159 -			} else if (pOwner == g_PluginSys.GetIdentity()) {
   1.160 +			}
   1.161 +			else if (pOwner == g_PluginSys.GetIdentity())
   1.162 +			{
   1.163  				owner = "PLUGINSYS";
   1.164 -			} else {
   1.165 +			}
   1.166 +			else
   1.167 +			{
   1.168  				CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
   1.169  				if (ext)
   1.170  				{
   1.171  					owner = ext->GetFilename();
   1.172 -				} else {
   1.173 +				}
   1.174 +				else
   1.175 +				{
   1.176  					CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
   1.177  					if (pPlugin)
   1.178  					{
   1.179 @@ -953,7 +1036,9 @@
   1.180  					}
   1.181  				}
   1.182  			}
   1.183 -		} else {
   1.184 +		}
   1.185 +		else
   1.186 +		{
   1.187  			owner = "NONE";
   1.188  		}
   1.189  		const char *type = "ANON";