core/systems/PluginSys.cpp
author David Anderson <dvander@alliedmods.net>
Sat Nov 11 05:49:52 2006 +0000 (2006-11-11)
changeset 176 c1699993453c
parent 174 5611e4b3fa42
child 177 d29ade52d953
permissions -rw-r--r--
Implemented a lot more of the plugin system
added aggressive caching O(1) function object retrieval
dvander@173
     1
#include <stdio.h>
dvander@173
     2
#include "PluginSys.h"
dvander@173
     3
dvander@174
     4
CPluginManager g_PluginMngr;
dvander@174
     5
dvander@174
     6
CPluginManager::CPluginManager()
dvander@174
     7
{
dvander@174
     8
}
dvander@173
     9
dvander@176
    10
void CFunction::Set(funcid_t funcid, CPlugin *plugin)
dvander@176
    11
{
dvander@176
    12
	m_funcid = funcid;
dvander@176
    13
	m_pPlugin = plugin;
dvander@176
    14
}
dvander@176
    15
dvander@176
    16
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
dvander@176
    17
{
dvander@176
    18
	IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
dvander@176
    19
dvander@176
    20
	for (unsigned int i=0; i<num_params; i++)
dvander@176
    21
	{
dvander@176
    22
		ctx->PushCell(params[i]);
dvander@176
    23
	}
dvander@176
    24
dvander@176
    25
	return ctx->Execute(m_funcid, result);
dvander@176
    26
}
dvander@176
    27
dvander@176
    28
IPlugin *CFunction::GetParentPlugin()
dvander@176
    29
{
dvander@176
    30
	return m_pPlugin;
dvander@176
    31
}
dvander@176
    32
dvander@176
    33
CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : 
dvander@176
    34
	m_funcid(funcid), m_pPlugin(plugin)
dvander@176
    35
{
dvander@176
    36
}
dvander@176
    37
dvander@173
    38
CPlugin *CPlugin::CreatePlugin(const char *file, 
dvander@173
    39
								bool debug_default, 
dvander@174
    40
								PluginType type, 
dvander@173
    41
								char *error, 
dvander@173
    42
								size_t maxlen)
dvander@173
    43
{
dvander@173
    44
	static unsigned int MySerial = 0;
dvander@173
    45
	FILE *fp = fopen(file, "rb");
dvander@173
    46
dvander@173
    47
	if (!fp)
dvander@173
    48
	{
dvander@173
    49
		snprintf(error, maxlen, "Could not open file");
dvander@173
    50
		return NULL;
dvander@173
    51
	}
dvander@173
    52
dvander@173
    53
	int err;
dvander@173
    54
	sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err);
dvander@173
    55
	if (pl == NULL)
dvander@173
    56
	{
dvander@173
    57
		snprintf(error, maxlen, "Could not load plugin, error %d", err);
dvander@173
    58
		return NULL;
dvander@173
    59
	}
dvander@173
    60
dvander@173
    61
	fclose(fp);
dvander@173
    62
dvander@173
    63
	ICompilation *co = g_pVM->StartCompilation(pl);
dvander@173
    64
	
dvander@173
    65
	if (debug_default)
dvander@173
    66
	{
dvander@173
    67
		if (!g_pVM->SetCompilationOption(co, "debug", "1"))
dvander@173
    68
		{
dvander@173
    69
			g_pVM->AbortCompilation(co);
dvander@173
    70
			snprintf(error, maxlen, "Could not set plugin to debug mode");
dvander@173
    71
			return NULL;
dvander@173
    72
		}
dvander@173
    73
	}
dvander@173
    74
dvander@173
    75
	sp_context_t *ctx = g_pVM->CompileToContext(co, &err);
dvander@173
    76
	if (ctx == NULL)
dvander@173
    77
	{
dvander@173
    78
		snprintf(error, maxlen, "Plugin failed to load, JIT error: %d", err);
dvander@173
    79
		return NULL;
dvander@173
    80
	}
dvander@173
    81
dvander@173
    82
	IPluginContext *base = g_pSourcePawn->CreateBaseContext(ctx);
dvander@173
    83
	CPlugin *pPlugin = new CPlugin;
dvander@173
    84
dvander@173
    85
	snprintf(pPlugin->m_filename, PLATFORM_MAX_PATH, "%s", file);
dvander@173
    86
	pPlugin->m_debugging = debug_default;
