Interface system refactoring

* lumiera_interface are now static structures, never wrritten
 * introduced a lumiera_interfacenode which manages the dynamic data
   of interfaces. The interfaceregistry now holds this nodes.
This commit is contained in:
Christian Thaeter 2008-10-14 23:06:43 +02:00
parent 405a578c42
commit f05f6772f1
4 changed files with 177 additions and 123 deletions

View file

@ -36,18 +36,22 @@
*/
extern LumieraInterface lumiera_interface_stack;
static LumieraInterfacenode
lumiera_interface_open_interfacenode (LumieraInterfacenode self);
static void
lumiera_interfacenode_close (LumieraInterfacenode self);
LumieraInterface
lumiera_interface_open (const char* interface, unsigned version, size_t minminorversion, const char* name)
{
LumieraInterface self = NULL;
LumieraInterfacenode self = NULL;
TRACE (interface, "%s", name);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
self = lumiera_interfaceregistry_interface_find (interface, version, name);
self = lumiera_interfaceregistry_interfacenode_find (interface, version, name);
if (!self)
{
@ -56,33 +60,33 @@ lumiera_interface_open (const char* interface, unsigned version, size_t minminor
if (self)
{
if (minminorversion > self->size)
if (minminorversion > self->interface->size)
{
UNIMPLEMENTED ("set error");
self = NULL;
}
else
{
self = lumiera_interface_open_interface (self);
self = lumiera_interface_open_interfacenode (self);
}
}
}
return self;
return self->interface;
}
static void
push_dependency (LumieraInterface parent, LumieraInterface child)
push_dependency (LumieraInterfacenode parent, LumieraInterfacenode child)
{
/* push a dependency on the dependency array, allcoate or resize it on demand */
TRACE (interface, "%s %s", parent->name, child->name);
TRACE (interface, "%s %s", parent->interface->name, child->interface->name);
/* no dependencies recorded yet, alloc a first block for 4 pointers */
if (!parent->ndeps)
parent->deps = lumiera_calloc (parent->ndeps = 4, sizeof (LumieraInterface));
if (!parent->deps_size)
parent->deps = lumiera_calloc (parent->deps_size = 4, sizeof (LumieraInterfacenode));
size_t sz = parent->ndeps;
LumieraInterface* itr = parent->deps;
size_t sz = parent->deps_size;
LumieraInterfacenode* itr = parent->deps;
while (*itr)
{
@ -91,33 +95,31 @@ push_dependency (LumieraInterface parent, LumieraInterface child)
if (sz == 1)
{
/* block to small, realloc it with twice its size, we keep the block NULL terminated */
sz = parent->ndeps + 1;
parent->ndeps *= 2;
parent->deps = lumiera_realloc (parent->deps, parent->ndeps * sizeof (LumieraInterface));
sz = parent->deps_size + 1;
parent->deps_size *= 2;
parent->deps = lumiera_realloc (parent->deps, parent->deps_size * sizeof (LumieraInterface));
itr = parent->deps + sz - 2;
memset (itr, 0, sz * sizeof (LumieraInterface));
}
}
TODO ("free the deps when unregistering the interface");
/* found free element, store self in dependencies */
*itr = child;
}
static void
depwalk (LumieraInterface self, LumieraInterface* stack)
depwalk (LumieraInterfacenode self, LumieraInterfacenode* stack)
{
/* increment refcount for all non-cyclic dependencies recursively */
if (self->deps)
{
TRACE (interface, "%s %d", self->name, self->refcnt);
for (LumieraInterface* dep = self->deps; *dep; ++dep)
TRACE (interface, "%s %d", self->interface->name, self->refcnt);
for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
{
TRACE (interface, "loop %s", (*dep)->name);
TRACE (interface, "loop %s", (*dep)->interface->name);
int cycle = 0;
for (LumieraInterface itr = *stack; itr; itr = itr->lnk)
for (LumieraInterfacenode itr = *stack; itr; itr = itr->lnk)
{
if (itr == *dep)
{
@ -144,11 +146,11 @@ depwalk (LumieraInterface self, LumieraInterface* stack)
}
LumieraInterface
lumiera_interface_open_interface (LumieraInterface self)
static LumieraInterfacenode
lumiera_interface_open_interfacenode (LumieraInterfacenode self)
{
static unsigned collect_dependencies = 0;
static LumieraInterface stack = NULL;
static LumieraInterfacenode stack = NULL;
/*
Ok, this got little more complicated than it should be,
@ -157,14 +159,14 @@ lumiera_interface_open_interface (LumieraInterface self)
if (self)
{
TRACE (interface, "%s %d (%s)", self->name, self->refcnt, stack?stack->name:"");
TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
/* discover cycles, cycles don't refcount! */
int cycle = 0;
for (LumieraInterface itr = stack; itr; itr = itr->lnk)
for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
{
if (itr == self)
{
@ -188,11 +190,11 @@ lumiera_interface_open_interface (LumieraInterface self)
if (self->refcnt == 1)
{
/* first opening, run acquire, recursive opening shall record its dependencies here */
if (self->acquire)
if (self->interface->acquire)
{
TRACE (interface, "Acquire %s", self->name);
TRACE (interface, "Acquire %s", self->interface->name);
collect_dependencies = self->deps?0:1;
self = self->acquire (self);
self->interface = self->interface->acquire (self->interface);
}
}
else
@ -216,60 +218,69 @@ lumiera_interface_open_interface (LumieraInterface self)
void
lumiera_interface_close (LumieraInterface self)
{
static LumieraInterface stack = NULL;
TRACE (interface);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
lumiera_interfacenode_close ((LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, self, 100));
}
}
/* internal function, does no locking! */
static void
lumiera_interfacenode_close (LumieraInterfacenode self)
{
static LumieraInterfacenode stack = NULL;
if (!self)
return;
TRACE (interface, "%s %d (%s)", self->name, self->refcnt, stack?stack->name:"");
TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
REQUIRE (self->refcnt);
int cycle = 0;
for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
{
REQUIRE (self->refcnt);
int cycle = 0;
for (LumieraInterface itr = stack; itr; itr = itr->lnk)
if (itr == self)
{
if (itr == self)
{
TRACE (interface, "CYCLE");
cycle = 1;
break;
}
}
if (!cycle)
{
self->lnk = stack;
stack = self;
if (self->refcnt == 1)
{
if (self->release)
{
TRACE (interface, "Release %s", self->name);
self->release (self);
}
}
else
{
if (self->deps)
{
TRACE (interface, "Recurse %s %d", self->name, self->refcnt);
for (LumieraInterface* dep = self->deps; *dep; ++dep)
lumiera_interface_close (*dep);
}
}
stack = self->lnk;
self->lnk = NULL;
--self->refcnt;
TRACE (interface, "CYCLE");
cycle = 1;
break;
}
}
}
if (!cycle)
{
self->lnk = stack;
stack = self;
if (self->refcnt == 1)
{
if (self->interface->release)
{
TRACE (interface, "Release %s", self->interface->name);
self->interface->release (self->interface);
}
}
else
{
if (self->deps)
{
TRACE (interface, "Recurse %s %d", self->interface->name, self->refcnt);
for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
lumiera_interfacenode_close (*dep);
}
}
stack = self->lnk;
self->lnk = NULL;
--self->refcnt;
}
}
/*

View file

@ -22,6 +22,7 @@
#include "lib/mutex.h"
#include "lib/error.h"
#include "lib/psplay.h"
#include "lib/safeclib.h"
#include <nobug.h>
@ -41,10 +42,9 @@ NOBUG_DEFINE_FLAG_PARENT (interface_all, backend);
NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, interface_all);
NOBUG_DEFINE_FLAG_PARENT (interface, interface_all);
static PSplay interfaceregistry;
PSplay lumiera_interfaceregistry;
lumiera_mutex lumiera_interface_mutex;
static int
cmp_fn (const void* keya, const void* keyb);
@ -52,6 +52,34 @@ static const void*
key_fn (const PSplaynode node);
static LumieraInterfacenode
lumiera_interfacenode_new (LumieraInterface iface)
{
LumieraInterfacenode self = lumiera_malloc (sizeof (*self));
psplaynode_init (&self->node);
self->interface = iface;
self->refcnt = 0;
self->lnk = NULL;
self->deps_size = 0;
self->deps = NULL;
return self;
}
static void
lumiera_interfacenode_delete (LumieraInterfacenode self)
{
if (self)
{
REQUIRE (self->refcnt == 0);
lumiera_free (self->deps);
lumiera_free (self);
}
}
/**
* Initialize the interface registry
@ -63,28 +91,27 @@ lumiera_interfaceregistry_init (void)
NOBUG_INIT_FLAG (interfaceregistry);
NOBUG_INIT_FLAG (interface);
TRACE (interfaceregistry);
REQUIRE (!interfaceregistry);
REQUIRE (!lumiera_interfaceregistry);
TODO ("introduce a registrynode structure, place all dynamic interface stuff there, make interface_struct const");
interfaceregistry = psplay_new (cmp_fn, key_fn, NULL);
if (!interfaceregistry)
lumiera_interfaceregistry = psplay_new (cmp_fn, key_fn, NULL);
if (!lumiera_interfaceregistry)
LUMIERA_DIE (ERRNO);
lumiera_recmutex_init (&lumiera_interface_mutex, "interfaceregistry", &NOBUG_FLAG(interfaceregistry));
}
void
lumiera_interfaceregistry_destroy (void)
{
TRACE (interfaceregistry);
REQUIRE (!psplay_nelements (interfaceregistry));
REQUIRE (!psplay_nelements (lumiera_interfaceregistry));
lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(interfaceregistry));
if (interfaceregistry)
psplay_destroy (interfaceregistry);
interfaceregistry = NULL;
if (lumiera_interfaceregistry)
psplay_destroy (lumiera_interfaceregistry);
lumiera_interfaceregistry = NULL;
}
@ -97,7 +124,7 @@ lumiera_interfaceregistry_register_interface (LumieraInterface self)
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", self->interface, self->version, self->name);
psplay_insert (interfaceregistry, &self->node, 100);
psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (self)->node, 100);
}
}
@ -113,7 +140,7 @@ lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self)
while (*self)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name);
psplay_insert (interfaceregistry, &(*self)->node, 100);
psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (*self)->node, 100);
++self;
}
}
@ -128,10 +155,10 @@ lumiera_interfaceregistry_remove_interface (LumieraInterface self)
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
REQUIRE (self->refcnt == 0);
psplay_remove (interfaceregistry, &self->node);
LumieraInterfacenode node = (LumieraInterfacenode) psplay_find (lumiera_interfaceregistry, self, 0);
REQUIRE (node->refcnt == 0, "but is %d", node->refcnt);
FIXME ("free deps");
lumiera_interfacenode_delete ((LumieraInterfacenode)psplay_remove (lumiera_interfaceregistry, &node->node));
}
}
@ -147,18 +174,20 @@ lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self)
while (*self)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name);
REQUIRE ((*self)->refcnt == 0, "but is %d", (*self)->refcnt);
psplay_remove (interfaceregistry, &(*self)->node);
LumieraInterfacenode node = (LumieraInterfacenode) psplay_find (lumiera_interfaceregistry, *self, 0);
REQUIRE (node->refcnt == 0, "but is %d", node->refcnt);
lumiera_interfacenode_delete ((LumieraInterfacenode) psplay_remove (lumiera_interfaceregistry, &node->node));
++self;
FIXME ("free deps");
}
}
}
LumieraInterface
lumiera_interfaceregistry_interface_find (const char* interface, unsigned version, const char* name)
LumieraInterfacenode
lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned version, const char* name)
{
TRACE (interfaceregistry);
struct lumiera_interface_struct cmp;
@ -166,17 +195,24 @@ lumiera_interfaceregistry_interface_find (const char* interface, unsigned versio
cmp.version = version;
cmp.name = name;
LumieraInterface ret = NULL;
LumieraInterfacenode ret = NULL;
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
ret = (LumieraInterface)psplay_find (interfaceregistry, &cmp, 100);
ret = (LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, &cmp, 100);
}
return ret;
}
LumieraInterface
lumiera_interfaceregistry_interface_find (const char* interface, unsigned version, const char* name)
{
return lumiera_interfaceregistry_interfacenode_find (interface, version, name)->interface;
}
static int
cmp_fn (const void* keya, const void* keyb)
{
@ -207,7 +243,7 @@ cmp_fn (const void* keya, const void* keyb)
static const void*
key_fn (const PSplaynode node)
{
return node;
return ((LumieraInterfacenode)node)->interface;
}

View file

@ -22,6 +22,7 @@
#define LUMIERA_INTERFACEREGISTRY_H
#include "lib/mutex.h"
#include "lib/psplay.h"
#include "lib/interface.h"
#include <nobug.h>
@ -38,9 +39,37 @@ NOBUG_DECLARE_FLAG (interface_all);
NOBUG_DECLARE_FLAG (interfaceregistry);
NOBUG_DECLARE_FLAG (interface);
extern PSplay lumiera_interfaceregistry;
extern lumiera_mutex lumiera_interface_mutex;
/**
* Interface management node.
* All active interfaces managed through this node which contains the dynamic data for
* dependency tracking and reference counting.
*/
typedef struct lumiera_interfacenode_struct lumiera_interfacenode;
typedef lumiera_interfacenode* LumieraInterfacenode;
struct lumiera_interfacenode_struct
{
/** all known interfaces are registered in a tree */
psplaynode node;
/** the interface itself */
LumieraInterface interface;
/** reference counters and link used for internal reference management */
unsigned refcnt;
/** temporary used to stack interfaces when recursively opening/closing them */
LumieraInterfacenode lnk;
/** allocated size of the following deps table */
size_t deps_size;
/** NULL terminated table of all dependenncies (interfaces opened on initialization) */
LumieraInterfacenode* deps;
};
/**
* Initialize the interface registry
*/
@ -63,6 +92,9 @@ lumiera_interfaceregistry_remove_interface (LumieraInterface self);
void
lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self);
LumieraInterfacenode
lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned version, const char* name);
LumieraInterface
lumiera_interfaceregistry_interface_find (const char* interface, unsigned version, const char* name);

View file

@ -182,15 +182,10 @@ PPMPL_FOREACH(_P1_, __VA_ARGS__)
LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, version, name) = \
{ \
{ \
PSPLAYNODE_INITIALIZER, \
#iname, \
version, \
#name, \
sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \
0, \
NULL, \
0, \
NULL, \
descriptor, \
acquire, \
release \
@ -342,9 +337,6 @@ struct lumiera_interfaceslot_struct
*/
struct lumiera_interface_struct
{
/** all known interfaces are registered in a tree */
psplaynode node;
/** name of the interface (type) */
const char* interface;
@ -357,12 +349,6 @@ struct lumiera_interface_struct
/** size of the whole interface structure (minor version) */
size_t size;
/** reference counters and link used for internal reference management */
unsigned refcnt;
LumieraInterface lnk;
size_t ndeps;
LumieraInterface* deps;
/** metadata descriptor, itself a interface (or NULL) */
LumieraInterface descriptor;
@ -391,17 +377,6 @@ struct lumiera_interface_struct
*/
/**
* Open an interface by handle.
* This is faster because it needs no lookup, one must be sure to have a valid handle
* which mets the requirements (version)
* @param self pointer to the interface to be opened
* @return self on success or NULL on error
* @internal This function is mostly for internal purposes
*/
LumieraInterface
lumiera_interface_open_interface (LumieraInterface self);
/**
* Open an interface by version and name.
* Looks up the requested interface, possibly loading it from a plugin.