You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
heartbeat/include/pils/plugin.h.in

724 lines
24 KiB

/*
* Copyright (C) 2000 Alan Robertson <alanr@unix.sh>
* This software licensed under the GNU LGPL.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef PILS_PLUGIN_H
# define PILS_PLUGIN_H
# include <ltdl.h>
/* Glib headers generate warnings - so we make them go away */
#define time FOOtime
#define index FOOindex
#include <glib.h>
#undef index
#undef time
/*****************************************************************************
* PILS - Universal Plugin and Interface loading system
*****************************************************************************
*
* An Overview of PILS...
*
* PILS is fairly general and reasonably interesting plugin loading system.
* We manage both plugins and their interfaces
*
* This plugin / interface management system is quite general, and should be
* directly usable by basically any project on any platform on which it runs
* - which should be many, since everything is build with automake
* and libtool.
*
* Some terminology...
*
* There are two basic kinds of objects we deal with here:
*
* Plugins: dynamically loaded chunks of code which implement one or more
* interfaces. The system treats all plugins as the same.
* In UNIX, these are dynamically loaded ".so" files.
*
* Interface: A set of functions which implement a particular capability
* (or interface)
* Generally interfaces are registered as part of a plugin.
* The system treats all interfaces of the same type the same.
* It is common to have exactly one interface inside of each plugin.
* In this case, the interface name should match the plugin name.
*
* Each interface implementation exports certain functions for its clients
* to use. We refer to these those "Ops". Every interface of the same type
* "imports" the same interfaces from its interface manager,
* and exports the same "Ops".
*
* Each interface implementation is provided certain interfaces which it
* imports when it from its interface manager when it is registered.
* We refer to these as "Imports". Every interface of a given type
* imports the same interfaces.
*
* The story with plugins is a little different...
*
* Every plugin exports a certain set of interfaces, regardless of what type
* of interfaces is implemented by it. These are described in the
* PILPluginOps structure.
*
* Every plugin imports a certain set of interfaces, regardless of what type
* of interfaces it may implement. These are described by the
* PILPluginImports structure.
*
* In the function parameters below, the following notation will
* sometimes appear:
*
* (OP) == Output Parameter - a parameter which is modified by the
* function being called
*
*
*****************************************************************************
*
* The basic structures we maintain about plugins are as follows:
*
* PILPlugin The data which represents a plugin.
* PILPluginType The data common to all plugins of a given type
* PILPluginUniv The set of all plugin types in the Universe
* (well... at least *this* universe)
*
* The basic structures we maintain about interfaces are as follows:
* PILInterface The data which represents a interface
* PILInterfaceType The data which is common to all
* interfaces of a given type
* PILPluginUniv The set of all interface types in the Universe
* (well... at least *this* universe)
*
* Regarding "Universe"s. It is our intent that a given program can deal
* with plugins in more than one universe. This might occur if you have two
* independent libraries each of which uses the plugin loading environment
* to manage their own independent interface components. There should be
* no restriction in creating a program which uses both of these libraries.
* At least that's what we hope ;-)
*
*
***************************************************************************
* SOME MORE DETAILS ABOUT PLUGINS...
***************************************************************************
*
* Going back to more detailed data structures about plugins...
*
* PILPluginImports The set of standard functions all plugins
* import.
* This includes:
* register_plugin()
* unregister_plugin()
* register_interface()
* unregister_interface()
* load_plugin()
* log() Preferred logging function
*
* PILPluginOps The set of standard operations all plugins
* export.
* This includes:
* pluginversion()
* pluginname()
* getdebuglevel()
* setdebuglevel()
* close() Prepare for unloading...
*
* Although we treat plugins pretty much the same, they are still
* categorized into "types" - one type per directory. These types
* generally correspond to interface types.
*
* One can only cause a plugin to be loaded - not a interface. But it is
* common to assume that loading a plugin named foo of type bar will
* cause a interface named foo of type bar to be registered. If one
* wants to implement automatic plugin loading in a given interface type,
* this assumption is necessary.
*
* The general way this works is...
*
* - A request is made to load a particular plugin of a particular type.
*
* - The plugin is loaded from the appropriate directory for plugins
* of that type.
*
* - The ml_plugin_init() function is called once when the plugin is
* loaded.
*
* The ml_plugin_init() function is passed a vector of functions which
* point to functions it can call to register itself, etc.
* (it's of type PILPluginImports)
*
* The ml_plugin_init function then uses this set of imported functions
* to register itself and its interfaces.
*
* The mechanism of registering a interface is largely the same for
* every interface. However, the semantics of registering a interfaces
* is determined by the interface manager for the particular type of
* interface being discussed.
*
***************************************************************************
* SOME MORE DETAILS ABOUT PLUGINS...
***************************************************************************
*
* There is only one built in type of interface. That's the Interface
* manager interface.
* The interface manager for the interface of type "InterfaceMgr",
* named "InterfaceMgr" inserts itself into the system in order
* to bootstrap things...
*
* When an attempt is made to register a interface of an unknown type,
* then the appropriate Interface manager is loaded automatically.
*
* The name of an interface manager determines the type of
* interface it manages.
*
* It handles requests for interfaces whose type is the same
* as its interface name. If the interface manager's interface name
* is foo, then it is the interface manager for all interfaces whose
* type is foo.
*
* Types associated with interfaces of type Interface
*
* PILInterfaceOps The set of interfaces that every interface
* manager exports
* PILInterfaceImports The set of interfaces which are supplied to
* (imported by) every interface of type
* Interface. (that is, every interface
* manager).
*
*****************************************************************************
*
* Each plugin has only one entry point which is exported directly, regardless
* of what kind of interface(s) it may implement...
*
* This entrypoint is named ml_plugin_init() {more or less - see below}
*
* The ml_plugin_init() function is called once when the plugin is loaded.
*
*
* All other function pointers are registered (exported) through parameters
* passed to ml_plugin_init()
*
* It is the purpose of the Ml_plugin_init() to register the plugin,
* and all the interfaces which this plugin implements. A pointer to
* the registration function is in the parameters which are passed
* to ml_plugin_init().
*
*****************************************************************************
*
* THINGS IN THIS DESIGN WHICH ARE PROBABLY BROKEN...
*
* It may also be the case that the plugin loading environment needs
* to be able to have some kind of user_data passed to it which it can
* also pass along to any interface ...
*
* Maybe this should be handled by a sort of global user_data registration
* structure, so globals can be passed to interfaces when they're registered.
*
* A sort of "user_data" registry. One for each interface type and one
* for each interface... Or maybe it could be even more flexible...
*
* This is all so that these nice pristene, beautiful concepts can come out
* and work well in the real world where interfaces need to interact with
* some kind of global system view, and with each other...
*
* Probably need some better way of managing interface versions, etc.
*
****************************************************************************
*/
/*
* If you want to use this funky export stuff, then you need to #define
* PIL_PLUGINTYPE and PIL_PLUGIN *before* including this file.
*
* The way to use this stuff is to declare your primary entry point this way:
*
* This example is for an plugin of type "auth" named "sha1"
*
* #define PIL_PLUGINTYPE auth
* #define PIL_PLUGIN sha1
* #include <upmls/PILPlugin.h>
*
* static const char* Ourpluginversion (void);
* static const char* Ourpluginname (void);
* static int Ourgetdebuglevel(void);
* static void Oursetdebuglevel(int);
* static void Ourclose (PILPlugin*);
*
* static struct PILPluginOps our_exported_plugin_operations =
* { Ourpluginversion,
* , Ourpluginname
* , Ourgetdebuglevel
* , Oursetdebuglevel
* , Ourclose
* };
*
* static const PILPluginImports* PluginOps;
* static PILPlugin* OurPlugin;
*
* // Our plugin initialization and registration function
* // It gets called when the plugin gets loaded.
* PIL_rc
* PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports)
* {
* PluginOps = imports;
* OurPlugin = us;
*
* // Register ourself as a plugin * /
* imports->register_plugin(us, &our_exported_plugin_operations);
*
* // Register our interfaces
* imports->register_interface(us, "interfacetype", "interfacename"
* // Be sure and define "OurExports" and OurImports
* // above...
* , &OurExports
* , &OurImports);
* // Repeat for all interfaces in this plugin...
*
* }
*
* Except for the PIL_PLUGINTYPE and the PIL_PLUGIN definitions, and changing
* the names of various static variables and functions, every single plugin is
* set up pretty much the same way
*
*/
/*
* No doubt there is a fancy preprocessor trick for avoiding these
* duplications but I don't have time to figure it out. Patches are
* being accepted...
*/
#define mlINIT_FUNC _pil_plugin_init
#define mlINIT_FUNC_STR "_pil_plugin_init"
#define PIL_INSERT _LTX_
#define PIL_INSERT_STR "_LTX_"
/*
* snprintf-style format string for initialization entry point name:
* arguments are: (plugintype, pluginname)
*/
#define PIL_FUNC_FMT "%s" PIL_INSERT_STR "%s" mlINIT_FUNC_STR
#ifdef __STDC__
# define EXPORTHELPER1(plugintype, insert, pluginname, function) \
plugintype##insert##pluginname##function
#else
# define EXPORTHELPER1(plugintype, insert, pluginname, function) \
plugintype/**/insert/**/pluginname/**/function
#endif
#define EXPORTHELPER2(a, b, c, d) EXPORTHELPER1(a, b, c, d)
#define PIL_PLUGIN_INIT \
EXPORTHELPER2(PIL_PLUGINTYPE,PIL_INSERT,PIL_PLUGIN,mlINIT_FUNC)
/*
* Plugin loading return codes. OK will always be zero.
*
* There are many ways to fail, but only one kind of success ;-)
*/
typedef enum {
PIL_OK=0, /* Success */
PIL_INVAL=1, /* Invalid Parameters */
PIL_BADTYPE=2, /* Bad plugin/interface type */
PIL_EXIST=3, /* Duplicate Plugin/Interface name */
PIL_OOPS=4, /* Internal Error */
PIL_NOPLUGIN=5 /* No such plugin or Interface */
}PIL_rc; /* Return code from Plugin fns*/
const char * PIL_strerror(PIL_rc rc);
typedef struct PILPluginImports_s PILPluginImports;
typedef struct PILPluginOps_s PILPluginOps;
typedef struct PILPlugin_s PILPlugin;
typedef struct PILPluginUniv_s PILPluginUniv;
typedef struct PILPluginType_s PILPluginType;
typedef struct PILInterface_s PILInterface;
typedef struct PILInterfaceImports_s PILInterfaceImports;
typedef struct PILInterfaceUniv_s PILInterfaceUniv;
typedef struct PILInterfaceType_s PILInterfaceType;
typedef PIL_rc(*PILInterfaceFun)(PILInterface*, void* ud_interface);
#define PIL_MAGIC_PLUGIN 0xFEEDBEEFUL
#define PIL_MAGIC_PLUGINTYPE 0xFEEDCEEFUL
#define PIL_MAGIC_PLUGINUNIV 0xFEEDDEEFUL
#define PIL_MAGIC_INTERFACE 0xFEEDEEEFUL
#define PIL_MAGIC_INTERFACETYPE 0xFEEDFEEFUL
#define PIL_MAGIC_INTERFACEUNIV 0xFEED0EEFUL
#define IS_PILPLUGIN(s) ((s)->MagicNum == PIL_MAGIC_PLUGIN)
#define IS_PILPLUGINTYPE(s) ((s)->MagicNum == PIL_MAGIC_PLUGINTYPE)
#define IS_PILPLUGINUNIV(s) ((s)->MagicNum == PIL_MAGIC_PLUGINUNIV)
#define IS_PILINTERFACE(s) ((s)->MagicNum == PIL_MAGIC_INTERFACE)
#define IS_PILINTERFACETYPE(s) ((s)->MagicNum == PIL_MAGIC_INTERFACETYPE)
#define IS_PILINTERFACEUNIV(s) ((s)->MagicNum == PIL_MAGIC_INTERFACEUNIV)
/* This is the place where PILS installs its own plugins */
#define PILS_BASE_PLUGINDIR "@pils_plugindir@"
/* The type of a Plugin Initialization Function */
typedef PIL_rc (*PILPluginInitFun) (PILPlugin*us
, PILPluginImports* imports
, void* plugin_user_data);
/*
* struct PILPluginOps_s (typedef PILPluginOps) defines the set of functions
* exported by all plugins...
*/
struct PILPluginOps_s {
const char* (*pluginversion) (void);
int (*getdebuglevel) (void);
void (*setdebuglevel) (int);
const char* (*license) (void);
const char* (*licenseurl) (void);
void (*close) (PILPlugin*);
};
/*
* Logging levels for the "standard" log interface.
*/
typedef enum {
PIL_FATAL= 1, /* BOOM! Causes program to stop */
PIL_CRIT = 2, /* Critical -- serious error */
PIL_WARN = 3, /* Warning */
PIL_INFO = 4, /* Informative message */
PIL_DEBUG= 5 /* Debug message */
}PILLogLevel;
typedef void (*PILLogFun)(PILLogLevel priority, const char * fmt, ...);
/*
* struct PILPluginImports_s (typedef PILPluginImports) defines
* the functions and capabilities that every plugin imports when it is loaded.
*/
struct PILPluginImports_s {
PIL_rc (*register_plugin)(PILPlugin* piinfo
, const PILPluginOps* commonops);
PIL_rc (*unregister_plugin)(PILPlugin* piinfo);
/*
* A little explanation of the close_func parameter to register_interface
* is in order.
*
* It is an exported operation function, just like the Ops structure.
* However, the Ops vector is exported to applications that
* are using the interface. Unlike the Ops structure, close_func is
* exported only to the interface system, since applications shouldn't
* call it directly, but should manage the reference counts for the
* interfaces instead.
* The generic interface system doesn't have any idea how to call
* any functions in the operations vector. So, it's a separate
* parameter for two good reasons.
*/
PIL_rc (*register_interface)(PILPlugin* piinfo
, const char * interfacetype /* Type of interface */
, const char * interfacename /* Name of interface */
, void* Ops /* Info (functions) exported
by this interface */
/* Function to call to shut down this interface */
, PILInterfaceFun close_func
, PILInterface** interfaceid /* Interface id (OP) */
, void** Imports
, void* ud_interface); /* interface user data */
PIL_rc (*unregister_interface)(PILInterface* interfaceid);
PIL_rc (*load_plugin)(PILPluginUniv* universe
, const char * plugintype, const char * pluginname
, void* plugin_private);
void (*log) (PILLogLevel priority, const char * fmt, ...);
void* (*alloc)(unsigned long size);
void* (*mrealloc)(void * ptr, unsigned long size);
void (*mfree)(void* space);
char* (*mstrdup)(const char *s);
};
/*
* Function for logging with the given logging function
* The reason why it's here is so we can get printf arg checking
* You can't get that when you call a function pointer directly.
*/
void PILCallLog(PILLogFun logfun, PILLogLevel priority, const char * fmt, ...)
G_GNUC_PRINTF(3,4);
/*
* EXPORTED INTERFACES...
*/
/* Create a new plugin universe - start the plugin loading system up */
PILPluginUniv* NewPILPluginUniv(const char * baseplugindirectory);
/* Change memory allocation functions right after creating universe */
void PilPluginUnivSetMemalloc(PILPluginUniv*
, void* (*alloc)(unsigned long size)
, void* (*mrealloc)(void *, unsigned long size)
, void (*mfree)(void* space)
, char* (*mstrdup)(const char *s));
void PilPluginUnivSetLog(PILPluginUniv*
, void (*log) (PILLogLevel priority, const char * fmt, ...));
/* Delete a plugin universe - shut the plugin loading system down */
/* Best if used carefully ;-) */
void DelPILPluginUniv(PILPluginUniv*);
/* Set the debug level for the plugin system itself */
void PILpisysSetDebugLevel (int level);
/* Return a list of plugins of the given type */
char ** PILListPlugins(PILPluginUniv* u, const char *plugintype
, int* plugincount /*can be NULL*/);
/* Free the plugin list returned by PILFreeListPlugins */
void PILFreePluginList(char ** pluginlist);
/* Load the requested plugin */
PIL_rc PILLoadPlugin(PILPluginUniv* piuniv
, const char * plugintype
, const char * pluginname
, void * pi_private);
/* Return PIL_OK if the given plugin exists */
PIL_rc PILPluginExists(PILPluginUniv* piuniv
, const char * plugintype
, const char * pluginname);
/* Either or both of pitype and piname may be NULL */
void PILSetDebugLevel(PILPluginUniv*u, const char * pitype
, const char * piname
, int level);
/* Neither pitype nor piname may be NULL */
int PILGetDebugLevel(PILPluginUniv* u, const char * pitype
, const char * piname);
PIL_rc PILIncrIFRefCount(PILPluginUniv* piuniv
, const char * interfacetype
, const char * interfacename
, int plusminus);
int PILGetIFRefCount(PILPluginUniv* piuniv
, const char * interfacetype
, const char * interfacename);
void PILLogMemStats(void);
/* The plugin/interface type of a interface manager */
#define PI_IFMANAGER "InterfaceMgr"
#define PI_IFMANAGER_TYPE InterfaceMgr
/*
* These functions are standard exported functions for all plugins.
*/
#define PIL_PLUGIN_BOILERPLATE_PROTOTYPES_GENERIC(PluginVersion, DebugName) \
/* \
* Prototypes for boilerplate functions \
*/ \
static const char* Ourpluginversion(void); \
static int GetOurDebugLevel(void); \
static void SetOurDebugLevel(int); \
static const char * ReturnOurLicense(void); \
static const char * ReturnOurLicenseURL(void);
#define PIL_PLUGIN_BOILERPLATE_FUNCS(PluginVersion, DebugName) \
/* \
* Definitions of boilerplate functions \
*/ \
static const char* \
Ourpluginversion(void) \
{ return PluginVersion; } \
\
static int DebugName = 0; \
\
static int \
GetOurDebugLevel(void) \
{ return DebugName; } \
\
static void \
SetOurDebugLevel(int level) \
{ DebugName = level; } \
\
static const char * \
ReturnOurLicense(void) \
{ return PIL_PLUGINLICENSE; } \
\
static const char * \
ReturnOurLicenseURL(void) \
{ return PIL_PLUGINLICENSEURL; }
#define PIL_PLUGIN_BOILERPLATE(PluginVersion, DebugName, CloseName) \
PIL_PLUGIN_BOILERPLATE_PROTOTYPES_GENERIC(PluginVersion, DebugName) \
static void CloseName(PILPlugin*); \
/* \
* Initialize Plugin Exports structure \
*/ \
static PILPluginOps OurPIExports = \
{ Ourpluginversion \
, GetOurDebugLevel \
, SetOurDebugLevel \
, ReturnOurLicense \
, ReturnOurLicenseURL \
, CloseName \
}; \
PIL_PLUGIN_BOILERPLATE_FUNCS(PluginVersion, DebugName)
#define PIL_PLUGIN_BOILERPLATE2(PluginVersion, DebugName) \
PIL_PLUGIN_BOILERPLATE_PROTOTYPES_GENERIC(PluginVersion, DebugName) \
/* \
* Initialize Plugin Exports structure \
*/ \
static PILPluginOps OurPIExports = \
{ Ourpluginversion \
, GetOurDebugLevel \
, SetOurDebugLevel \
, ReturnOurLicense \
, ReturnOurLicenseURL \
, NULL \
}; \
PIL_PLUGIN_BOILERPLATE_FUNCS(PluginVersion, DebugName)
/* A few sample licenses and URLs. We can easily add to this */
#define LICENSE_GPL "gpl"
#define URL_GPL "http://www.fsf.org/licenses/gpl.html"
#define LICENSE_LGPL "lgpl"
#define URL_LGPL "http://www.fsf.org/licenses/lgpl.html"
#define LICENSE_X11 "x11"
#define URL_X11 "http://www.x.org/terms.htm"
#define LICENSE_PUBDOM "publicdomain"
#define URL_PUBDOM "file:///dev/null"
#define LICENSE_MODBSD "modbsd"
#define URL_MODBSD "http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5"
#define LICENSE_OLDBSD "origbsd"
#define URL_OLDBSD "http://www.xfree86.org/3.3.6/COPYRIGHT2.html#6"
#define LICENSE_EXPAT "expat"
#define URL_EXPAT "http://www.jclark.com/xml/copying.txt"
#define LICENSE_ZLIB "zlib"
#define URL_ZLIB "http://www.gzip.org/zlib/zlib_license.html"
#define LICENSE_APACHE_10 "apache1_0"
#define URL_APACHE_10 "http://www.apache.org/LICENSE-1.0"
#define LICENSE_APACHE_11 "apache1_1"
#define URL_APACHE_11 "http://www.apache.org/LICENSE-1.1"
#define LICENSE_MPL "mpl"
#define URL_MPL "http://www.mozilla.org/MPL/MPL-1.1.html"
#define LICENSE_PROP "proprietary"
#define URL_PROP ""
#define LICENSE_IBMPL "ibmpl"
#define URL_IBMPL "http://oss.software.ibm.com/developerworks/opensource/license10.html"
#ifdef ENABLE_PIL_DEFS_PRIVATE
/* Perhaps these should be moved to a different header file */
/*
* PILPluginType is the "class" for the basic plugin loading mechanism.
*
* To enable loading of plugins from a particular plugin type
* one calls NewPILPluginType with the plugin type name, the plugin
* base directory, and the set of functions to be imported to the plugin.
*
*
* The general idea of these structures is as follows:
*
* The PILPluginUniv object contains information about all plugins of
* all types.
*
* The PILPluginType object contains information about all the plugins of a
* specific type.
*
* Note: for plugins which implement a single interface, the plugin type name
* should be the same as the interface type name.
*
* For other plugins that implement more than one interface, one of
* the interface names should normally match the plugin name.
*/
/*
* struct PILPlugin_s (typedef PILPlugin) is the structure which
* represents/defines a plugin, and is used to identify which plugin is
* being referred to in various function calls.
*
* NOTE: It may be the case that this definition should be moved to
* another header file - since no one ought to be messing with them anyway ;-)
*
* I'm not sure that we're putting the right stuff in here, either...
*/
struct PILPlugin_s {
unsigned long MagicNum;
char* plugin_name;
PILPluginType* plugintype; /* Parent structure */
int refcnt; /* Reference count for this plugin */
lt_dlhandle dlhandle; /* Reference to D.L. object */
PILPluginInitFun dlinitfun; /* Initialization function */
const PILPluginOps* pluginops; /* Exported plugin operations */
void* ud_plugin; /* Plugin-Private data */
/* Other stuff goes here ... (?) */
};
/*
* PILPluginType Information about all plugins of a given type.
* (i.e., in a given directory)
* (AKA struct PILPluginType_s)
*/
struct PILPluginType_s {
unsigned long MagicNum;
char * plugintype;
PILPluginUniv* piuniv; /* The universe to which we belong */
GHashTable* Plugins;
/* Key is plugin type, value is PILPlugin */
char** (*listplugins)(PILPluginType*, int* listlen);
};
/*
* PILPluginUniv (aka struct PILPluginUniv_s) is the structure which
* represents the universe of all PILPluginType objects.
* There is one PILPluginType object for each Plugin type.
*/
struct PILPluginUniv_s {
unsigned long MagicNum;
char ** rootdirlist;
/* key is plugin type, data is PILPluginType* */
GHashTable* PluginTypes;
struct PILInterfaceUniv_s*ifuniv; /* Universe of interfaces */
PILPluginImports* imports;
};
# endif /* ENABLE_PIL_DEFS_PRIVATE */
#endif /*PILS_PLUGIN_H */