?? pils.c
字號:
/* $Id: pils.c,v 1.47 2005/02/17 05:49:24 alan Exp $ *//* * Copyright (C) 2001 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 * */#include <portability.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <dirent.h>#include <errno.h>#include <stdarg.h>#include <sys/stat.h>/* Dumbness... */#define time FooTimeParameter#define index FooIndexParameter# include <glib.h>#undef time#undef index#define ENABLE_PIL_DEFS_PRIVATE#define ENABLE_PLUGIN_MANAGER_PRIVATE#ifndef STRLEN_CONST# define STRLEN_CONST(con) (sizeof(con)-1)#endif#include <pils/interface.h>#define NEW(type) (g_new(type,1))#define ZAP(obj) memset(obj, 0, sizeof(*obj))#define DELETE(obj) {g_free(obj); obj = NULL;}#ifdef LTDL_SHLIB_EXT# define PLUGINSUFFIX LTDL_SHLIB_EXT#else# define PLUGINSUFFIX ".so"#endifstatic int PluginDebugLevel = 0;#define DEBUGPLUGIN (PluginDebugLevel > 0)static PIL_rc InterfaceManager_plugin_init(PILPluginUniv* univ);static char** PILPluginTypeListPlugins(PILPluginType* pitype, int* picount);static PILInterface* FindIF(PILPluginUniv* universe, const char *iftype, const char * ifname);static PIL_rc PluginExists(const char * PluginPath);static char * PILPluginPath(PILPluginUniv* universe, const char * plugintype, const char * pluginname);void DelPILPluginUniv(PILPluginUniv*);/* * These RmA* functions primarily called from hash_table_foreach, * functions, so they have gpointer arguments. When calling * them by hand, take special care to pass the right argument types. * * They all follow the same calling sequence though. It is: * String name"*" type object * "*" type object with the name given by 1st argument * NULL * * For example: * RmAPILPluginType takes * string name * PILPluginType* object with the given name. */static gboolean RmAPILPluginType( gpointer pitname /* Name of this plugin type */, gpointer pitype /* PILPluginType* */, gpointer notused);static void RemoveAPILPluginType(PILPluginType*);static PILPluginType* NewPILPluginType( PILPluginUniv* pluginuniv, const char * plugintype);static void DelPILPluginType(PILPluginType*);/* * These RmA* functions primarily called from hash_table_foreach, * so they have gpointer arguments. When calling * them by hand, take special care to pass the right argument types. */static gboolean RmAPILPlugin( gpointer piname /* Name of this plugin */, gpointer plugin /* PILPlugin* */, gpointer notused);static void RemoveAPILPlugin(PILPlugin*);static PILPlugin* NewPILPlugin(PILPluginType* pitype , const char * plugin_name , lt_dlhandle dlhand , PILPluginInitFun PluginSym);static void DelPILPlugin(PILPlugin*);struct MemStat { unsigned long news; unsigned long frees;};static struct PluginStats { struct MemStat plugin; struct MemStat pitype; struct MemStat piuniv; struct MemStat interface; struct MemStat interfacetype; struct MemStat interfaceuniv;}PILstats;#define STATNEW(t) {PILstats.t.news ++; }#define STATFREE(t) {PILstats.t.frees ++; }static PILInterfaceUniv* NewPILInterfaceUniv(PILPluginUniv*);static void DelPILInterfaceUniv(PILInterfaceUniv*);/* * These RmA* functions primarily called from hash_table_foreach, but * not necessarily, so they have gpointer arguments. When calling * them by hand, take special care to pass the right argument types. */static gboolean RmAPILInterfaceType( gpointer iftypename /* Name of this interface type */, gpointer iftype /* PILInterfaceType* */, gpointer notused);static void RemoveAPILInterfaceType(PILInterfaceType*, PILInterfaceType*);static PILInterfaceType* NewPILInterfaceType( PILInterfaceUniv*, const char * typename, void* ifexports, void* user_data);static void DelPILInterfaceType(PILInterfaceType*);/* * These RmA* functions are designed to be called from * hash_table_foreach, so they have gpointer arguments. When calling * them by hand, take special care to pass the right argument types. * They can be called from other places safely also. */static gboolean RmAPILInterface( gpointer ifname /* Name of this interface */, gpointer plugin /* PILInterface* */, gpointer notused);static PIL_rc RemoveAPILInterface(PILInterface*);static void DelPILPluginType(PILPluginType*);static PILInterface* NewPILInterface( PILInterfaceType* interfacetype, const char* interfacename, void * exports, PILInterfaceFun closefun, void* ud_interface, PILPlugin* loading_plugin /* The plugin that loaded us */);static void DelPILInterface(PILInterface*);static PIL_rc close_ifmgr_interface(PILInterface*, void*);/* * For consistency, we show up as a plugin in our our system. * * Here are our exports as a plugin. * */static const char * PIL_PILPluginVersion(void);static void PIL_PILPluginClose (PILPlugin*);void PILpisysSetDebugLevel (int level);int PILpisysGetDebugLevel(void);static const char * PIL_PILPluginLicense (void);static const char * PIL_PILPluginLicenseUrl (void);static const PILPluginOps PluginExports ={ PIL_PILPluginVersion, PILpisysGetDebugLevel, PILpisysSetDebugLevel, PIL_PILPluginLicense, PIL_PILPluginLicenseUrl, PIL_PILPluginClose};/* Prototypes for the functions that we export to every plugin */static PIL_rc PILregister_plugin(PILPlugin* piinfo, const PILPluginOps* mops);static PIL_rc PILunregister_plugin(PILPlugin* piinfo);static PIL_rcPILRegisterInterface( PILPlugin* piinfo, const char * interfacetype /* Type of interface */, const char * interfacename /* Name of interface */, void* Ops /* Ops exported by this interface */, PILInterfaceFun closefunc /* Ops exported by this interface */, PILInterface** interfaceid /* Interface id (OP) */, void** Imports /* Functions imported by */ /* this interface (OP) */, void* ud_interface /* interface user data */);static PIL_rc PILunregister_interface(PILInterface* interfaceid);static void PILLog(PILLogLevel priority, const char * fmt, ...);/* * This is the set of functions that we export to every plugin * * That also makes it the set of functions that every plugin imports. * */static PILPluginImports PILPluginImportSet ={ PILregister_plugin /* register_plugin */, PILunregister_plugin /* unregister_plugin */, PILRegisterInterface /* register_interface */, RemoveAPILInterface /* unregister_interface */, PILLoadPlugin /* load_plugin */, PILLog /* Logging function */, g_malloc /* Malloc function */, g_realloc /* realloc function */, g_free /* Free function */, g_strdup /* Strdup function */};static PIL_rc ifmgr_register_interface(PILInterface* newif , void** imports);static PIL_rc ifmgr_unregister_interface(PILInterface* interface);/* * For consistency, the master interface manager is a interface in the * system. Below is our set of exported Interface functions. * * Food for thought: This is the interface manager whose name is * interface. This makes it the Interface Interface interface ;-) * (or the Interface/Interface interface if you prefer) */static PILInterfaceOps IfExports ={ ifmgr_register_interface, ifmgr_unregister_interface};/* * Below is the set of functions we export to every interface manager. */static int IfRefCount(PILInterface * ifh);static int IfIncrRefCount(PILInterface*eifinfo,int plusminus);static int PluginIncrRefCount(PILPlugin*eifinfo,int plusminus);#if 0static int PluginRefCount(PILPlugin * ifh);#endifstatic void IfForceUnregister(PILInterface *eifinfo);static void IfForEachClientRemove(PILInterface* manangerif , gboolean(*f)(PILInterface* clientif, void * other) , void* other);static PILInterfaceImports IFManagerImports ={ IfRefCount, IfIncrRefCount, IfForceUnregister, IfForEachClientRemove};static void PILValidatePlugin(gpointer key, gpointer plugin, gpointer pitype);static void PILValidatePluginType(gpointer key, gpointer pitype, gpointer piuniv);static void PILValidatePluginUniv(gpointer key, gpointer pitype, gpointer);static void PILValidateInterface(gpointer key, gpointer interface, gpointer iftype);static void PILValidateInterfaceType(gpointer key, gpointer iftype, gpointer ifuniv);static void PILValidateInterfaceUniv(gpointer key, gpointer puniv, gpointer);/***************************************************************************** * * This code is for managing plugins, and interacting with them... * ****************************************************************************/static PILPlugin*NewPILPlugin( PILPluginType* pitype , const char * plugin_name , lt_dlhandle dlhand , PILPluginInitFun PluginSym){ PILPlugin* ret = NEW(PILPlugin); if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "NewPILPlugin(0x%x)", (unsigned long)ret); } STATNEW(plugin); ret->MagicNum = PIL_MAGIC_PLUGIN; ret->plugin_name = g_strdup(plugin_name); ret->plugintype = pitype; ret->refcnt = 0; ret->dlhandle = dlhand; ret->dlinitfun = PluginSym; PILValidatePlugin(ret->plugin_name, ret, pitype); return ret;}static voidDelPILPlugin(PILPlugin*pi){ if (pi->refcnt > 0) { PILLog(PIL_INFO, "DelPILPlugin: Non-zero refcnt"); } if (pi->dlhandle) { if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "Closing dlhandle for (%s/%s)" , pi->plugintype->plugintype, pi->plugin_name); } lt_dlclose(pi->dlhandle); }else if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "NO dlhandle for (%s/%s)!" , pi->plugintype->plugintype, pi->plugin_name); } DELETE(pi->plugin_name); ZAP(pi); DELETE(pi); STATFREE(plugin);}static PILPluginType dummymlpitype ={ PIL_MAGIC_PLUGINTYPE, NULL /*plugintype*/, NULL /*piuniv*/, NULL /*Plugins*/, PILPluginTypeListPlugins /* listplugins */};static PILPluginType*NewPILPluginType(PILPluginUniv* pluginuniv , const char * plugintype){ PILPluginType* ret = NEW(PILPluginType); if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "NewPILPlugintype(0x%x)", (unsigned long)ret); } STATNEW(pitype); *ret = dummymlpitype; ret->plugintype = g_strdup(plugintype); ret->piuniv = pluginuniv; ret->Plugins = g_hash_table_new(g_str_hash, g_str_equal); g_hash_table_insert(pluginuniv->PluginTypes , g_strdup(ret->plugintype), ret); PILValidatePluginType(ret->plugintype, ret, pluginuniv); return ret;}static voidDelPILPluginType(PILPluginType*pitype){ PILValidatePluginType(NULL, pitype, NULL); if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "DelPILPluginType(%s)", pitype->plugintype); } STATFREE(pitype); g_hash_table_foreach_remove(pitype->Plugins, RmAPILPlugin, NULL); g_hash_table_destroy(pitype->Plugins); DELETE(pitype->plugintype); ZAP(pitype); DELETE(pitype);}/* * These RmA* functions primarily called from hash_table_foreach, * so they have gpointer arguments. This *not necessarily* clause * is why they do the g_hash_table_lookup_extended call instead of * just deleting the key. When called from outside, the key * * may not be pointing at the key to actually free, but a copy * of the key. */static gbooleanRmAPILPlugin /* IsA GHFunc: required for g_hash_table_foreach_remove() */( gpointer piname /* Name of this plugin */, gpointer plugin /* PILPlugin* */, gpointer notused ){ PILPlugin* Plugin = plugin; PILPluginType* Pitype = Plugin->plugintype; PILValidatePlugin(piname, plugin, NULL); PILValidatePluginType(NULL, Pitype, NULL); g_assert(IS_PILPLUGIN(Plugin)); if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "RmAPILPlugin(%s/%s)", Pitype->plugintype , Plugin->plugin_name); } /* Normally called from g_hash_table_foreachremove or equivalent */ DelPILPlugin(plugin); DELETE(piname); return TRUE;}static voidRemoveAPILPlugin(PILPlugin*Plugin){ PILPluginType* Pitype = Plugin->plugintype; gpointer key; if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "RemoveAPILPlugin(%s/%s)" , Pitype->plugintype , Plugin->plugin_name); } if (g_hash_table_lookup_extended(Pitype->Plugins , Plugin->plugin_name, &key, (void*)&Plugin)) { g_hash_table_remove(Pitype->Plugins, key); RmAPILPlugin(key, Plugin, NULL); key = NULL; Plugin = NULL; }else{ g_assert_not_reached(); } if (g_hash_table_size(Pitype->Plugins) == 0) { RemoveAPILPluginType(Pitype); /* Pitype is now invalid */ Pitype = NULL; }}PILPluginUniv*NewPILPluginUniv(const char * basepluginpath){ PILPluginUniv* ret = NEW(PILPluginUniv); /* The delimiter separating search path components */ const char* path_delim = G_SEARCHPATH_SEPARATOR_S; char * fullpath; STATNEW(piuniv); if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "NewPILPluginUniv(0x%x)" , (unsigned long)ret); } if (!g_path_is_absolute(basepluginpath)) { DELETE(ret); return(ret); } ret->MagicNum = PIL_MAGIC_PLUGINUNIV; fullpath = g_strdup_printf("%s%s%s", basepluginpath , path_delim, PILS_BASE_PLUGINDIR); if (DEBUGPLUGIN) { PILLog(PIL_DEBUG , "PILS: Plugin path = %s", fullpath); } /* Separate the root directory PATH into components */ ret->rootdirlist = g_strsplit(fullpath, path_delim, 100); g_free(fullpath); ret->PluginTypes = g_hash_table_new(g_str_hash, g_str_equal); ret->imports = &PILPluginImportSet; ret->ifuniv = NewPILInterfaceUniv(ret); PILValidatePluginUniv(NULL, ret, NULL); return ret;}/* Change memory allocation functions immediately after creating universe */voidPilPluginUnivSetMemalloc(PILPluginUniv* u, void* (*allocfun)(unsigned long size), void* (*reallocfun)(void * ptr, unsigned long size), void (*freefun)(void* space), char* (*strdupfun)(const char *s)){ u->imports->alloc = allocfun; u->imports->mrealloc = reallocfun; u->imports->mfree = freefun; u->imports->mstrdup = strdupfun;}/* Change logging functions - preferably right after creating universe */voidPilPluginUnivSetLog(PILPluginUniv* u, void (*logfun) (PILLogLevel priority, const char * fmt, ...)){ u->imports->log = logfun;}voidDelPILPluginUniv(PILPluginUniv* piuniv){ if (DEBUGPLUGIN) { PILLog(PIL_DEBUG, "DelPILPluginUniv(0x%lx)" , (unsigned long)piuniv); } STATFREE(piuniv); PILValidatePluginUniv(NULL, piuniv, NULL); DelPILInterfaceUniv(piuniv->ifuniv); piuniv->ifuniv = NULL; g_hash_table_foreach_remove(piuniv->PluginTypes , RmAPILPluginType, NULL); g_hash_table_destroy(piuniv->PluginTypes); g_strfreev(piuniv->rootdirlist); ZAP(piuniv); DELETE(piuniv);}/* * These RmA* functions primarily called from hash_table_foreach,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -