Landed sourcepawn-1.2. The big changes:
1) JIT compilation/optimization now occurs per-function, and only when functions are first used. We're now officially a whole-method JIT rather than an AOT compiler (albiet, still a simple JIT). This has two implications: Functions are now much better abstracted internally, and loading a plugin is now much less expensive. If a function contains calls to other functions, THOSE functions are only compiled when they're invoked as well.
2) I've removed debug mode. We always show full backtraces now, as there was a very cheap way to implement this which really cleaned up everything. This is great for a number of reasons -- there's less code, the JIT is better designed, we don't need to relocate debug tables, and best of all we no longer have to tell users to enable debug mode at their own expense.
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
33 #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
38 #include <IPluginSys.h>
39 #include <IHandleSys.h>
40 #include <IForwardSys.h>
43 #include <sh_vector.h>
44 #include <sh_string.h>
45 #include "sm_globals.h"
46 #include "PluginInfoDatabase.h"
48 #include "sourcemod.h"
49 #include <IRootConsoleMenu.h>
50 #if defined ORANGEBOX_BUILD
51 #include "convar_sm_ob.h"
53 #include "convar_sm.h"
55 #include "ITranslator.h"
56 #include "NativeOwner.h"
59 using namespace SourceHook;
64 * UPDATE 2008-03-11: These comments are horribly out of date. They paint a good overall
65 * picture of how PluginSys works, but things like dependencies and fake natives have
66 * complicated things quite a bit.
68 * Currently this system needs a lot of work but it's good skeletally. Plugin creation
69 * is done without actually compiling anything. This is done by Load functions in the
70 * manager. This will need a rewrite when we add context switching.
72 * The plugin object itself has a few things to note. The most important is that it stores
73 * a table of function objects. The manager marshals allocation and freeing of these objects.
74 * The plugin object can be in erroneous states, they are:
75 * Plugin_Error --> Some error occurred any time during or after compilation.
76 * This error can be cleared since the plugin itself is valid.
77 * However, the state itself being set prevents any runtime action.
78 * Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it.
80 * If a plugin fails to load externally, it is never added to the internal tracker. However,
81 * plugins that failed to load from the internal loading mechanism are always tracked. This
82 * allows users to see which automatically loaded plugins failed, and makes the interface a bit
85 * Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid
86 * for execution. SourceMod is a two pass system, and even though the second pass is not implemented
87 * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When
88 * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
90 * The two pass loading mechanism is described below. Modules/natives are not implemented yet.
91 * PASS ONE: All loadable plugins are found and have the following steps performed:
92 * 1. Loading and compilation is attempted.
93 * 2. If successful, all natives from Core are added.
94 * 3. OnPluginLoad() is called.
95 * 4. If failed, any user natives are scrapped and the process halts here.
96 * 5. If successful, the plugin is ready for Pass 2.
98 * 1. All forced modules are loaded.
99 * PASS TWO: All loaded plugins are found and have these steps performed:
100 * 1. Any modules referenced in the plugin that are not already loaded, are loaded.
101 * 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
102 * 3. If any natives are unresolved, check if they are found in the user-natives pool.
103 * 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter.
104 * 5. If the filter fails, the plugin is marked as failed.
105 * 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
106 * Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
107 * PASS THREE (not a real pass):
108 * 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
114 LoadRes_AlreadyLoaded,
132 friend class CPluginManager;
133 friend class CFunction;
135 CPlugin(const char *file);
138 PluginType GetType();
139 SourcePawn::IPluginContext *GetBaseContext();
140 sp_context_t *GetContext();
141 void *GetPluginStructure();
142 const char *GetFilename();
144 PluginStatus GetStatus();
145 const sm_plugininfo_t *GetPublicInfo();
146 bool SetPauseState(bool paused);
147 unsigned int GetSerial();
148 IdentityToken_t *GetIdentity();
149 unsigned int CalcMemUsage();
150 bool SetProperty(const char *prop, void *ptr);
151 bool GetProperty(const char *prop, void **ptr, bool remove=false);
152 void DropEverything();
153 SourcePawn::IPluginRuntime *GetRuntime();
156 * Creates a plugin object with default values.
157 * If an error buffer is specified, and an error occurs, the error will be copied to the buffer
158 * and NULL will be returned.
159 * If an error buffer is not specified, the error will be copied to an internal buffer and
160 * a valid (but error-stated) CPlugin will be returned.
162 static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
166 * Sets an error state on the plugin
168 void SetErrorState(PluginStatus status, const char *error_fmt, ...);
171 * Initializes the plugin's identity information
176 * Calls the OnPluginLoad function, and sets any failed states if necessary.
177 * NOTE: Valid pre-states are: Plugin_Created
178 * NOTE: If validated, plugin state is changed to Plugin_Loaded
180 * If the error buffer is NULL, the error message is cached locally.
182 bool Call_AskPluginLoad(char *error, size_t maxlength);
185 * Calls the OnPluginStart function.
186 * NOTE: Valid pre-states are: Plugin_Created
187 * NOTE: Post-state will be Plugin_Running
189 void Call_OnPluginStart();
192 * Calls the OnPluginEnd function.
194 void Call_OnPluginEnd();
197 * Calls the OnAllPluginsLoaded function.
199 void Call_OnAllPluginsLoaded();
202 * Returns true if a plugin is usable.
207 * Get languages info.
209 IPhraseCollection *GetPhrases();
212 * Returns the modification time during last plugin load.
214 time_t GetTimeStamp();
217 * Returns the current modification time of the plugin file.
219 time_t GetFileTimeStamp();
222 * Returns true if the plugin was running, but is now invalid.
226 Handle_t GetMyHandle();
228 bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
229 void AddConfig(bool autoCreate, const char *cfg, const char *folder);
230 unsigned int GetConfigCount();
231 AutoConfig *GetConfig(unsigned int i);
232 inline void AddLibrary(const char *name)
234 m_Libraries.push_back(name);
236 void LibraryActions(bool dropping);
239 void SetTimeStamp(time_t t);
240 void DependencyDropped(CPlugin *pOwner);
243 char m_filename[PLATFORM_MAX_PATH];
244 PluginStatus m_status;
245 unsigned int m_serial;
246 sm_plugininfo_t m_info;
247 char m_errormsg[256];
249 IdentityToken_t *m_ident;
252 IPhraseCollection *m_pPhrases;
253 List<String> m_RequiredLibs;
254 List<String> m_Libraries;
256 bool m_FakeNativesMissing;
257 bool m_LibraryMissing;
258 CVector<AutoConfig *> m_configs;
259 bool m_bGotAllLoaded;
261 char m_DateTime[256];
262 IPluginRuntime *m_pRuntime;
263 IPluginContext *m_pContext;
266 class CPluginManager :
267 public IPluginManager,
268 public SMGlobalClass,
269 public IHandleTypeDispatch,
270 public IRootConsoleCommand
272 friend class CPlugin;
277 /* Implements iterator class */
278 class CPluginIterator : public IPluginIterator
281 CPluginIterator(List<CPlugin *> *mylist);
282 virtual ~CPluginIterator();
283 virtual bool MorePlugins();
284 virtual IPlugin *GetPlugin();
285 virtual void NextPlugin();
290 List<CPlugin *> *mylist;
291 List<CPlugin *>::iterator current;
293 friend class CPluginManager::CPluginIterator;
294 public: //IPluginManager
295 IPlugin *LoadPlugin(const char *path,
301 bool UnloadPlugin(IPlugin *plugin);
302 IPlugin *FindPluginByContext(const sp_context_t *ctx);
303 unsigned int GetPluginCount();
304 IPluginIterator *GetPluginIterator();
305 void AddPluginsListener(IPluginsListener *listener);
306 void RemovePluginsListener(IPluginsListener *listener);
307 public: //SMGlobalClass
308 void OnSourceModAllInitialized();
309 void OnSourceModShutdown();
310 public: //IHandleTypeDispatch
311 void OnHandleDestroy(HandleType_t type, void *object);
312 bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
313 public: //IRootConsoleCommand
314 void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
317 * Loads all plugins not yet loaded
319 void LoadAll_FirstPass(const char *config, const char *basedir);
322 * Runs the second loading pass for all plugins
324 void LoadAll_SecondPass();
327 * Tests a plugin file mask against a local folder.
328 * The alias is searched backwards from localdir - i.e., given this input:
331 * csdm/ban optional/csdm/ban
332 * All of these will return true for an alias match.
333 * Wildcards are allowed in the filename.
335 bool TestAliasMatch(const char *alias, const char *localdir);
338 * Returns whether anything loaded will be a late load.
340 bool IsLateLoadTime() const;
343 * Converts a Handle to an IPlugin if possible.
345 IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
348 * Finds a plugin based on its index. (starts on index 1)
350 CPlugin *GetPluginByOrder(int num);
352 int GetOrderOfPlugin(IPlugin *pl);
355 * Internal version of FindPluginByContext()
357 CPlugin *GetPluginByCtx(const sp_context_t *ctx);
360 * Gets status text for a status code
362 const char *GetStatusText(PluginStatus status);
365 * Reload or update plugins on level shutdown.
367 void ReloadOrUnloadPlugins();
370 * Add public functions from all running or paused
371 * plugins to the specified forward if the names match.
373 void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
376 * Iterates through plugins to call OnAllPluginsLoaded.
378 void AllPluginsLoaded();
380 CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
384 void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
386 bool LibraryExists(const char *lib);
388 bool ReloadPlugin(CPlugin *pl);
392 CPlugin *FindPluginByConsoleArg(const char *arg);
394 LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
396 void LoadAutoPlugin(const char *plugin);
399 * Recursively loads all plugins in the given directory.
401 void LoadPluginsFromDir(const char *basedir, const char *localdir);
404 * Adds a plugin object. This is wrapped by LoadPlugin functions.
406 void AddPlugin(CPlugin *pPlugin);
409 * Runs the second loading pass on a plugin.
411 bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
414 * Runs an extension pass on a plugin.
416 bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
419 * Manages required natives.
421 bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
423 void _SetPauseState(CPlugin *pPlugin, bool pause);
426 * Caching internal objects
428 void ReleaseIterator(CPluginIterator *iter);
430 inline IdentityToken_t *GetIdentity()
435 void TryRefreshDependencies(CPlugin *pOther);
437 List<IPluginsListener *> m_listeners;
438 List<CPlugin *> m_plugins;
439 CStack<CPluginManager::CPluginIterator *> m_iters;
440 CPluginInfoDatabase m_PluginInfo;
442 bool m_AllPluginsLoaded;
443 IdentityToken_t *m_MyIdent;
445 /* Dynamic native stuff */
446 List<FakeNative *> m_Natives;
448 bool m_LoadingLocked;
451 extern CPluginManager g_PluginSys;
453 #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_