dvander@173
    87
	pPlugin->m_ctx_current.base = base;
dvander@173
    88
	pPlugin->m_ctx_current.ctx = ctx;
dvander@174
    89
	pPlugin->m_type = type;
dvander@173
    90
	pPlugin->m_serial = ++MySerial;
dvander@173
    91
	pPlugin->m_status = Plugin_Loaded;
dvander@173
    92
	pPlugin->m_plugin = pl;
dvander@173
    93
dvander@173
    94
	pPlugin->UpdateInfo();
dvander@173
    95
dvander@174
    96
	ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)(IPlugin *)pPlugin;
dvander@174
    97
dvander@176
    98
	/* Build function information loosely */
dvander@176
    99
	pPlugin->m_funcsnum = g_pVM->FunctionCount(ctx);
dvander@176
   100
dvander@176
   101
	if (pPlugin->m_funcsnum)
dvander@176
   102
	{
dvander@176
   103
		pPlugin->m_priv_funcs = new CFunction *[pPlugin->m_funcsnum];
dvander@176
   104
		memset(pPlugin->m_priv_funcs, 0, sizeof(CFunction *) * pPlugin->m_funcsnum);
dvander@176
   105
	} else {
dvander@176
   106
		pPlugin->m_priv_funcs = NULL;
dvander@176
   107
	}
dvander@176
   108
dvander@176
   109
	if (pl->info.publics_num)
dvander@176
   110
	{
dvander@176
   111
		pPlugin->m_pub_funcs = new CFunction *[pl->info.publics_num];
dvander@176
   112
		memset(pPlugin->m_pub_funcs, 0, sizeof(CFunction *) * pl->info.publics_num);
dvander@176
   113
	} else {
dvander@176
   114
		pPlugin->m_pub_funcs = NULL;
dvander@176
   115
	}
dvander@176
   116
dvander@173
   117
	return pPlugin;
dvander@173
   118
}
dvander@173
   119
dvander@176
   120
IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
dvander@176
   121
{
dvander@176
   122
	CFunction *pFunc = NULL;
dvander@176
   123
	funcid_t save = func_id;
dvander@176
   124
dvander@176
   125
	if (func_id & 1)
dvander@176
   126
	{
dvander@176
   127
		func_id >>= 1;
dvander@176
   128
		if (func_id >= m_plugin->info.publics_num)
dvander@176
   129
		{
dvander@176
   130
			return NULL;
dvander@176
   131
		}
dvander@176
   132
		pFunc = m_pub_funcs[func_id];
dvander@176
   133
		if (!pFunc)
dvander@176
   134
		{
dvander@176
   135
			pFunc = g_PluginMngr.GetFunctionFromPool(save, this);
dvander@176
   136
			m_pub_funcs[func_id] = pFunc;
dvander@176
   137
		}
dvander@176
   138
	} else {
dvander@176
   139
		func_id >>= 1;
dvander@176
   140
		unsigned int index;
dvander@176
   141
		if (!g_pVM->FunctionLookup(m_ctx_current.ctx, func_id, &index))
dvander@176
   142
		{
dvander@176
   143
			return NULL;
dvander@176
   144
		}
dvander@176
   145
		pFunc = m_priv_funcs[func_id];
dvander@176
   146
		if (!pFunc)
dvander@176
   147
		{
dvander@176
   148
			pFunc = g_PluginMngr.GetFunctionFromPool(save, this);
dvander@176
   149
			m_priv_funcs[func_id] = pFunc;
dvander@176
   150
		}
dvander@176
   151
	}
dvander@176
   152
dvander@176
   153
	return pFunc;
dvander@176
   154
}
dvander@176
   155
dvander@176
   156
IPluginFunction *CPlugin::GetFunctionByName(const char *public_name)
dvander@176
   157
{
dvander@176
   158
	uint32_t index;
dvander@176
   159
	IPluginContext *base = m_ctx_current.base;
dvander@176
   160
dvander@176
   161
	if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE)
dvander@176
   162
	{
dvander@176
   163
		return NULL;
dvander@176
   164
	}
dvander@176
   165
dvander@176
   166
	CFunction *pFunc = m_pub_funcs[index];
dvander@176
   167
	if (!pFunc)
