mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 21:23:04 +01:00
283 lines
11 KiB
C++
283 lines
11 KiB
C++
/*
|
|
* PROGRAM: JRD Plugin Manager Class
|
|
* MODULE: plugin_manager.h
|
|
* DESCRIPTION: Manages dynamically loadable engine plugins
|
|
*
|
|
* The contents of this file are subject to the Initial
|
|
* Developer's Public License Version 1.0 (the "License");
|
|
* you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
|
*
|
|
* Software distributed under the License is distributed AS IS,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing rights
|
|
* and limitations under the License.
|
|
*
|
|
* The Original Code was created by John Bellardo
|
|
* for the Firebird Open Source RDBMS project.
|
|
*
|
|
* Copyright (c) 2002 John Bellardo <bellardo@cs.ucsd.edu>
|
|
* and all contributors signed below.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
#ifndef JRD_PLUGIN_MANAGER_H
|
|
#define JRD_PLUGIN_MANAGER_H
|
|
|
|
#include "../jrd/os/mod_loader.h"
|
|
#include "../common/classes/fb_string.h"
|
|
#include "../common/classes/fb_pair.h"
|
|
#include "../common/classes/objects_array.h"
|
|
#include "../common/classes/init.h"
|
|
|
|
/** The PluginManager class provides a platform independent interface for
|
|
* loading, unloading, and accessing symbols in dynamically loadable
|
|
* libraries. The PluginManager has the ability to restrict module
|
|
* loading to specific search paths, ignore certain modules in a
|
|
* search path, and automatically load all the modules in the search
|
|
* paths.
|
|
*
|
|
* In addition, the PluginManager provides for a single, unified way of
|
|
* handling loadable modules. This is to prevent an explosion of
|
|
* separate PluginManager objects as the engine grows. The pre-existing
|
|
* subsystems that used loadable modules (for example: intl, flu) will still
|
|
* have their own PluginManager instance. But other subsystems should try
|
|
* to stay within the boundries of the new, more generic, plugin interface.
|
|
*
|
|
* This interface is divided into two parts: enginge and plugin. The engine
|
|
* interface consists of a single function: load_engine_plugins. This
|
|
* function searches through the plugin directory (XXX) and loads all the
|
|
* plugins it finds. After loading it calls the plugin's "register" function.
|
|
* This function has the signature "extern "C" void register_plugin(void *parm)".
|
|
* This function is, in turn, responsible for registering the plugin with the
|
|
* various parts of the engine as required. To do this each engine subsystem
|
|
* that wants to make use of plugins needs to provide a "registration" function.
|
|
* This function can take any parameters as necessary to establish the link between
|
|
* the plugin and the subsystem, but it must accept the void* parameter given to
|
|
* the plugin's register function. This parameter is a Plugin pointer which allows
|
|
* the subsystem to access the plugin's symbols.
|
|
*
|
|
* The exact semantics of the function the plugin needs to call varies by
|
|
* subsystem. Please refer to the subsystem documentation for details.
|
|
**/
|
|
|
|
class PluginManager : public Firebird::PermanentStorage
|
|
{
|
|
static const char *ENGINE_PLUGIN_DIR;
|
|
static const char *ENGINE_PLUGIN_REGISTRATION_ENTRYPOINT;
|
|
|
|
public:
|
|
static void load_engine_plugins();
|
|
static Firebird::InitInstance<PluginManager> enginePluginManager;
|
|
|
|
class iterator;
|
|
|
|
private:
|
|
/** PluginManager::Module is an internal class that encapsulates
|
|
* the reference counter, module array, module
|
|
* name, and symbol lookup function of a loaded module. This class
|
|
* is expected to be subclassed to provide module specific functionality.
|
|
* For example, a builtin module class may load modules that have been statically
|
|
* linked in with the engine, while a dynamic module class might handle modules
|
|
* found in OS specific dynamic libraries.
|
|
**/
|
|
class Module
|
|
{
|
|
public:
|
|
/// The constructor requires the name of the module. The initial reference count
|
|
/// is 1, to indicate that the PluginManager itself has a reference. This is
|
|
/// verified in debug builds in the PluginManager destructor.
|
|
Module(MemoryPool& p, const Firebird::PathName& nameL)
|
|
: refCnt(1), module_name(p, nameL), prev(0), next(0) {}
|
|
/// The destructor is responsible for removing the module from the array.
|
|
virtual ~Module();
|
|
/// acquire indicates the interest of a particular piece of engine code in
|
|
/// the loadable module. Currently that interest is tracked via a reference
|
|
/// counter.
|
|
void acquire() { refCnt++; }
|
|
/// release indicates the end of interest in a modules. Each call to acquire
|
|
/// must be balanced with a call to release.
|
|
void release() { refCnt--; }
|
|
/// Accessor function that returns the name of the module
|
|
const Firebird::PathName& name() const { return module_name; }
|
|
/// lookupSymbol searches through a module's symbol table and attempts to
|
|
/// locate the given symbol name. If successful it returns a pointer to
|
|
/// the symbol's location in the current address space. If the symbol can't
|
|
/// be found it returns 0.
|
|
virtual void *lookupSymbol(const Firebird::string&) = 0;
|
|
|
|
private:
|
|
friend class PluginManager;
|
|
friend class iterator;
|
|
int refCnt;
|
|
Firebird::PathName module_name;
|
|
Module **prev;
|
|
Module *next;
|
|
|
|
/// unload_module is used called by the destructor when the module
|
|
/// represented by this module object needs to be physically unloaded
|
|
/// from memory.
|
|
virtual void unload_module() {}
|
|
};
|
|
|
|
public:
|
|
friend class Plugin;
|
|
friend class iterator;
|
|
|
|
explicit PluginManager(MemoryPool& p) : Firebird::PermanentStorage(p),
|
|
moduleList(0), searchPaths(getPool()), ignoreModules(getPool()) {}
|
|
~PluginManager();
|
|
|
|
/** The Plugin class encapsulates the various operations that are available
|
|
* after a plugin has been located. The PluginManager returns instances
|
|
* of the Plugin class to the calling code to give that code access to
|
|
* the aforementioned operations. These operations include tracking the
|
|
* usage of a plugin, and locating symbols within the plugin. The Plugin
|
|
* class has a full contingent of constructors, assignment operators, and
|
|
* equality operators.
|
|
**/
|
|
class Plugin
|
|
{
|
|
public:
|
|
friend class PluginManager;
|
|
Plugin() : module(0) {}
|
|
Plugin(const Plugin& src) : module(src.module)
|
|
{
|
|
if (module)
|
|
module->acquire();
|
|
}
|
|
~Plugin()
|
|
{
|
|
if (module)
|
|
module->release();
|
|
}
|
|
const Plugin& operator=(const Plugin&);
|
|
bool operator ==(const Plugin &other) const
|
|
{ return module == other.module; }
|
|
bool operator !=(const Plugin &other) const
|
|
{ return module != other.module; }
|
|
/// Looks in the Plugin's symbol table for a symbol with the given name.
|
|
/// If the symbol exists a pointer to that symbol's location in the
|
|
/// current address space is returned. Otherwise NULL is returned.
|
|
void *lookupSymbol(const Firebird::string &sym)
|
|
{ return module ? module->lookupSymbol(sym) : 0; }
|
|
operator bool() { return module != 0; }
|
|
|
|
private:
|
|
friend class iterator;
|
|
Plugin(Module *mod) : module(mod)
|
|
{
|
|
if (module)
|
|
module->acquire();
|
|
}
|
|
|
|
Module *module;
|
|
};
|
|
|
|
/** The iterator class allows external code to iterate through all the plugins
|
|
* a plugin manager knows about. The iterator behaves like a traditional STL
|
|
* iterator.
|
|
**/
|
|
class iterator
|
|
{
|
|
public:
|
|
friend class PluginManager;
|
|
const iterator &operator++()
|
|
{
|
|
if (curr)
|
|
curr = curr->next;
|
|
return *this;
|
|
}
|
|
Plugin operator*()
|
|
{ return Plugin(curr); }
|
|
bool operator==(const iterator& cmp) const
|
|
{ return curr == cmp.curr; }
|
|
bool operator!=(const iterator& cmp) const
|
|
{ return curr != cmp.curr; }
|
|
operator bool() const { return curr != 0; }
|
|
const iterator &operator=(const iterator& other)
|
|
{ curr = other.curr; return *this; }
|
|
iterator(const iterator& other) : curr(other.curr) {}
|
|
|
|
private:
|
|
Module *curr;
|
|
|
|
iterator(Module *start = 0) : curr(start) {}
|
|
};
|
|
|
|
/// Searches for the plugin with the given name using the
|
|
/// preset search criteria.
|
|
Plugin findPlugin(const Firebird::PathName&);
|
|
/// Adds a path to the array of paths to be searched for a modules. The
|
|
/// second parameter indicates if the path is absolute, or relative to
|
|
/// the current working directory.
|
|
void addSearchPath(const Firebird::PathName&, bool = true);
|
|
/// Removes the given search path from the array of search paths. The path name
|
|
/// (1st parameter) and the relative indicator (2nd parameter) must exactly match
|
|
/// those passed in to addSearchPath.
|
|
void removeSearchPath(const Firebird::PathName&, bool = true);
|
|
/// Adds a module to the ignore list. Ignored modules are not loaded automatically
|
|
/// when a directory is scanned, but may be loaded manually via the findPlugin
|
|
/// function.
|
|
void addIgnoreModule(const Firebird::PathName &mod)
|
|
{ ignoreModules.push(mod); }
|
|
/// Loads all the plugins found in the current set of search paths, except those that
|
|
/// have been ignored. This function must be called after adding all the needed search paths,
|
|
/// and before iterating through the plugins.
|
|
void loadAllPlugins();
|
|
/// The traditional STL iterator end function. Returns an iterator that represents the
|
|
/// last element in the iteration.
|
|
iterator end() { return iterator(0); }
|
|
/// Returns an iterator set to the first element in the iteration set. That set
|
|
/// is the set of all plugins known to the PluginManager. This includes all plugins
|
|
/// found with the loadAllPluings and findPlugin functions.
|
|
iterator begin() { return iterator(moduleList); }
|
|
|
|
private:
|
|
typedef void (*engineRegistrationFuncType)(Plugin*);
|
|
typedef Firebird::Pair<Firebird::Left<Firebird::PathName, bool> > Path;
|
|
Module *moduleList;
|
|
Firebird::ObjectsArray<Path> searchPaths;
|
|
typedef Firebird::ObjectsArray<Path>::iterator spIterator;
|
|
Firebird::ObjectsArray<Firebird::PathName> ignoreModules;
|
|
|
|
Module *loadPluginModule(const Firebird::PathName& name);
|
|
Module *loadBuiltinModule(const Firebird::PathName& name);
|
|
|
|
class BuiltinModule : public Module
|
|
{
|
|
public:
|
|
BuiltinModule(MemoryPool& p, const Firebird::PathName& nameL)
|
|
: Module(p, nameL), symbols(p) {}
|
|
|
|
private:
|
|
typedef Firebird::Pair<Firebird::Left<Firebird::string, void*> > PMSymbol;
|
|
typedef Firebird::FirstKey<PMSymbol> PMSymbolKey;
|
|
typedef Firebird::SortedArray<PMSymbol,
|
|
Firebird::EmptyStorage<PMSymbol>,
|
|
Firebird::string, PMSymbolKey> PMSymbols;
|
|
PMSymbols symbols;
|
|
|
|
void *lookupSymbol(const Firebird::string&);
|
|
};
|
|
|
|
class PluginModule : public Module
|
|
{
|
|
public:
|
|
PluginModule(MemoryPool& p, const Firebird::PathName &nameL, ModuleLoader::Module *mod)
|
|
: Module(p, nameL), module(mod) {}
|
|
|
|
private:
|
|
ModuleLoader::Module *module;
|
|
|
|
void unload_module();
|
|
void *lookupSymbol(const Firebird::string&);
|
|
};
|
|
};
|
|
|
|
#endif // JRD_PLUGIN_MANAGER_H
|
|
|