Logo Search packages:      
Sourcecode: heartbeat version File versions

generic.c

/* $Id: generic.c,v 1.18.2.3 2004/09/07 16:26:26 alan Exp $ */
/*
 * 
 * Generic interface (implementation) manager
 *
 * Copyright 2001 Alan Robertson <alanr@unix.sh>
 * Licensed under the GNU Lesser General Public License
 *
 * This manager will manage any number of types of interfaces.
 *
 * This means that when any implementations of our client interfaces register
 * or unregister, it is us that makes their interfaces show up in the outside
 * world.
 *
 * And, of course, we have to do this in a very generic way, since we have
 * no idea about the client programs or interface types, or anything else.
 *
 * We do that by getting a parameter passed to us which tell us the names
 * of the interface types we want to manage, and the address of a GHashTable
 * for each type that we put the implementation in when they register
 * themselves.
 *
 * So, each type of interface that we manage gets its own private
 * GHashTable of the implementations of that type that are currently
 * registered.
 *
 * For example, if we manage communication modules, their exported
 * interfaces will be registered in a hash table.  If we manage
 * authentication modules, they'll have their (separate) hash table that
 * their exported interfaces are registered in.
 *
 *
 * 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
 *
 */

#define     PIL_PLUGINTYPE          InterfaceMgr
#define PIL_PLUGINTYPE_S      "InterfaceMgr"
#define     PIL_PLUGIN        generic
#define PIL_PLUGIN_S          "generic"
#define PIL_PLUGINLICENSE     LICENSE_LGPL
#define PIL_PLUGINLICENSEURL  URL_LGPL

/* We are an interface manager... */
#define ENABLE_PLUGIN_MANAGER_PRIVATE
#define ENABLE_PIL_DEFS_PRIVATE

#include <portability.h>
#include <pils/generic.h>

#include <stdio.h>

PIL_PLUGIN_BOILERPLATE("1.0", GenDebugFlag, CloseGeneralPluginManager)

/*
 * Key is interface type, value is a PILGenericIfMgmtRqst.
 * The key is g_strdup()ed, but the struct is not copied.
 */

static gboolean FreeAKey(gpointer key, gpointer value, gpointer data);

/*
 *    Places to store information gotten during registration.
 */
static const PILPluginImports*      GenPIImports;     /* Imported plugin fcns */
static PILPlugin*       GenPlugin;  /* Our plugin info */
static PILInterfaceImports*   GenIfImports;     /* Interface imported fcns */

/* Our exported generic interface management functions */
static PIL_rc RegisterGenIF(PILInterface* ifenv, void**     imports);

static PIL_rc UnregisterGenIF(PILInterface*iifinfo);

static PIL_rc CloseGenInterfaceManager(PILInterface*, void* info);

/*
 *    Our Interface Manager interfaces - exported to the universe!
 *
 *    (or at least to the interface management universe ;-).
 *
 *    These are the interfaces which are used to manage our
 *    client implementations
 */
static PILInterfaceOps        GenIfOps =
{     RegisterGenIF
,     UnregisterGenIF
};


PIL_rc PIL_PLUGIN_INIT(PILPlugin*us, PILPluginImports* imports, void*);

/*
 *    Our user_ptr is presumed to point to NULL-terminated array of
 *    PILGenericIfMgmtRqst structs.
 *
 *    These requests have pointers to GHashTables for us
 *    to put plugins into when they show up, and drop from when
 *    they disappear.
 *
 *    Issues include:
 *    - freeing all memory,
 *    - making sure things are all cleaned up correctly
 *    - Thread-safety?
 *
 *    IMHO the global system should handle thread-safety.
 */
static PIL_rc AddAnInterfaceType(PILPlugin*us, GHashTable* MasterTable, PILGenericIfMgmtRqst* req);

PIL_rc
PIL_PLUGIN_INIT(PILPlugin*us, PILPluginImports* imports, void *user_ptr)
{
      PIL_rc                  ret;
      PILGenericIfMgmtRqst*   user_req;
      PILGenericIfMgmtRqst*   curreq;
      GHashTable* MasterTable = NULL;
      /*
       * Force the compiler to check our parameters...
       */
      PILPluginInitFun  fun = &PIL_PLUGIN_INIT; (void)fun;

        GenPIImports = imports;

      if (GenDebugFlag) {
            PILCallLog(GenPIImports->log, PIL_DEBUG
            ,     "IF manager %s: initializing.", PIL_PLUGIN_S);
      }

      if (user_ptr == NULL) {
            PILCallLog(GenPIImports->log, PIL_CRIT
            ,     "%s Interface Manager requires non-NULL "
            " PILGenericIfMgmtRqst user pointer at initialization."
            ,     PIL_PLUGIN_S);
            return PIL_INVAL;
      }
      GenPlugin = us;

      if (GenDebugFlag) {
            PILCallLog(GenPIImports->log, PIL_DEBUG
            ,     "IF manager %s: registering as a plugin."
            , PIL_PLUGIN_S);
      }

      user_req = user_ptr;
      MasterTable = g_hash_table_new(g_str_hash, g_str_equal);
      us->ud_plugin = MasterTable;  /* Override passed value */

      /* Register ourselves as a plugin */

      if ((ret = imports->register_plugin(us, &OurPIExports)) != PIL_OK) {
            PILCallLog(imports->log, PIL_CRIT
            ,     "IF manager %s unable to register as plugin (%s)"
            ,     PIL_PLUGIN_S, PIL_strerror(ret));

            return ret;
      }

      /*
       * Register to manage implementations
       * for all the interface types we've been asked to manage.
       */

      for(curreq = user_req; curreq->iftype != NULL; ++curreq) {
            PIL_rc newret;

            newret = AddAnInterfaceType(us, MasterTable, curreq);

            if (newret != PIL_OK) {
                  ret = newret;
            }
      }

      /*
       * Our plugin and all our registered plugin types
       * have ud_plugin pointing at MasterTable.
       */

      return ret;
}

