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