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) Lumiera.org
5  2008, Christian Thaeter <ct@pipapo.org>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
33 #include "include/logging.h"
34 
35 #include "lib/recmutex.h"
36 #include "lib/safeclib.h"
37 
38 #include "common/plugin.h"
39 #include "common/interface.h"
40 
42 
43 #include <nobug.h>
44 
45 
46 
48 LumieraInterface lumiera_interface_interface;
49 
50 static LumieraInterfacenode
51 lumiera_interface_open_interfacenode (LumieraInterfacenode self);
52 
53 static void
54 lumiera_interfacenode_close (LumieraInterfacenode self);
55 
56 
57 LumieraInterface
58 lumiera_interface_open (const char* interface, unsigned version, size_t minminorversion, const char* name)
59 {
60  LumieraInterfacenode self = NULL;
61  TRACE (interface, "%s", name);
62  WARN_IF (version == 0, interface, "opening experimental interface: %s_%d_%s", interface, version, name);
63 
64  LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex)
65  {
66  self = lumiera_interfaceregistry_interfacenode_find (interface, version, name);
67 
68  if (!self)
69  {
70  UNIMPLEMENTED ("query plugindb and load plugin if exists");
71  }
72 
73  if (self)
74  {
75  if (minminorversion > self->interface->size)
76  {
77  UNIMPLEMENTED ("set error");
78  self = NULL;
79  }
80  else
81  {
82  self = lumiera_interface_open_interfacenode (self);
83  }
84  }
85  }
86  return self->interface;
87 }
88 
89 
90 static void
91 push_dependency (LumieraInterfacenode parent, LumieraInterfacenode child)
92 {
93  /* push a dependency on the dependency array, allocate or resize it on demand */
94  TRACE (interface_dbg, "%s %s", parent->interface->name, child->interface->name);
95 
96  /* no dependencies recorded yet, allocate a first block for 4 pointers */
97  if (!parent->deps_size)
98  parent->deps = lumiera_calloc (parent->deps_size = 4, sizeof (LumieraInterfacenode));
99 
100  size_t sz = parent->deps_size;
101  LumieraInterfacenode* itr = parent->deps;
102 
103  while (*itr)
104  {
105  --sz;
106  ++itr;
107  if (sz == 1)
108  {
109  /* block too small, realloc it with twice its size, we keep the block NULL terminated */
110  sz = parent->deps_size + 1;
111  parent->deps_size *= 2;
112  parent->deps = lumiera_realloc (parent->deps, parent->deps_size * sizeof (LumieraInterface));
113  itr = parent->deps + sz - 2;
114  memset (itr, 0, sz * sizeof (LumieraInterface));
115  }
116  }
117 
118  /* found free element, store self in dependencies */
119  *itr = child;
120 }
121 
122 
123 static void
124 depwalk (LumieraInterfacenode self, LumieraInterfacenode* stack)
125 {
126  /* increment refcount for all non-cyclic dependencies recursively */
127  if (self->deps)
128  {
129  TRACE (interface_dbg, "%s %d", self->interface->name, self->refcnt);
130  for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
131  {
132  TRACE (interface_dbg, "loop %s", (*dep)->interface->name);
133  int cycle = 0;
134  for (LumieraInterfacenode itr = *stack; itr; itr = itr->lnk)
135  {
136  if (itr == *dep)
137  {
138  TRACE (interface_dbg, "CYCLE");
139  cycle = 1;
140  break;
141  }
142  }
143 
144  if (!cycle)
145  {
146  if ((*dep)->plugin)
147  lumiera_plugin_refinc ((*dep)->plugin);
148  ++(*dep)->refcnt;
149  (*dep)->lnk = *stack;
150  *stack = *dep;
151 
152  depwalk (*dep, stack);
153 
154  *stack = (*dep)->lnk;
155  (*dep)->lnk = NULL;
156  }
157  }
158  }
159 }
160 
161 
162 static LumieraInterfacenode
163 lumiera_interface_open_interfacenode (LumieraInterfacenode self)
164 {
165  static unsigned collect_dependencies = 0;
166  static LumieraInterfacenode stack = NULL;
167 
168  /*
169  OK, this got little more complicated than it should be,
170  but finally it handles any kind of cross dependencies between interfaces gracefully
171  */
172 
173  if (self)
174  {
175  TRACE (interface_dbg, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
176 
177  LUMIERA_RECMUTEX_SECTION (mutex_sync, &lumiera_interface_mutex)
178  {
179  /* discover cycles, cycles don't refcount! */
180  int cycle = 0;
181 
182  for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
183  {
184  if (itr == self)
185  {
186  TRACE (interface_dbg, "CYCLE");
187  cycle = 1;
188  break;
189  }
190  }
191 
192  /* 'stack' is ensured to be !NULL here because only a parent call can switch collect_dependencies on */
193  if (collect_dependencies)
194  push_dependency (stack, self);
195 
196  if (!cycle)
197  {
198  if (self->plugin)
199  lumiera_plugin_refinc (self->plugin);
200  ++self->refcnt;
201 
202  self->lnk = stack;
203  stack = self;
204  int collect_dependencies_bak = collect_dependencies;
205 
206  if (self->refcnt == 1)
207  {
208  /* first opening, run acquire, recursive opening shall record its dependencies here */
209  if (self->interface->acquire)
210  {
211  TRACE (interface_dbg, "Acquire %s", self->interface->name);
212  collect_dependencies = self->deps?0:1;
213  self->interface = self->interface->acquire (self->interface, lumiera_interface_interface);
214  }
215  }
216  else
217  {
218  /* opening again recurse dependencies */
219  collect_dependencies = 0;
220  depwalk (self, &stack);
221  }
222 
223  collect_dependencies = collect_dependencies_bak;
224  stack = self->lnk;
225  self->lnk = NULL;
226  }
227  }
228  }
229 
230  return self;
231 }
232 
233 
234 void
235 lumiera_interface_close (LumieraInterface self)
236 {
237  TRACE (interface_dbg);
238 
239  LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
240  {
241  lumiera_interfacenode_close ((LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, self, 100));
242  }
243 }
244 
245 
246 unsigned
247 lumiera_interface_version (LumieraInterface self, const char* iname)
248 {
249  if (self && iname && !strcmp (self->interface, iname))
250  return self->version;
251 
252  return ~0;
253 }
254 
255 
256 /* internal function, does no locking! */
257 static void
258 lumiera_interfacenode_close (LumieraInterfacenode self)
259 {
260  static LumieraInterfacenode stack = NULL;
261 
262  if (!self)
263  return;
264 
265  TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
266 
267  REQUIRE (self->refcnt);
268 
269  int cycle = 0;
270 
271  for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
272  {
273  if (itr == self)
274  {
275  TRACE (interface_dbg, "CYCLE");
276  cycle = 1;
277  break;
278  }
279  }
280 
281  if (!cycle)
282  {
283  self->lnk = stack;
284  stack = self;
285 
286  if (self->refcnt == 1)
287  {
288  if (self->interface->release)
289  {
290  TRACE (interface_dbg, "Release %s", self->interface->name);
291  self->interface->release (self->interface);
292  }
293  }
294  else
295  {
296  if (self->deps)
297  {
298  TRACE (interface_dbg, "Recurse %s %d", self->interface->name, self->refcnt);
299 
300  for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
301  lumiera_interfacenode_close (*dep);
302  }
303  }
304 
305  stack = self->lnk;
306  self->lnk = NULL;
307  if (self->plugin)
308  lumiera_plugin_refdec (self->plugin);
309  --self->refcnt;
310  }
311 }
312 
319  LUMIERA_INTERFACE_DEFINE (lumieraorg_interface, 0,
320  lumieraorg_interface,
321  NULL,
322  NULL,
323  NULL,
324  LUMIERA_INTERFACE_MAP (open,
326  LUMIERA_INTERFACE_MAP (close,
328  LUMIERA_INTERFACE_MAP (version,
330  )
331  )
332 
333 
334 void
336 {
339  lumiera_interface_open ("lumieraorg_interface", 0, 0, "lumieraorg_interface");
340 }
341 
342 void
344 {
347 }
348 
349 /*
350 // Local Variables:
351 // mode: C
352 // c-file-style: "gnu"
353 // indent-tabs-mode: nil
354 // End:
355 */
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:139
#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx)
Recursive Mutual exclusive section.
Definition: recmutex.h:41
void lumiera_interface_destroy(void)
deregistering implementations of the above interface
Definition: interface.c:343
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:58
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:318
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:247
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:309
#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:333
Lumiera interface macros and structures.
void lumiera_plugin_refinc(LumieraPlugin self)
Definition: plugin.c:181
void lumiera_interface_close(LumieraInterface self)
Close an interface after use.
Definition: interface.c:235
void * lumiera_realloc(void *ptr, size_t size)
Change the size of a memory block.
Definition: safeclib.c:158
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:339
ElementBoxWidget::Config::Qualifier name(string id)
define the name-ID displayed in the caption
void lumiera_plugin_refdec(LumieraPlugin self)
Definition: plugin.c:188
LumieraInterface lumiera_interface_interface
the mother of all interfaces
Definition: interface.c:48