core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Fri Feb 16 03:47:10 2007 +0000 (2007-02-16)
changeset 501 e209a7296936
parent 447 f072596618c9
child 525 d36c45088e36
permissions -rw-r--r--
removed this potential feature, not useful enough
     1 /**
     2  * ===============================================================
     3  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4  * ===============================================================
     5  *
     6  * This file is not open source and may not be copied without explicit
     7  * written permission of AlliedModders LLC.  This file may not be redistributed 
     8  * in whole or significant part.
     9  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    10  *
    11  * Version: $Id$
    12  */
    13 
    14 #include <assert.h>
    15 #include <stdarg.h>
    16 #include <string.h>
    17 #include "ForwardSys.h"
    18 #include "PluginSys.h"
    19 #include "ShareSys.h"
    20 
    21 CForwardManager g_Forwards;
    22 
    23 /**
    24  * Gensis turns to its source, reduction occurs stepwise although the essence is all one.
    25  * End of line.  FTL system check.
    26  *
    27  * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
    28  * VARARG FUNCTIONS:
    29  * - Pushing no varargs
    30  */
    31 
    32 // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
    33 // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
    34 
    35 void CForwardManager::OnSourceModAllInitialized()
    36 {
    37 	g_PluginSys.AddPluginsListener(this);
    38 	g_ShareSys.AddInterface(NULL, this);
    39 }
    40 
    41 void CForwardManager::OnSourceModShutdown()
    42 {
    43 	g_PluginSys.RemovePluginsListener(this);
    44 }
    45 
    46 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...)
    47 {
    48 	CForward *fwd;
    49 	va_list ap;
    50 	va_start(ap, types);
    51 	
    52 	fwd = CForward::CreateForward(name, et, num_params, types, ap);
    53 
    54 	va_end(ap);
    55 
    56 	if (fwd)
    57 	{
    58 		m_managed.push_back(fwd);
    59 	}
    60 
    61 	return fwd;
    62 }
    63 
    64 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, ParamType *types, ...)
    65 {
    66 	CForward *fwd;
    67 	va_list ap;
    68 	va_start(ap, types);
    69 
    70 	fwd = CForward::CreateForward(name, et, num_params, types, ap);
    71 
    72 	va_end(ap);
    73 
    74 	if (fwd)
    75 	{
    76 		m_unmanaged.push_back(fwd);
    77 	}
    78 
    79 	return fwd;
    80 }
    81 
    82 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
    83 {
    84 	/* Attach any globally managed forwards */
    85 	List<CForward *>::iterator iter;
    86 	CForward *fwd;
    87 
    88 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
    89 	{
    90 		fwd = (*iter);
    91 		IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
    92 		if (pFunc)
    93 		{
    94 			fwd->AddFunction(pFunc);
    95 		}
    96 	}
    97 }
    98 
    99 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
   100 {
   101 	List<CForward *>::iterator iter;
   102 	CForward *fwd;
   103 
   104 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   105 	{
   106 		fwd = (*iter);
   107 		fwd->RemoveFunctionsOfPlugin(plugin);
   108 	}
   109 
   110 	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   111 	{
   112 		fwd = (*iter);
   113 		fwd->RemoveFunctionsOfPlugin(plugin);
   114 	}
   115 }
   116 
   117 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
   118 {
   119 	List<CForward *>::iterator iter;
   120 	CForward *fwd;
   121 
   122 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   123 	{
   124 		fwd = (*iter);
   125 		if (strcmp(fwd->GetForwardName(), name) == 0)
   126 		{
   127 			if (ifchng)
   128 			{
   129 				*ifchng = NULL;
   130 			}
   131 			return fwd;
   132 		}
   133 	}
   134 
   135 	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   136 	{
   137 		fwd = (*iter);
   138 		if (strcmp(fwd->GetForwardName(), name) == 0)
   139 		{
   140 			if (ifchng)
   141 			{
   142 				*ifchng = fwd;
   143 			}
   144 			return fwd;
   145 		}
   146 	}
   147 
   148 	if (ifchng)
   149 	{
   150 		*ifchng = NULL;
   151 	}
   152 
   153 	return NULL;
   154 }
   155 
   156 void CForwardManager::ReleaseForward(IForward *forward)
   157 {
   158 	ForwardFree(static_cast<CForward *>(forward));
   159 }
   160 
   161 void CForwardManager::ForwardFree(CForward *fwd)
   162 {
   163 	m_FreeForwards.push(fwd);
   164 	m_managed.remove(fwd);
   165 }
   166 
   167 CForward *CForwardManager::ForwardMake()
   168 {
   169 	CForward *fwd;
   170 	if (m_FreeForwards.empty())
   171 	{
   172 		fwd = new CForward;
   173 	} else {
   174 		fwd = m_FreeForwards.front();
   175 		m_FreeForwards.pop();
   176 	}
   177 	return fwd;
   178 }
   179 
   180 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
   181 {
   182 	List<CForward *>::iterator iter;
   183 	CForward *fwd;
   184 
   185 	if (paused)
   186 	{
   187 		for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   188 		{
   189 			fwd = (*iter);
   190 			fwd->PushPausedFunctions(plugin);
   191 		}
   192 		for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   193 		{
   194 			fwd = (*iter);
   195 			fwd->PushPausedFunctions(plugin);
   196 		}
   197 	} else {
   198 		for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   199 		{
   200 			fwd = (*iter);
   201 			fwd->PopPausedFunctions(plugin);
   202 		}
   203 		for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   204 		{
   205 			fwd = (*iter);
   206 			fwd->PopPausedFunctions(plugin);
   207 		}
   208 	}
   209 }
   210 
   211 /*************************************
   212  * ACTUAL FORWARD API IMPLEMENTATION *
   213  *************************************/
   214 
   215 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
   216 {
   217 	ParamType _types[SP_MAX_EXEC_PARAMS];
   218 
   219 	if (num_params > SP_MAX_EXEC_PARAMS)
   220 	{
   221 		return NULL;
   222 	}
   223 	
   224 	if (types == NULL && num_params)
   225 	{
   226 		for (unsigned int i=0; i<num_params; i++)
   227 		{
   228 			_types[i] = (ParamType)va_arg(ap, int);
   229 			if (_types[i] == Param_VarArgs && (i != num_params - 1))
   230 			{
   231 				return NULL;
   232 			}
   233 		}
   234 		types = _types;
   235 	} else {
   236 		for (unsigned int i=0; i<num_params; i++)
   237 		{
   238 			if (types[i] == Param_VarArgs && (i != num_params - 1))
   239 			{
   240 				return NULL;
   241 			}
   242 		}
   243 	}
   244 
   245 	/* First parameter can never be varargs */
   246 	if (types[0] == Param_VarArgs)
   247 	{
   248 		return NULL;
   249 	}
   250 
   251 	CForward *pForward = g_Forwards.ForwardMake();
   252 	pForward->m_curparam = 0;
   253 	pForward->m_ExecType = et;
   254 	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
   255 	
   256 	for (unsigned int i=0; i<num_params; i++)
   257 	{
   258 		pForward->m_types[i] = types[i];
   259 	}
   260 
   261 	if (num_params && types[num_params-1] == Param_VarArgs)
   262 	{
   263 		pForward->m_varargs = num_params--;
   264 	} else {
   265 		pForward->m_varargs = false;
   266 	}
   267 
   268 	pForward->m_numparams = num_params;
   269 	pForward->m_errstate = SP_ERROR_NONE;
   270 
   271 	return pForward;
   272 }
   273 
   274 int CForward::Execute(cell_t *result, IForwardFilter *filter)
   275 {
   276 	if (m_errstate)
   277 	{
   278 		int err = m_errstate;
   279 		Cancel();
   280 		return err;
   281 	}
   282 
   283 	if (filter)
   284 	{
   285 		filter->OnExecuteBegin();
   286 	}
   287 
   288 	FuncIter iter = m_functions.begin();
   289 	IPluginFunction *func;
   290 	cell_t cur_result = 0;
   291 	cell_t high_result = 0;
   292 	int err;
   293 	unsigned int failed=0, success=0;
   294 	unsigned int num_params = m_curparam;
   295 	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   296 	FwdParamInfo *param;
   297 	ParamType type;
   298 
   299 	/* Save local, reset */
   300 	memcpy(temp_info, m_params, sizeof(m_params));
   301 	m_curparam = 0;
   302 
   303 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   304 	{
   305 		func = (*iter);
   306 
   307 		for (unsigned int i=0; i<num_params; i++)
   308 		{
   309 			param = &temp_info[i];
   310 			if (i >= m_numparams || m_types[i] == Param_Any)
   311 			{
   312 				type = param->pushedas;
   313 			} else {
   314 				type = m_types[i];
   315 			}
   316 			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
   317 			{
   318 				/* If we're byref or we're vararg, we always push everything by ref.
   319 				 * Even if they're byval, we must push them byref.
   320 				 */
   321 				if (type == Param_String)
   322 				{
   323 					func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
   324 				} else if (type == Param_Float || type == Param_Cell) {
   325 					func->PushCellByRef(&param->val, 0); 
   326 				} else {
   327 					func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
   328 					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
   329 				}
   330 			} else {
   331 				/* If we're not byref or not vararg, our job is a bit easier. */
   332 				assert(type == Param_Cell || type == Param_Float);
   333 				func->PushCell(param->val);
   334 			}
   335 		}
   336 		
   337 		/* Call the function and deal with the return value. */
   338 		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
   339 		{
   340 			bool handled = false;
   341 			if (filter)
   342 			{
   343 				handled = filter->OnErrorReport(this, func, err);
   344 			}
   345 			if (!handled)
   346 			{
   347 				/* :TODO: invoke global error reporting here */
   348 			}
   349 			failed++;
   350 		} else {
   351 			success++;
   352 			switch (m_ExecType)
   353 			{
   354 			case ET_Event:
   355 				{
   356 					if (cur_result > high_result)
   357 					{
   358 						high_result = cur_result;
   359 					}
   360 					break;
   361 				}
   362 			case ET_Hook:
   363 				{
   364 					if (cur_result > high_result)
   365 					{
   366 						high_result = cur_result;
   367 						if ((ResultType)high_result == Pl_Stop)
   368 						{
   369 							iter = m_functions.end();
   370 							break;
   371 						}
   372 					}
   373 					break;
   374 				}
   375 			case ET_Custom:
   376 				{
   377 					if (filter)
   378 					{
   379 						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
   380 						{
   381 							iter = m_functions.end();
   382 						}
   383 					}
   384 					break;
   385 				}
   386 			default:
   387 				{
   388 					break;
   389 				}
   390 			}
   391 		}
   392 	}
   393 
   394 	if (success)
   395 	{
   396 		if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
   397 		{
   398 			cur_result = high_result;
   399 		} else if (m_ExecType == ET_Ignore) {
   400 			cur_result = 0;
   401 		}
   402 		if (result)
   403 		{
   404 			*result = cur_result;
   405 		}
   406 	}
   407 
   408 	if (filter)
   409 	{
   410 		filter->OnExecuteEnd(&cur_result, success, failed);
   411 	}
   412 
   413 	return SP_ERROR_NONE;
   414 }
   415 
   416 int CForward::PushCell(cell_t cell)
   417 {
   418 	if (m_curparam < m_numparams)
   419 	{
   420 		if (m_types[m_curparam] == Param_Any)
   421 		{
   422 			m_params[m_curparam].pushedas = Param_Cell;
   423 		} else if (m_types[m_curparam] != Param_Cell) {
   424 			return SetError(SP_ERROR_PARAM);
   425 		}
   426 	} else {
   427 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   428 		{
   429 			return SetError(SP_ERROR_PARAMS_MAX);
   430 		}
   431 		m_params[m_curparam].pushedas = Param_Cell;
   432 	}
   433 
   434 	m_params[m_curparam++].val = cell;
   435 
   436 	return SP_ERROR_NONE;
   437 }
   438 
   439 int CForward::PushFloat(float number)
   440 {
   441 	if (m_curparam < m_numparams)
   442 	{
   443 		if (m_types[m_curparam] == Param_Any)
   444 		{
   445 			m_params[m_curparam].pushedas = Param_Float;
   446 		} else if (m_types[m_curparam] != Param_Float) {
   447 			return SetError(SP_ERROR_PARAM);
   448 		}
   449 	} else {
   450 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   451 		{
   452 			return SetError(SP_ERROR_PARAMS_MAX);
   453 		}
   454 		m_params[m_curparam].pushedas = Param_Float;
   455 	}
   456 
   457 	m_params[m_curparam++].val = *(cell_t *)&number;
   458 
   459 	return SP_ERROR_NONE;
   460 }
   461 
   462 int CForward::PushCellByRef(cell_t *cell, int flags)
   463 {
   464 	if (m_curparam < m_numparams)
   465 	{
   466 		if (m_types[m_curparam] == Param_Any)
   467 		{
   468 			m_params[m_curparam].pushedas = Param_CellByRef;
   469 		} else if (m_types[m_curparam] != Param_CellByRef) {
   470 			return SetError(SP_ERROR_PARAM);
   471 		}
   472 	} else {
   473 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   474 		{
   475 			return SetError(SP_ERROR_PARAMS_MAX);
   476 		}
   477 		m_params[m_curparam].pushedas = Param_CellByRef;
   478 	}
   479 
   480 	_Int_PushArray(cell, 1, flags);
   481 	m_curparam++;
   482 
   483 	return SP_ERROR_NONE;
   484 }
   485 
   486 int CForward::PushFloatByRef(float *num, int flags)
   487 {
   488 	if (m_curparam < m_numparams)
   489 	{
   490 		if (m_types[m_curparam] == Param_Any)
   491 		{
   492 			m_params[m_curparam].pushedas = Param_FloatByRef;
   493 		} else if (m_types[m_curparam] != Param_FloatByRef) {
   494 			return SetError(SP_ERROR_PARAM);
   495 		}
   496 	} else {
   497 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   498 		{
   499 			return SetError(SP_ERROR_PARAMS_MAX);
   500 		}
   501 		m_params[m_curparam].pushedas = Param_FloatByRef;
   502 	}
   503 
   504 	_Int_PushArray((cell_t *)num, 1, flags);
   505 	m_curparam++;
   506 
   507 	return SP_ERROR_NONE;
   508 }
   509 
   510 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   511 {
   512 	m_params[m_curparam].byref.cells = cells;
   513 	m_params[m_curparam].byref.flags = flags;
   514 	m_params[m_curparam].byref.orig_addr = inarray;
   515 }
   516 
   517 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
   518 {
   519 	/* We don't allow this here */
   520 	if (!inarray)
   521 	{
   522 		return SetError(SP_ERROR_PARAM);
   523 	}
   524 
   525 	if (m_curparam < m_numparams)
   526 	{
   527 		if (m_types[m_curparam] == Param_Any)
   528 		{
   529 			m_params[m_curparam].pushedas = Param_Array;
   530 		} else if (m_types[m_curparam] != Param_Array) {
   531 			return SetError(SP_ERROR_PARAM);
   532 		}
   533 	} else {
   534 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   535 		{
   536 			return SetError(SP_ERROR_PARAMS_MAX);
   537 		}
   538 		m_params[m_curparam].pushedas = Param_Array;
   539 	}
   540 
   541 	if (phys_addr)
   542 	{
   543 		*phys_addr = NULL;
   544 	}
   545 
   546 	_Int_PushArray(inarray, cells, flags);
   547 
   548 	m_curparam++;
   549 
   550 	return SP_ERROR_NONE;
   551 }
   552 
   553 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
   554 {
   555 	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
   556 	m_params[m_curparam].byref.flags = cp_flags;
   557 	m_params[m_curparam].byref.orig_addr = inarray;
   558 	m_params[m_curparam].byref.sz_flags = sz_flags;
   559 }
   560 
   561 int CForward::PushString(const char *string)
   562 {
   563 	if (m_curparam < m_numparams)
   564 	{
   565 		if (m_types[m_curparam] == Param_Any)
   566 		{
   567 			m_params[m_curparam].pushedas = Param_String;
   568 		} else if (m_types[m_curparam] != Param_String) {
   569 			return SetError(SP_ERROR_PARAM);
   570 		}
   571 	} else {
   572 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   573 		{
   574 			return SetError(SP_ERROR_PARAMS_MAX);
   575 		}
   576 		m_params[m_curparam].pushedas = Param_String;
   577 	}
   578 
   579 	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
   580 	m_curparam++;
   581 
   582 	return SP_ERROR_NONE;
   583 }
   584 
   585 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   586 {
   587 	if (m_curparam < m_numparams)
   588 	{
   589 		if (m_types[m_curparam] == Param_Any)
   590 		{
   591 			m_params[m_curparam].pushedas = Param_String;
   592 		} else if (m_types[m_curparam] != Param_String) {
   593 			return SetError(SP_ERROR_PARAM);
   594 		}
   595 	} else {
   596 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   597 		{
   598 			return SetError(SP_ERROR_PARAMS_MAX);
   599 		}
   600 		m_params[m_curparam].pushedas = Param_String;
   601 	}
   602 
   603 	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
   604 	m_curparam++;
   605 
   606 	return SP_ERROR_NONE;
   607 }
   608 
   609 void CForward::Cancel()
   610 {
   611 	if (!m_curparam)
   612 	{
   613 		return;
   614 	}
   615 
   616 	m_curparam = 0;
   617 	m_errstate = SP_ERROR_NONE;
   618 }
   619 
   620 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
   621 {
   622 	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   623 
   624 	if (!pFunc)
   625 	{
   626 		return false;
   627 	}
   628 
   629 	return AddFunction(pFunc);
   630 }
   631 
   632 bool CForward::RemoveFunction(IPluginFunction *func)
   633 {
   634 	bool found = false;
   635 	FuncIter iter;
   636 	List<IPluginFunction *> *lst;
   637 
   638 	if (func->GetParentContext()->IsRunnable())
   639 	{
   640 		lst = &m_functions;
   641 	} else {
   642 		lst = &m_paused;
   643 	}
   644 
   645 	for (iter=lst->begin(); iter!=lst->end(); iter++)
   646 	{
   647 		if ((*iter) == func)
   648 		{
   649 			found = true;
   650 			lst->erase(iter);
   651 			break;
   652 		}
   653 	}
   654 
   655 	/* Cancel a call, if any */
   656 	if (found || m_curparam)
   657 	{
   658 		func->Cancel();
   659 	}
   660 
   661 	return found;
   662 }
   663 
   664 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   665 {
   666 	FuncIter iter;
   667 	IPluginFunction *func;
   668 	unsigned int removed = 0;
   669 	IPluginContext *pContext = plugin->GetBaseContext();
   670 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   671 	{
   672 		func = (*iter);
   673 		if (func->GetParentContext() == pContext)
   674 		{
   675 			iter = m_functions.erase(iter);
   676 			removed++;
   677 		} else {
   678 			iter++;
   679 		}
   680 	}
   681 
   682 	return removed;
   683 }
   684 
   685 bool CForward::AddFunction(IPluginFunction *func)
   686 {
   687 	if (m_curparam)
   688 	{
   689 		return false;
   690 	}
   691 
   692 	//:IDEA: eventually we will tell the plugin we're using it [?]
   693 	if (func->GetParentContext()->IsRunnable())
   694 	{
   695 		m_functions.push_back(func);
   696 	} else {
   697 		m_paused.push_back(func);
   698 	}
   699 
   700 	return true;
   701 }
   702 
   703 const char *CForward::GetForwardName() const
   704 {
   705 	return m_name;
   706 }
   707 
   708 unsigned int CForward::GetFunctionCount() const
   709 {
   710 	return m_functions.size();
   711 }
   712 
   713 ExecType CForward::GetExecType() const
   714 {
   715 	return m_ExecType;
   716 }
   717 
   718 void CForward::PushPausedFunctions(IPlugin *plugin)
   719 {
   720 	FuncIter iter;
   721 	IPluginFunction *func;
   722 	IPluginContext *pContext = plugin->GetBaseContext();
   723 
   724 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   725 	{
   726 		func = (*iter);
   727 		if (func->GetParentContext() == pContext)
   728 		{
   729 			m_paused.push_back(func);
   730 			iter = m_functions.erase(iter);
   731 		} else {
   732 			iter++;
   733 		}
   734 	}
   735 }
   736 
   737 void CForward::PopPausedFunctions(IPlugin *plugin)
   738 {
   739 	FuncIter iter;
   740 	IPluginFunction *func;
   741 	IPluginContext *pContext = plugin->GetBaseContext();
   742 
   743 	for (iter=m_paused.begin(); iter!=m_paused.end();)
   744 	{
   745 		func = (*iter);
   746 		if (func->GetParentContext() == pContext)
   747 		{
   748 			m_functions.push_back(func);
   749 			iter = m_paused.erase(iter);
   750 		} else {
   751 			iter++;
   752 		}
   753 	}
   754 }