dvander@176
   168
	{
dvander@176
   169
		sp_public_t *pub = NULL;
dvander@176
   170
		base->GetPublicByIndex(index, &pub);
dvander@176
   171
		if (pub)
dvander@176
   172
		{
dvander@176
   173
			pFunc = g_PluginMngr.GetFunctionFromPool(pub->funcid, this);
dvander@176
   174
			m_pub_funcs[index] = pFunc;
dvander@176
   175
		}
dvander@176
   176
	}
dvander@176
   177
dvander@176
   178
	return pFunc;
dvander@176
   179
}
dvander@176
   180
dvander@173
   181
void CPlugin::UpdateInfo()
dvander@173
   182
{
dvander@173
   183
	/* Now grab the info */
dvander@173
   184
	uint32_t idx;
dvander@173
   185
	IPluginContext *base = GetBaseContext();
dvander@173
   186
	int err = base->FindPubvarByName("myinfo", &idx);
dvander@173
   187
dvander@173
   188
	if (err == SP_ERROR_NONE)
dvander@173
   189
	{
dvander@173
   190
		struct sm_plugininfo_c_t
dvander@173
   191
		{
dvander@173
   192
			cell_t name;
dvander@173
   193
			cell_t description;
dvander@173
   194
			cell_t author;
dvander@173
   195
			cell_t version;
dvander@173
   196
			cell_t url;
dvander@173
   197
		};
dvander@173
   198
		sm_plugininfo_c_t *cinfo;
dvander@173
   199
		cell_t local_addr;
dvander@173
   200
dvander@173
   201
		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&cinfo);
dvander@173
   202
		base->LocalToString(cinfo->name, (char **)&m_info.name);
dvander@173
   203
		base->LocalToString(cinfo->description, (char **)&m_info.description);
dvander@173
   204
		base->LocalToString(cinfo->author, (char **)&m_info.author);
dvander@173
   205
		base->LocalToString(cinfo->url, (char **)&m_info.url);
dvander@173
   206
		base->LocalToString(cinfo->version, (char **)&m_info.version);
dvander@173
   207
	}
dvander@173
   208
dvander@173
   209
	m_info.author = m_info.author ? m_info.author : "";
dvander@173
   210
	m_info.description = m_info.description ? m_info.description : "";
dvander@173
   211
	m_info.name = m_info.name ? m_info.name : "";
dvander@173
   212
	m_info.url = m_info.url ? m_info.url : "";
dvander@173
   213
	m_info.version = m_info.version ? m_info.version : "";
dvander@173
   214
}
dvander@173
   215
dvander@173
   216
const sp_plugin_t *CPlugin::GetPluginStructure() const
dvander@173
   217
{
dvander@173
   218
	return m_plugin;
dvander@173
   219
}
dvander@173
   220
dvander@173
   221
IPluginContext *CPlugin::GetBaseContext() const
dvander@173
   222
{
dvander@173
   223
	return m_ctx_current.base;
dvander@173
   224
}
dvander@173
   225
dvander@173
   226
sp_context_t *CPlugin::GetContext() const
dvander@173
   227
{
dvander@173
   228
	return m_ctx_current.ctx;
dvander@173
   229
}
dvander@173
   230
dvander@173
   231
const char *CPlugin::GetFilename() const
dvander@173
   232
{
dvander@173
   233
	return m_filename;
dvander@173
   234
}
dvander@173
   235
dvander@174
   236
PluginType CPlugin::GetType() const
dvander@173
   237
{
dvander@174
   238
	return m_type;
dvander@173
   239
}
dvander@173
   240
dvander@173
   241
const sm_plugininfo_t *CPlugin::GetPublicInfo() const
dvander@173
   242
{
dvander@173
   243
	return &m_info;
dvander@173
   244
}
dvander@173
   245
dvander@173
   246
unsigned int CPlugin::GetSerial() const
dvander@173
   247
{
dvander@173
   248
	return m_serial;
dvander@173
   249
}
dvander@173
   250
dvander@173
   251
PluginStatus CPlugin::GetStatus() const
dvander@173
   252
{
dvander@173
   253
	return m_status;
dvander@173
   254
}
dvander@173
   255
dvander@173
   256
bool CPlugin::IsDebugging() const
dvander@173
   257
{
dvander@173
   258
	return m_debugging;
dvander@173
   259
}
dvander@173
   260
dvander@173
   261