static PIL_rc
AddAnInterfaceType(PILPlugin*us, GHashTable* MasterTable, PILGenericIfMgmtRqst* req)
{
      PIL_rc      rc;
      PILInterface*           GenIf;            /* Our Generic Interface info*/

      g_assert(MasterTable != NULL);
      g_hash_table_insert(MasterTable, g_strdup(req->iftype), req);

      if (req->ifmap == NULL) {
            PILCallLog(GenPIImports->log, PIL_CRIT
            ,     "IF manager %s: iftype %s has NULL"
            " ifmap pointer address."
            ,     PIL_PLUGIN_S, req->iftype);
            return PIL_INVAL;
      }
      if ((*req->ifmap) != NULL) {
            PILCallLog(GenPIImports->log, PIL_CRIT
            ,     "IF manager %s: iftype %s GHashTable pointer"
            " was not initialized to NULL"
            ,     PIL_PLUGIN_S, req->iftype);
            return PIL_INVAL;
      }

      if (GenDebugFlag) {
            PILCallLog(GenPIImports->log, PIL_DEBUG
            ,     "IF manager %s: registering ourselves"
            " to manage interface type %s"
            ,     PIL_PLUGIN_S, req->iftype);
            PILCallLog(GenPIImports->log, PIL_DEBUG
            ,     "%s IF manager: ifmap: 0x%lx callback: 0x%lx"
            " imports: 0x%lx"
            ,     PIL_PLUGIN_S
            ,     (unsigned long)req->ifmap
            ,     (unsigned long)req->callback
            ,     (unsigned long)req->importfuns);
      }

      /* Create the hash table to communicate with this client */
      *(req->ifmap) = g_hash_table_new(g_str_hash, g_str_equal);

      rc = GenPIImports->register_interface(us
      ,     PIL_PLUGINTYPE_S
      ,     req->iftype /* the iftype we're managing here */
      ,     &GenIfOps
      ,     CloseGenInterfaceManager
      ,     &GenIf
      ,     (void*)&GenIfImports
      ,     MasterTable);     /* Point ud_interface to MasterTable */

      /* We don't ever want to be unloaded... */
      GenIfImports->ModRefCount(GenIf, +100);

      if (rc != PIL_OK) {
            PILCallLog(GenPIImports->log, PIL_CRIT
            ,     "Generic interface manager %s: unable to register"
            " to manage interface type %s: %s"
            ,     PIL_PLUGIN_S, req->iftype
            ,     PIL_strerror(rc));
      }
      return rc;
}

static void
CloseGeneralPluginManager(PILPlugin* us)
{
      
      GHashTable* MasterTable = us->ud_plugin;
      int         count;

      g_assert(MasterTable != NULL);

      /*
       * All our clients have already been shut down automatically
       * This is the final shutdown for us...
       */


      /* There *shouldn't* be any keys in there ;-) */

      if ((count=g_hash_table_size(MasterTable)) > 0) {

            /* But just in case there are... */
            g_hash_table_foreach_remove(MasterTable, FreeAKey, NULL);
      }
      g_hash_table_destroy(MasterTable);
      us->ud_plugin = NULL;
      return;
}

/*
 *    We get called for every time an implementation registers itself as
 *    implementing one of the kinds of interfaces we manage.
 *
 *    It's our job to make the implementation that's
 *    registering with us available to the system.
 *
 *    We do that by adding it to a GHashTable for its interface type
 *    Our users in the rest of the system takes it from there...
 *
 *    The key to the GHashTable is the implementation name, and the data is
 *    a pointer to the information the implementation exports.
 *
 *    It's a piece of cake ;-)
 */
