Lumiera  0.pre.03
»edit your freedom«
interface.c
Go to the documentation of this file.
1 /*
2  Interface - Lumiera interface handling
3 
4  Copyright (C)
5  2008, Christian Thaeter <ct@pipapo.org>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
14 
24 #include "include/logging.h"
25 
26 #include "lib/recmutex.h"
27 #include "lib/safeclib.h"
28 
29 #include "common/plugin.h"
30 #include "common/interface.h"
31 
33 
34 #include <nobug.h>
35 
36 
37 
39 LumieraInterface lumiera_interface_interface;
40 
41 static LumieraInterfacenode
42 lumiera_interface_open_interfacenode (LumieraInterfacenode self);
43 
44 static void
45 lumiera_interfacenode_close (LumieraInterfacenode self);
46 
47 
48 LumieraInterface
49 lumiera_interface_open (const char* interface, unsigned version, size_t minminorversion, const char* name)
50 {
51  LumieraInterfacenode self = NULL;
52  TRACE (interface, "%s", name);
53  WARN_IF (version == 0, interface, "opening experimental interface: %s_%d_%s", interface, version, name);
54 
55  LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex)
56  {
57  self = lumiera_interfaceregistry_interfacenode_find (interface, version, name);
58 
59  if (!self)
60  {
61  UNIMPLEMENTED ("query plugindb and load plugin if exists");
62  }
63 
64  if (self)
65  {
66  if (minminorversion > self->interface->size)
67  {
68  UNIMPLEMENTED ("set error");
69  self = NULL;
70  }
71  else
72  {
73  self = lumiera_interface_open_interfacenode (self);
74  }
75  }
76  }
77  return self->interface;
78 }
79 
80 
81 static void
82 push_dependency (LumieraInterfacenode parent, LumieraInterfacenode child)
83 {
84  /* push a dependency on the dependency array, allocate or resize it on demand */
85  TRACE (interface_dbg, "%s %s", parent->interface->name, child->interface->name);
86 
87  /* no dependencies recorded yet, allocate a first block for 4 pointers */
88  if (!parent->deps_size)
89  parent->deps = lumiera_calloc (parent->deps_size = 4, sizeof (LumieraInterfacenode));
90 
91  size_t sz = parent->deps_size;
92  LumieraInterfacenode* itr = parent->deps;
93 
94  while (*itr)
95  {
96  --sz;
97  ++itr;
98  if (sz == 1)
99  {
100  /* block too small, realloc it with twice its size, we keep the block NULL terminated */
101  sz = parent->deps_size + 1;
102  parent->deps_size *= 2;
103  parent->deps = lumiera_realloc (parent->deps, parent->deps_size * sizeof (LumieraInterface));
104  itr = parent->deps + sz - 2;
105  memset (itr, 0, sz * sizeof (LumieraInterface));
106  }
107  }
108 
109  /* found free element, store self in dependencies */
110  *itr = child;
111 }
112 
113 
114 static void
115 depwalk (LumieraInterfacenode self, LumieraInterfacenode* stack)
116 {
117  /* increment refcount for all non-cyclic dependencies recursively */
118  if (self->deps)
119  {
120  TRACE (interface_dbg, "%s %d", self->interface->name, self->refcnt);
121  for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
122  {
123  TRACE (interface_dbg, "loop %s", (*dep)->interface->name);
124  int cycle = 0;
125  for (LumieraInterfacenode itr = *stack; itr; itr = itr->lnk)
126  {
127  if (itr == *dep)
128  {
129  TRACE (interface_dbg, "CYCLE");
130  cycle = 1;
131  break;
132  }
133  }
134 
135  if (!cycle)
136  {
137  if ((*dep)->plugin)
138  lumiera_plugin_refinc ((*dep)->plugin);
139  ++(*dep)->refcnt;
140  (*dep)->lnk = *stack;
141  *stack = *dep;
142 
143  depwalk (*dep, stack);
144 
145  *stack = (*dep)->lnk;
146  (*dep)->lnk = NULL;
147  }
148  }
149  }
150 }
151 
152 
153 static LumieraInterfacenode
154 lumiera_interface_open_interfacenode (LumieraInterfacenode self)
155 {
156  static unsigned collect_dependencies = 0;
157  static LumieraInterfacenode stack = NULL;
158 
159  /*
160  OK, this got little more complicated than it should be,
161  but finally it handles any kind of cross dependencies between interfaces gracefully
162  */
163 
164  if (self)
165  {
166  TRACE (interface_dbg, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
167 
168  LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex)
169  {
170  /* discover cycles, cycles don't refcount! */
171  int cycle = 0;
172 
173  for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
174  {
175  if (itr == self)
176  {
177  TRACE (interface_dbg, "CYCLE");
178  cycle = 1;
179  break;
180  }
181  }
182 
183  /* 'stack' is ensured to be !NULL here because only a parent call can switch collect_dependencies on */
184  if (collect_dependencies)
185  push_dependency (stack, self);
186 
187  if (!cycle)
188  {
189  if (self->plugin)
190  lumiera_plugin_refinc (self->plugin);
191  ++self->refcnt;
192 
193  self->lnk = stack;
194  stack = self;
195  int collect_dependencies_bak = collect_dependencies;
196 
197  if (self->refcnt == 1)
198  {
199  /* first opening, run acquire, recursive opening shall record its dependencies here */
200  if (self->interface->acquire)
201  {
202  TRACE (interface_dbg, "Acquire %s", self->interface->name);
203  collect_dependencies = self->deps?0:1;
204  self->interface = self->interface->acquire (self->interface, lumiera_interface_interface);
205  }
206  }
207  else
208  {
209  /* opening again recurse dependencies */
210  collect_dependencies = 0;
211  depwalk (self, &stack);
212  }
213 
214  collect_dependencies = collect_dependencies_bak;
215  stack = self->lnk;
216  self->lnk = NULL;
217  }
218  }
219  }
220 
221  return self;
222 }
223 
224 
225 void
226 lumiera_interface_close (LumieraInterface self)
227 {
228  TRACE (interface_dbg);
229 
230  LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
231  {
232  lumiera_interfacenode_close ((LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, self, 100));
233  }
234 }
235 
236 
237 unsigned
238 lumiera_interface_version (LumieraInterface self, const char* iname)
239 {
240  if (self && iname && !strcmp (self->interface, iname))
241  return self->version;
242 
243  return ~0;
244 }
245 
246 
247 /* internal function, does no locking! */
248 static void
249 lumiera_interfacenode_close (LumieraInterfacenode self)
250 {
251  static LumieraInterfacenode stack = NULL;
252 
253  if (!self)
254  return;
255 
256  TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
257 
258  REQUIRE (self->refcnt);
259 
260  int cycle = 0;
261 
262  for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
263  {
264  if (itr == self)
265  {
266  TRACE (interface_dbg, "CYCLE");
267  cycle = 1;
268  break;
269  }
270  }
271 
272  if (!cycle)
273  {
274  self->lnk = stack;
275  stack = self;
276 
277  if (self->refcnt == 1)
278  {
279  if (self->interface->release)
280  {
281  TRACE (interface_dbg, "Release %s", self->interface->name);
282  self->interface->release (self->interface);
283  }
284  }
285  else
286  {
287  if (self->deps)
288  {
289  TRACE (interface_dbg, "Recurse %s %d", self->interface->name, self->refcnt);
290 
291  for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
292  lumiera_interfacenode_close (*dep);
293  }
294  }
295 
296  stack = self->lnk;
297  self->lnk = NULL;
298  if (self->plugin)
299  lumiera_plugin_refdec (self->plugin);
300  --self->refcnt;
301  }
302 }
303 
310  LUMIERA_INTERFACE_DEFINE (lumieraorg_interface, 0,
311  lumieraorg_interface,
312  NULL,
313  NULL,
314  NULL,
315  LUMIERA_INTERFACE_MAP (open,
317  LUMIERA_INTERFACE_MAP (close,
319  LUMIERA_INTERFACE_MAP (version,
321  )
322  )
323 
324 
325 void
327 {
330  lumiera_interface_open ("lumieraorg_interface", 0, 0, "lumieraorg_interface");
331 }
332 
333 void
335 {
338 }
339 
340 /*
341 // Local Variables:
342 // mode: C
343 // c-file-style: "gnu"
344 // indent-tabs-mode: nil
345 // End:
346 */
Portable and safe wrappers around some C-Lib functions.
void * lumiera_calloc(size_t n, size_t size)
Allocate cleared memory for an array.
Definition: safeclib.c:130
#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx)
Recursive Mutual exclusive section.
Definition: recmutex.h:32
void lumiera_interface_destroy(void)
deregistering implementations of the above interface
Definition: interface.c:334
LumieraInterface lumiera_interface_open(const char *interface, unsigned version, size_t minminorversion, const char *name)
Open an interface by version and name.
Definition: interface.c:49
LUMIERA_EXPORT(LUMIERA_INTERFACE_DEFINE(lumieraorg_interface, 0, lumieraorg_interface, NULL, NULL, NULL, LUMIERA_INTERFACE_MAP(open, lumiera_interface_open), LUMIERA_INTERFACE_MAP(close, lumiera_interface_close), LUMIERA_INTERFACE_MAP(version, lumiera_interface_version),))
Definition of &#39;the mother of all interfaces&#39; since this interface is singleton and required for any c...
Definition: interface.c:309
void lumiera_interface_init(void)
registering implementations of the above interface
Lumiera plugins define &#39;interfaces&#39; as shown in interface.h, the plugin system handles the loading of...
unsigned lumiera_interface_version(LumieraInterface self, const char *iname)
Runtime check for interface type and version.
Definition: interface.c:238
This header is for including and configuring NoBug.
Mutual exclusion locking, header.
PSplaynode psplay_find(PSplay self, const void *key, int splayfactor)
Find a element in a splay tree.
Definition: psplay.c:300
#define LUMIERA_INTERFACE_REGISTEREXPORTED
Register all exported interfaces when not a plugin This is a no-op when LUMIERA_PLUGIN is defined...
Definition: interface.h:324
Lumiera interface macros and structures.
void lumiera_plugin_refinc(LumieraPlugin self)
Definition: plugin.c:172
void lumiera_interface_close(LumieraInterface self)
Close an interface after use.
Definition: interface.c:226
void * lumiera_realloc(void *ptr, size_t size)
Change the size of a memory block.
Definition: safeclib.c:149
Global registry for interfaces (extension points).
#define LUMIERA_INTERFACE_UNREGISTEREXPORTED
Unregister all exported interfaces when not a plugin This is a no-op when LUMIERA_PLUGIN is defined...
Definition: interface.h:330
ElementBoxWidget::Config::Qualifier name(string id)
define the name-ID displayed in the caption
void lumiera_plugin_refdec(LumieraPlugin self)
Definition: plugin.c:179
LumieraInterface lumiera_interface_interface
the mother of all interfaces
Definition: interface.c:39