core/systems/PluginSys.h
author David Anderson <dvander@alliedmods.net>
Fri Dec 15 13:53:58 2006 +0000 (2006-12-15)
changeset 213 2bec1ff85d06
parent 211 4c77142eaf36
child 220 73d3fcf9bbd1
permissions -rw-r--r--
added second pass function
     1 #ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
     2 #define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
     3 
     4 #include <time.h>
     5 #include <IPluginSys.h>
     6 #include <sh_list.h>
     7 #include <sh_stack.h>
     8 #include "sm_globals.h"
     9 #include "CFunction.h"
    10 #include "PluginInfoDatabase.h"
    11 #include "sm_trie.h"
    12 
    13 using namespace SourceHook;
    14 
    15 /**
    16  * NOTES:
    17  *
    18  *  Currently this system needs a lot of work but it's good skeletally.  Plugin creation 
    19  * is done without actually compiling anything.  This is done by Load functions in the 
    20  * manager.  This will need a rewrite when we add context switching.
    21  *
    22  *  The plugin object itself has a few things to note.  The most important is that it stores
    23  * a table of function objects.  The manager marshals allocation and freeing of these objects.
    24  * The plugin object can be in erroneous states, they are:
    25  *   Plugin_Error   --> Some error occurred any time during or after compilation.
    26  *						This error can be cleared since the plugin itself is valid.
    27  *						However, the state itself being set prevents any runtime action.
    28  *   Plugin_BadLoad	--> The plugin failed to load entirely and nothing can be done to save it.
    29  *
    30  *  If a plugin fails to load externally, it is never added to the internal tracker.  However, 
    31  * plugins that failed to load from the internal loading mechanism are always tracked.  This 
    32  * allows users to see which automatically loaded plugins failed, and makes the interface a bit
    33  * more flexible.
    34  *
    35  *  Once a plugin is compiled, it sets its own state to Plugin_Created.  This state is still invalid
    36  * for execution.  SourceMod is a two pass system, and even though the second pass is not implemented
    37  * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass.  When
    38  * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
    39  *
    40  *  The two pass loading mechanism is described below.  Modules/natives are not implemented yet.
    41  * PASS ONE: All loadable plugins are found and have the following steps performed:
    42  *			 1.  Loading and compilation is attempted.
    43  *			 2.  If successful, all natives from Core are added.
    44  *			 3.  OnPluginLoad() is called.
    45  *			 4.  If failed, any user natives are scrapped and the process halts here.
    46  *			 5.  If successful, the plugin is ready for Pass 2.
    47  * INTERMEDIATE:
    48  *			 1.  All forced modules are loaded.
    49  * PASS TWO: All loaded plugins are found and have these steps performed:
    50  *			 1. Any modules referenced in the plugin that are not already loaded, are loaded.
    51  *			 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
    52  *			 3. If any natives are unresolved, check if they are found in the user-natives pool.
    53  *			 4. If yes, load succeeds.  If not, natives are passed through a native acceptance filter.
    54  *			 5. If the filter fails, the plugin is marked as failed.
    55  *			 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
    56  *			    Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
    57  * PASS THREE (not a real pass):
    58  *			 7. Once all plugins are deemed to be loaded, OnPluginInit() is called
    59  */
    60 
    61 #define SM_CONTEXTVAR_MYSELF	0
    62 
    63 struct ContextPair
    64 {
    65 	ContextPair() : base(NULL), ctx(NULL), co(NULL)
    66 	{
    67 	};
    68 	IPluginContext *base;
    69 	sp_context_t *ctx;
    70 	ICompilation *co;
    71 	IVirtualMachine *vm;
    72 };
    73 
    74 class CPlugin : public IPlugin
    75 {
    76 	friend class CPluginManager;
    77 	friend class CFunction;
    78 public:
    79 	CPlugin(const char *file);
    80 	~CPlugin();
    81 public:
    82 	virtual PluginType GetType() const;
    83 	virtual SourcePawn::IPluginContext *GetBaseContext() const;
    84 	virtual sp_context_t *GetContext() const;
    85 	virtual const sm_plugininfo_t *GetPublicInfo() const;
    86 	virtual const char *GetFilename() const;
    87 	virtual bool IsDebugging() const;
    88 	virtual PluginStatus GetStatus() const;
    89 	virtual bool SetPauseState(bool paused);
    90 	virtual unsigned int GetSerial() const;
    91 	virtual const sp_plugin_t *GetPluginStructure() const;
    92 	virtual IPluginFunction *GetFunctionByName(const char *public_name);
    93 	virtual IPluginFunction *GetFunctionById(funcid_t func_id);
    94 public:
    95 	/**
    96 	 * Creates a plugin object with default values.
    97 	 *   If an error buffer is specified, and an error occurs, the error will be copied to the buffer
    98 	 * and NULL will be returned.
    99 	 *   If an error buffer is not specified, the error will be copied to an internal buffer and 
   100 	 * a valid (but error-stated) CPlugin will be returned.
   101 	 */
   102 	static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
   103 public:
   104 	/**
   105 	 * Starts the initial compilation of a plugin.
   106 	 * Returns false if another compilation exists or there is a current context set.
   107 	 */
   108 	ICompilation *StartMyCompile(IVirtualMachine *vm);
   109 	/** 
   110 	 * Finalizes a compilation.  If error buffer is NULL, the error is saved locally.
   111 	 */
   112 	bool FinishMyCompile(char *error, size_t maxlength);
   113 	void CancelMyCompile();
   114 	/**
   115 	 * Sets an error state on the plugin
   116 	 */
   117 	void SetErrorState(PluginStatus status, const char *error_fmt, ...);
   118 
   119 	/**
   120 	 * Calls the OnPluginLoad function, and sets any failed states if necessary.
   121 	 * NOTE: Valid pre-states are: Plugin_Created
   122 	 * If validated, plugin state is changed to Plugin_Loaded
   123 	 *
   124 	 * If the error buffer is NULL, the error message is cached locally.
   125 	 */
   126 	bool Call_AskPluginLoad(char *error, size_t maxlength);
   127 
   128 	/**
   129 	 * Calls the OnPluginInit function.
   130 	 * NOTE: Valid pre-states are: Plugin_Created
   131 	 * NOTE: Pre-state will be changed to Plugin_Running
   132 	 */
   133 	void Call_OnPluginInit();
   134 public:
   135 	time_t HasUpdatedFile();
   136 protected:
   137 	void UpdateInfo();
   138 private:
   139 	ContextPair m_ctx;
   140 	PluginType m_type;
   141 	char m_filename[PLATFORM_MAX_PATH+1];
   142 	PluginStatus m_status;
   143 	unsigned int m_serial;
   144 	sm_plugininfo_t m_info;
   145 	sp_plugin_t *m_plugin;
   146 	unsigned int m_funcsnum;
   147 	CFunction **m_priv_funcs;
   148 	CFunction **m_pub_funcs;
   149 	char m_errormsg[256];
   150 	time_t m_LastAccess;
   151 };
   152 
   153 class CPluginManager : public IPluginManager
   154 {
   155 	friend class CPlugin;
   156 public:
   157 	CPluginManager();
   158 	~CPluginManager();
   159 public:
   160 	/* Implements iterator class */
   161 	class CPluginIterator : public IPluginIterator
   162 	{
   163 	public:
   164 		CPluginIterator(List<CPlugin *> *mylist);
   165 		virtual ~CPluginIterator();
   166 		virtual bool MorePlugins();
   167 		virtual IPlugin *GetPlugin();
   168 		virtual void NextPlugin();
   169 		virtual void Release();
   170 	public:
   171 		void Reset();
   172 	private:
   173 		List<CPlugin *> *mylist;
   174 		List<CPlugin *>::iterator current;
   175 	};
   176 	friend class CPluginManager::CPluginIterator;
   177 public: //IPluginManager
   178 	virtual IPlugin *LoadPlugin(const char *path, 
   179 								bool debug,
   180 								PluginType type,
   181 								char error[],
   182 								size_t err_max);
   183 	virtual bool UnloadPlugin(IPlugin *plugin);
   184 	virtual IPlugin *FindPluginByContext(const sp_context_t *ctx);
   185 	virtual unsigned int GetPluginCount();
   186 	virtual IPluginIterator *GetPluginIterator();
   187 	virtual void AddPluginsListener(IPluginsListener *listener);
   188 	virtual void RemovePluginsListener(IPluginsListener *listener);
   189 public:
   190 	/**
   191 	 * Loads all plugins not yet loaded
   192 	 */
   193 	void LoadAll_FirstPass(const char *config, const char *basedir);
   194 
   195 	/**
   196 	 * Runs the second loading pass for all plugins
   197 	 */
   198 	void LoadAll_SecondPass();
   199 
   200 	/**
   201 	 * Tests a plugin file mask against a local folder.
   202 	 * The alias is searched backwards from localdir - i.e., given this input:
   203 	 *   csdm/ban        csdm/ban
   204 	 *   ban             csdm/ban
   205 	 *   csdm/ban        optional/csdm/ban
   206 	 * All of these will return true for an alias match.  
   207 	 * Wildcards are allowed in the filename.
   208 	 */
   209 	bool TestAliasMatch(const char *alias, const char *localdir);
   210 
   211 	/**
   212 	 * Registers natives in core itself ONLY.
   213 	 */
   214 	void RegisterGlobalNatives(sp_nativeinfo_t *info[]);
   215 
   216 	/** 
   217 	 * Returns whether anything loaded will be a late load.
   218 	 */
   219 	bool IsLateLoadTime();
   220 private:
   221 	/**
   222 	 * Recursively loads all plugins in the given directory.
   223 	 */
   224 	void LoadPluginsFromDir(const char *basedir, const char *localdir);
   225 
   226 	/**
   227 	 * Loads a plugin using automatic information.
   228 	 * The file must be relative to the plugins folder.
   229 	 */
   230 	void LoadAutoPlugin(const char *file);
   231 
   232 	/**
   233 	 * Adds a plugin object.  This is wrapped by LoadPlugin functions.
   234 	 */
   235 	void AddPlugin(CPlugin *pPlugin);
   236 
   237 	/**
   238 	 * Runs the second loading pass on a plugin.
   239 	 */
   240 	void RunSecondPass(CPlugin *pPlugin);
   241 
   242 	/**
   243 	 * Adds any globally registered natives to a plugin
   244 	 */
   245 	void AddCoreNativesToPlugin(CPlugin *pPlugin);
   246 protected:
   247 	/**
   248 	 * Caching internal objects
   249 	 */
   250 	void ReleaseIterator(CPluginIterator *iter);
   251 	CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin);
   252 	void ReleaseFunctionToPool(CFunction *func);
   253 private:
   254 	List<IPluginsListener *> m_listeners;
   255 	List<CPlugin *> m_plugins;
   256 	List<sp_nativeinfo_t *> m_natives;
   257 	CStack<CPluginManager::CPluginIterator *> m_iters;
   258 	CStack<CFunction *> m_funcpool;
   259 	CPluginInfoDatabase m_PluginInfo;
   260 	Trie *m_LoadLookup;
   261 	bool m_AllPluginsLoaded;
   262 };
   263 
   264 extern CPluginManager g_PluginSys;
   265 
   266 #endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_