static PIL_rc
RegisterGenIF(PILInterface* intf,  void** imports)
{
      PILGenericIfMgmtRqst*   ifinfo;
      GHashTable* MasterTable = intf->ifmanager->ud_interface;

      g_assert(MasterTable != NULL);

      /* Reference count should now be one */
      if (GenDebugFlag) {
            PILCallLog(GenPIImports->log, PIL_DEBUG
            ,     "%s IF manager: interface %s/%s registering."
            ,     PIL_PLUGIN_S, intf->interfacetype->typename
            ,     intf->interfacename);
      }
      g_assert(intf->refcnt == 1);
      /*
       * We need to add it to the table that goes with this particular
       * type of interface.
       */
      if ((ifinfo = g_hash_table_lookup(MasterTable
      ,     intf->interfacetype->typename)) !=  NULL) {
            GHashTable*       ifmap = *(ifinfo->ifmap);

            g_hash_table_insert(ifmap, intf->interfacename,intf->exports);
            if (GenDebugFlag) {
                  PILCallLog(GenPIImports->log, PIL_DEBUG
                  , "%s IF manager: Inserted interface [%s] in hash"
                  " table @ 0x%08lx"
                  , PIL_PLUGIN_S, intf->interfacename
                  , (unsigned long)ifmap);
                  PILCallLog(GenPIImports->log, PIL_DEBUG
                  , "%s IF manager: Exports are here: 0x%08x"
                  , PIL_PLUGIN_S
                  , GPOINTER_TO_UINT(intf->exports));
            }

            if (ifinfo->callback != NULL) {
                  PILInterfaceType* t = intf->interfacetype;

                  if (GenDebugFlag) {
                        PILCallLog(GenPIImports->log, PIL_DEBUG
                        ,     "%s IF manager: callback 0x%lx"
                        ,     PIL_PLUGIN_S
                        ,     (unsigned long)ifinfo->callback);
                  }
                  ifinfo->callback(PIL_REGISTER
                  ,     t->universe->piuniv, intf->interfacename
                  ,     t->typename, ifinfo->userptr);
            }

            *imports = ifinfo->importfuns;

            return PIL_OK;

      }else{
            PILCallLog(GenPIImports->log, PIL_WARN
            ,     "RegisterGenIF: interface type %s not found"
            ,     intf->interfacename);
      }
      return PIL_INVAL;
}

/* Unregister an implementation -
 *    We get called from the interface management system when someone
 *    has requested that an implementation of a client interface be
 *    unregistered.
 */
static PIL_rc
UnregisterGenIF(PILInterface*intf)
{
      GHashTable* MasterTable = intf->ifmanager->ud_interface;
      PILGenericIfMgmtRqst*   ifinfo;

      g_assert(MasterTable != NULL);
      g_assert(intf->refcnt >= 0);
      /*
       * Go through the "master table" and find client table, 
       * notify client we're about to remove this entry, then
       * then remove this entry from it.
       */
      if (GenDebugFlag) {
            PILCallLog(GenPIImports->log, PIL_DEBUG
            ,     "%s IF manager: unregistering interface %s/%s."
            ,     PIL_PLUGIN_S, intf->interfacetype->typename
            ,     intf->interfacename);
      }
      if ((ifinfo = g_hash_table_lookup(MasterTable
      ,     intf->interfacetype->typename)) != NULL)  {

            GHashTable*       ifmap = *(ifinfo->ifmap);

            if (ifinfo->callback != NULL) {
                  PILInterfaceType* t = intf->interfacetype;
                  if (GenDebugFlag) {
                        PILCallLog(GenPIImports->log, PIL_DEBUG
                        ,     "%s IF manager: callback 0x%lx"
                        ,     PIL_PLUGIN_S
                        ,     (unsigned long)ifinfo->callback);
                  }
                  ifinfo->callback(PIL_UNREGISTER
                  ,     t->universe->piuniv, intf->interfacename
                  ,     t->typename, ifinfo->userptr);
            }

            /* Remove the client entry from master table */
            g_hash_table_remove(ifmap, intf->interfacename);

      }else{
            PILCallLog(GenPIImports->log, PIL_WARN
            ,     "UnregisterGenIF: interface type %s not found"
            ,     intf->interfacename);
            return PIL_INVAL;
      }
      return PIL_OK;
}

/*
 *    Close down the generic interface manager.
 */
static PIL_rc
CloseGenInterfaceManager(PILInterface*intf, void* info)
{
      void*       key;
      void*       data;
      GHashTable* MasterTable = intf->ud_interface;

      if (GenDebugFlag) {
            PILCallLog(GenPIImports->log, PIL_INFO
            ,     "In CloseGenInterFaceManager on %s/%s (MasterTable: 0x%08lx)"
            ,     intf->interfacetype->typename, intf->interfacename
            ,     (unsigned long)MasterTable);
      }


      g_assert(MasterTable != NULL);
      if (g_hash_table_lookup_extended(MasterTable
      ,     intf->interfacename, &key, &data)) {
            PILGenericIfMgmtRqst*   ifinfo = data;
            g_hash_table_destroy(*(ifinfo->ifmap));
            *(ifinfo->ifmap) = NULL;
            g_hash_table_remove(MasterTable, key);
            g_free(key);
      }else{
            g_assert_not_reached();
      }
      return PIL_OK;
}

static gboolean
FreeAKey(gpointer key, gpointer value, gpointer data)
{
      g_free(key);
      return TRUE;
}

Generated by  Doxygen 1.6.0   Back to index