bool CPlugin::SetPauseState(bool paused)
dvander@173
   262
{
dvander@173
   263
	if (paused && GetStatus() != Plugin_Paused)
dvander@173
   264
	{
dvander@173
   265
		return false;
dvander@173
   266
	} else if (!paused && GetStatus() != Plugin_Running) {
dvander@173
   267
		return false;
dvander@173
   268
	}
dvander@173
   269
	
dvander@173
   270
	/* :TODO: execute some forwards or some crap */
dvander@173
   271
dvander@173
   272
	return true;
dvander@173
   273
}
dvander@174
   274
dvander@174
   275
/*******************
dvander@174
   276
 * PLUGIN ITERATOR *
dvander@174
   277
 *******************/
dvander@174
   278
CPluginManager::CPluginIterator::CPluginIterator(List<IPlugin *> *_mylist)
dvander@174
   279
{
dvander@174
   280
	mylist = _mylist;
dvander@174
   281
}
dvander@174
   282
dvander@174
   283
IPlugin *CPluginManager::CPluginIterator::GetPlugin()
dvander@174
   284
{
dvander@174
   285
	return (*current);
dvander@174
   286
}
dvander@174
   287
dvander@174
   288
bool CPluginManager::CPluginIterator::MorePlugins()
dvander@174
   289
{
dvander@174
   290
	return (current != mylist->end());
dvander@174
   291
}
dvander@174
   292
dvander@174
   293
void CPluginManager::CPluginIterator::NextPlugin()
dvander@174
   294
{
dvander@174
   295
	current++;
dvander@174
   296
}
dvander@174
   297
dvander@174
   298
void CPluginManager::CPluginIterator::Release()
dvander@174
   299
{
dvander@174
   300
	g_PluginMngr.ReleaseIterator(this);
dvander@174
   301
}
dvander@174
   302
dvander@174
   303
CPluginManager::CPluginIterator::~CPluginIterator()
dvander@174
   304
{
dvander@174
   305
}
dvander@174
   306
dvander@174
   307
void CPluginManager::CPluginIterator::Reset()
dvander@174
   308
{
dvander@174
   309
	current = mylist->begin();
dvander@174
   310
}
dvander@174
   311
dvander@174
   312
/******************
dvander@174
   313
 * PLUGIN MANAGER *
dvander@174
   314
 ******************/
dvander@174
   315
dvander@174
   316
IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max)
dvander@174
   317
{
dvander@174
   318
	CPlugin *pPlugin = CPlugin::CreatePlugin(path, debug, type, error, err_max);
dvander@174
   319
dvander@174
   320
	if (!pPlugin)
dvander@174
   321
	{
dvander@174
   322
		return NULL;
dvander@174
   323
	}
dvander@174
   324
dvander@174
   325
	m_plugins.push_back(pPlugin);
dvander@174
   326
dvander@174
   327
	List<IPluginsListener *>::iterator iter;
dvander@174
   328
	IPluginsListener *pListener;
dvander@174
   329
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@174
   330
	{
dvander@174
   331
		pListener = (*iter);
dvander@174
   332
		pListener->OnPluginCreated(pPlugin);
dvander@174
   333
	}
dvander@174
   334
dvander@174
   335
	/* :TODO: a lot more... */
dvander@174
   336
dvander@174
   337
	return pPlugin;
dvander@174
   338
}
dvander@174
   339
dvander@174
   340
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
dvander@174
   341
{
dvander@174
   342
	CPlugin *pPlugin = (CPlugin *)plugin;
dvander@174
   343
dvander@174
   344
	/* :TODO: More */
dvander@174
   345
dvander@174
   346
	List<IPluginsListener *>::iterator iter;
dvander@174
   347
	IPluginsListener *pListener;
dvander@174
   348
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@174
   349
	{
dvander@174
   350
		pListener = (*iter);
dvander@174
   351
		pListener->OnPluginDestroyed(pPlugin);
dvander@174
   352
	}
dvander@176
   353
	
dvander@176
   354
	if (pPlugin->m_pub_funcs)
dvander@176
   355
	{
dvander@176
   356
		for (uint32_t i=0; i<pPlugin->m_plugin->info.publics_num; i++)
dvander@176
   357
		{
dvander@176
   358
			delete pPlugin->m_pub_funcs[i];
dvander@176
   359
		}
dvander@176
   360
		delete [] pPlugin->m_pub_funcs;
dvander@176
   361
		pPlugin->m_pub_funcs = NULL;
dvander@176
   362
	}
dvander@176
   363
dvander@176
   364
	if (pPlugin->m_priv_funcs)
dvander@176
   365
	{
dvander@176
   366
		for (unsigned int i=0; i<pPlugin->m_funcsnum; i++)
dvander@176
   367
		{
dvander@176
   368
			delete pPlugin->m_priv_funcs[i];
dvander@176
   369
		}
dvander@176
   370
		delete [] pPlugin->m_priv_funcs;
dvander@176
   371
		pPlugin->m_priv_funcs = NULL;
dvander@176
   372
	}
dvander@174
   373
dvander@174
   374
	if (pPlugin->m_ctx_current.base)
dvander@174
   375
	{
dvander@174
   376
		g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_current.base);
dvander@174
   377
	}
dvander@174
   378
	if (pPlugin->m_ctx_backup.base)
dvander@174
   379
	{
dvander@174
   380
		g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_backup.base);
dvander@174
   381
	}
dvander@174
   382
	if (pPlugin->m_ctx_current.ctx)
dvander@174
   383
	{
dvander@174
   384
		pPlugin->m_ctx_current.ctx->vmbase->FreeContext(pPlugin->m_ctx_current.ctx);
dvander@174
   385
	}
dvander@174
   386
	if (pPlugin->m_ctx_backup.ctx)
dvander@174
   387
	{
dvander@174
   388
		pPlugin->m_ctx_backup.ctx->vmbase->FreeContext(pPlugin->m_ctx_backup.ctx);
dvander@174
   389
	}
dvander@174
   390
dvander@174
   391
	g_pSourcePawn->FreeFromMemory(pPlugin->m_plugin);
dvander@174
   392
dvander@174
   393
	delete pPlugin;
dvander@174
   394
dvander@174
   395
	return true;
dvander@174
   396
}
dvander@174
   397
dvander@174
   398
IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx)
dvander@174
   399
{
dvander@174
   400
	IPlugin *pl = (IPlugin *)ctx->user[SM_CONTEXTVAR_MYSELF];
dvander@174
   401
	return pl;
dvander@174
   402
}
dvander@174
   403
dvander@174
   404
unsigned int CPluginManager::GetPluginCount()
dvander@174
   405
{
dvander@174
   406
	return m_plugins.size();
dvander@174
   407
}
dvander@174
   408
dvander@174
   409
void CPluginManager::AddPluginsListener(IPluginsListener *listener)
dvander@174
   410
{
dvander@174
   411
	m_listeners.push_back(listener);
dvander@174
   412
}
dvander@174
   413
dvander@174
   414
void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
dvander@174
   415
{
dvander@174
   416
	m_listeners.remove(listener);
dvander@174
   417
}
dvander@174
   418
dvander@174
   419
IPluginIterator *CPluginManager::GetPluginIterator()
dvander@174
   420
{
dvander@174
   421
	if (m_iters.empty())
dvander@174
   422
	{
dvander@174
   423
		return new CPluginIterator(&m_plugins);
dvander@174
   424
	} else {
dvander@174
   425
		CPluginIterator *iter = m_iters.front();
dvander@174
   426
		m_iters.pop();
dvander@174
   427
		return iter;
dvander@174
   428
	}
dvander@174
   429
}
dvander@174
   430
dvander@174
   431
void CPluginManager::ReleaseIterator(CPluginIterator *iter)
dvander@174
   432
{
dvander@174
   433
	m_iters.push(iter);
dvander@174
   434
}
dvander@176
   435
dvander@176
   436
void CPluginManager::ReleaseFunctionToPool(CFunction *func)
dvander@176
   437
{
dvander@176
   438
	m_funcpool.push(func);
dvander@176
   439
}
dvander@176
   440
dvander@176
   441
CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin)
dvander@176
   442
{
dvander@176
   443
	if (m_funcpool.empty())
dvander@176
   444
	{
dvander@176
   445
		return new CFunction(f, plugin);
dvander@176
   446
	} else {
dvander@176
   447
		CFunction *func = m_funcpool.front();
dvander@176
   448
		m_funcpool.pop();
dvander@176
   449
		func->Set(f, plugin);
dvander@176
   450
		return func;
dvander@176
   451
	}
dvander@176
   452
}
dvander@176
   453
dvander@176
   454
CPluginManager::~CPluginManager()
dvander@176
   455
{
dvander@176
   456
	//:TODO: we need a good way to free what we're holding
dvander@176
   457
}