Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
plugin.c
Go to the documentation of this file.
1/*
2 Plugin - Lumiera Plugin loader implementation
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
21#include "include/logging.h"
22#include "lib/safeclib.h"
23#include "lib/tmpbuf.h"
24#include "lib/psplay.h"
25#include "lib/recmutex.h"
26#include "lib/error.h"
27
30#include "common/config.h"
31#include "common/plugin.h"
32
33#include <glob.h>
34
35#include <nobug.h>
36
37
38
40static char* init_exts_globs (void);
41
42
43
44/* errors */
45LUMIERA_ERROR_DEFINE(PLUGIN_INIT, "Initialisation error");
46LUMIERA_ERROR_DEFINE(PLUGIN_OPEN, "Could not open plugin");
47LUMIERA_ERROR_DEFINE(PLUGIN_WTF, "Not a Lumiera plugin");
48LUMIERA_ERROR_DEFINE(PLUGIN_REGISTER, "Could not register plugin");
49LUMIERA_ERROR_DEFINE(PLUGIN_VERSION, "Plugin Version unsupported");
50
51#define LUMIERA_PLUGIN_TYPE_PLANNED(name, ext)
52
59#define LUMIERA_PLUGIN_TYPES \
60 LUMIERA_PLUGIN_TYPE(DYNLIB, ".so") \
61 LUMIERA_PLUGIN_TYPE(DYNLIB, ".lum") \
62 LUMIERA_PLUGIN_TYPE_PLANNED(LUA, ".lua") \
63 LUMIERA_PLUGIN_TYPE_PLANNED(CSOURCE, ".c")
64
65
75typedef struct lumiera_plugintype_struct lumiera_plugintype;
76typedef lumiera_plugintype* LumieraPlugintype;
77
78/* forward declare loader functions for all types */
79#define LUMIERA_PLUGIN_TYPE(type, ext) \
80 LumieraPlugin lumiera_plugin_load_##type (const char*); \
81 void lumiera_plugin_unload_##type (LumieraPlugin);
83#undef LUMIERA_PLUGIN_TYPE
84
85/* and now setup a table which will be used for dispatching loaders depending on the type of the plugin */
86#define LUMIERA_PLUGIN_TYPE(type, ext) {lumiera_plugin_load_##type, lumiera_plugin_unload_##type, ext},
87static lumiera_plugintype lumiera_plugin_types[] =
88 {
90 {NULL, NULL, NULL}
91 };
92#undef LUMIERA_PLUGIN_TYPE
93
94
95
96
98{
99 psplaynode node;
100
101 /* long names as looked up ("/usr/local/lib/lumiera/plugins/effects/audio/normalize.so") */
102 const char* name;
103
104 /* use count for all interfaces of this plugin */
105 unsigned refcnt;
106
107 /* time when the refcounter dropped to 0 last time */
108 time_t last;
109
113
114 /* the 'plugin' interface itself */
116
117 /* generic handle for the plugin, dlopen handle, etc */
118 void* handle;
119};
120
121
123lumiera_plugin_new (const char* name)
124{
125 LumieraPlugin self = lumiera_malloc (sizeof (*self));
126
127 psplaynode_init (&self->node);
128 self->name = lumiera_strndup (name, SIZE_MAX);
129 self->refcnt = 0;
130 time (&self->last);
131 self->error = LUMIERA_ERROR_PLUGIN_INIT;
132 self->plugin = NULL;
133 self->handle = NULL;
134 return self;
135}
136
137
140{
141 self->error = lumiera_error ();
142 self->plugin = plugin;
143 self->handle = handle;
144 return self;
145}
146
147
150{
151 REQUIRE (self);
152 return self->error;
153}
154
155
156void*
158{
159 REQUIRE (self);
160 return self->handle;
161}
162
163
164const char*
166{
167 return self?self->name:NULL;
168}
169
170
171void
173{
174 ++self->refcnt;
175}
176
177
178void
180{
181 if (!--self->refcnt)
182 time (&self->last);
183}
184
185
186int
187lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin),
188 int (*callback_register) (LumieraPlugin))
189{
190 TRACE (pluginloader_dbg);
191 REQUIRE (callback_load);
192 REQUIRE (callback_register);
193
194 // Note: because the full-blown Config system isn't implemented yet,
195 // as a temporary solution we fetch this basic configuration
196 // from the setup.ini used to bootstrap the application
198
199 /* construct glob trail {.so,.lum,.lua} ... */
200 static char* exts_globs = NULL;
201 if (!exts_globs)
202 exts_globs = init_exts_globs ();
203
204 const char* path;
205 unsigned i = 0;
206 int flags = GLOB_PERIOD|GLOB_BRACE|GLOB_TILDE_CHECK;
207 glob_t globs;
208
209 while ((path = lumiera_config_wordlist_get_nth ("plugin.path", i, ":")))
210 {
211 path = lumiera_tmpbuf_snprintf (SIZE_MAX,"%s/%s", path, exts_globs);
212 TRACE (pluginloader_dbg, "globbing path '%s'", path);
213 int ret = glob (path, flags, NULL, &globs);
214 if (ret == GLOB_NOSPACE)
215 LUMIERA_DIE (NO_MEMORY);
216
217 flags |= GLOB_APPEND;
218 ++i;
219 }
220
221 if (globs.gl_pathc)
223 {
224 for (char** itr = globs.gl_pathv; *itr; ++itr)
225 {
226 if (!psplay_find (lumiera_pluginregistry, *itr, 100))
227 {
228 TRACE (pluginloader, "found new plugin '%s'", *itr);
229 callback_register (callback_load (*itr));
230 }
231 }
232 }
233
234 globfree (&globs);
235
236 return !lumiera_error_peek ();
237}
238
239
241lumiera_plugin_load (const char* plugin)
242{
243 TRACE (pluginloader_dbg, "plugin=%s", plugin);
244
245 /* dispatch on extension, call the registered function */
246 const char* ext = strrchr (plugin, '.');
247
249 while (itr->ext)
250 {
251 if (!strcmp (itr->ext, ext))
252 return itr->lumiera_plugin_load_fn (plugin);
253 ++itr;
254 }
255 return NULL;
256}
257
258
259int
261{
262 TRACE (pluginloader_dbg);
263 if (!plugin)
264 return 1;
265
267 {
268 if (psplay_insert (lumiera_pluginregistry, &plugin->node, 100))
269 {
270 if (!plugin->error)
271 {
272 switch (lumiera_interface_version (plugin->plugin, "lumieraorg__plugin"))
273 {
274 case 0:
275 {
276 TRACE (pluginloader, "registering %s", plugin->name);
277 LUMIERA_INTERFACE_HANDLE(lumieraorg__plugin, 0) handle =
278 LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) plugin->plugin;
279 lumiera_interfaceregistry_bulkregister_interfaces (handle->plugin_interfaces (), plugin);
280 }
281 break;
282 default:
283 LUMIERA_ERROR_SET (pluginloader, PLUGIN_VERSION, plugin->name);
284 }
285 }
286 }
287 else
288 {
289 LUMIERA_ERROR_SET_CRITICAL (pluginloader, PLUGIN_REGISTER, plugin->name);
290 }
291 }
292 return !!lumiera_error_peek();
293}
294
295
296unsigned
298{
299 TRACE (pluginloader_dbg);
300
301 if (!self)
302 return 0;
303
304 if (self->refcnt)
305 return self->refcnt;
306
307 /* dispatch on extension, call the registered function */
308 const char* ext = strrchr (self->name, '.');
309
311 while (itr->ext)
312 {
313 if (!strcmp (itr->ext, ext))
314 {
316 {
317 if (psplay_remove (lumiera_pluginregistry, &self->node))
318 {
319 if (!self->error)
320 {
321 LUMIERA_INTERFACE_HANDLE(lumieraorg__plugin, 0) handle =
322 LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) self->plugin;
323 lumiera_interfaceregistry_bulkremove_interfaces (handle->plugin_interfaces ());
324 }
325 }
326 }
327 itr->lumiera_plugin_unload_fn (self);
328 break;
329 }
330 ++itr;
331 }
332
333 return 0;
334}
335
336
338lumiera_plugin_lookup (const char* name)
339{
340 LumieraPlugin ret = NULL;
341
342 if (name)
345
346 return ret;
347}
348
349
350static char* init_exts_globs (void)
351{
352 char* exts_globs;
353 size_t exts_sz = 3; /* * { } \0 less one comma */
355 while (itr->ext)
356 {
357 exts_sz += strlen (itr->ext) + 1;
358 ++itr;
359 }
360
361 exts_globs = lumiera_malloc (exts_sz);
362 *exts_globs = '\0';
363
365 strcat (exts_globs, "*{");
366
367 while (itr->ext)
368 {
369 strcat (exts_globs, itr->ext);
370 strcat (exts_globs, ",");
371 ++itr;
372 }
373 exts_globs[exts_sz-2] = '}';
374 TRACE (pluginloader_dbg, "initialised extension glob to '%s'", exts_globs);
375 return exts_globs;
376}
377
378int
379lumiera_plugin_cmp_fn (const void* keya, const void* keyb)
380{
381 return strcmp ((const char*)keya, (const char*)keyb);
382}
383
384
385const void*
387{
388 return ((LumieraPlugin)node)->name;
389}
390
391
392void
394{
395 LumieraPlugin self = (LumieraPlugin) node;
396
397 ENSURE (!self->refcnt, "plugin %s still in use at shutdown", self->name);
398
399 const char* ext = strrchr (self->name, '.');
400
402 while (itr->ext)
403 {
404 if (!strcmp (itr->ext, ext))
405 {
406 if (!self->error)
407 {
408 LUMIERA_INTERFACE_HANDLE(lumieraorg__plugin, 0) handle =
409 LUMIERA_INTERFACE_CAST(lumieraorg__plugin, 0) self->plugin;
410 lumiera_interfaceregistry_bulkremove_interfaces (handle->plugin_interfaces ());
411 }
412 TRACE (pluginloader_dbg, "unloading plugin/module %s", self->name);
413 itr->lumiera_plugin_unload_fn (self);
414 break;
415 }
416 ++itr;
417 }
418}
The lumiera::Config wrapper class addresses two issues.
const char * lumiera_config_wordlist_get_nth(const char *key, unsigned nth, const char *delims)
return nth word of a wordlist
LumieraConfigitem lumiera_config_setdefault(const char *line)
Installs a default value for a config key.
Definition config.c:265
Interface for a lumiera configuration system (draft).
const char * lumiera_get_plugin_path_default()
lumiera_err lumiera_error_peek(void)
Check current error state without clearing it Please avoid this function and use lumiera_error() if p...
lumiera_err lumiera_error(void)
Get and clear current error state.
Lumiera error handling (C interface).
#define LUMIERA_ERROR_SET_CRITICAL(flag, err, extra)
Helper macro to raise an error for the current thread.
Definition error.h:112
#define LUMIERA_ERROR_SET(flag, err, extra)
Helper macro to raise an error for the current thread.
Definition error.h:82
#define LUMIERA_DIE(err)
Abort unconditionally with a 'Fatal Error!' message.
Definition error.h:54
const char * lumiera_err
Definition error.h:48
#define LUMIERA_ERROR_DEFINE(err, msg)
Definition and initialisation of an error constant.
Definition error.h:71
unsigned lumiera_interface_version(LumieraInterface self, const char *iname)
Runtime check for interface type and version.
Definition interface.c:238
#define LUMIERA_INTERFACE_CAST(name, version)
Construct a cast to the target interface type Used to cast a generic LumieraInterface to the real typ...
Definition interface.h:137
lumiera_interface * LumieraInterface
Definition interface.h:355
#define LUMIERA_INTERFACE_HANDLE(interface, version)
create a handle for a interface (WIP)
Definition interface.h:347
lumiera_recmutex lumiera_interface_mutex
void lumiera_interfaceregistry_bulkremove_interfaces(LumieraInterface *self)
void lumiera_interfaceregistry_bulkregister_interfaces(LumieraInterface *self, LumieraPlugin plugin)
Global registry for interfaces (extension points).
return NULL
Definition llist.h:586
This header is for including and configuring NoBug.
void lumiera_plugin_refdec(LumieraPlugin self)
Definition plugin.c:179
void lumiera_plugin_refinc(LumieraPlugin self)
Definition plugin.c:172
static char * init_exts_globs(void)
Definition plugin.c:350
lumiera_err error
bulk loading plugins must not fail entirely, just because one plugin doesn't comply.
Definition plugin.c:112
void lumiera_plugin_delete_fn(PSplaynode node)
Definition plugin.c:393
LumieraPlugin lumiera_plugin_lookup(const char *name)
Lookup a plugin handle in the pluginregistry.
Definition plugin.c:338
#define LUMIERA_PLUGIN_TYPES
Supported (and planned) plugin types and their file extensions This maps filename extensions to imple...
Definition plugin.c:59
LumieraPlugin lumiera_plugin_load(const char *plugin)
Tries to load a plugin Creates a new plugin structure and tries to load and initialise the plugin.
Definition plugin.c:241
int lumiera_plugin_register(LumieraPlugin plugin)
Register a plugin and its interfaces.
Definition plugin.c:260
void * lumiera_plugin_handle(LumieraPlugin self)
Query the plugin handle.
Definition plugin.c:157
const char * name
Definition plugin.c:102
const char * lumiera_plugin_name(LumieraPlugin self)
Query the plugin name The name is the path and filename under which it was loaded.
Definition plugin.c:165
lumiera_plugintype * LumieraPlugintype
Definition plugin.c:76
LumieraInterface plugin
Definition plugin.c:115
lumiera_err lumiera_plugin_error(LumieraPlugin self)
Query the error state of a plugin.
Definition plugin.c:149
LumieraPlugin lumiera_plugin_init(LumieraPlugin self, void *handle, LumieraInterface plugin)
Definition plugin.c:139
unsigned lumiera_plugin_unload(LumieraPlugin self)
Tries to unload a plugin.
Definition plugin.c:297
int lumiera_plugin_discover(LumieraPlugin(*callback_load)(const char *plugin), int(*callback_register)(LumieraPlugin))
discover new plugins traverses the configured plugin paths and calls the callback_load function for a...
Definition plugin.c:187
PSplay lumiera_pluginregistry
psplaynode node
Definition plugin.c:99
const void * lumiera_plugin_key_fn(const PSplaynode node)
Definition plugin.c:386
static lumiera_plugintype lumiera_plugin_types[]
Definition plugin.c:87
LumieraPlugin lumiera_plugin_new(const char *name)
Allocates an preinitialises a plugin structure.
Definition plugin.c:123
int lumiera_plugin_cmp_fn(const void *keya, const void *keyb)
Definition plugin.c:379
Lumiera plugins define 'interfaces' as shown in interface.h, the plugin system handles the loading of...
lumiera_plugin * LumieraPlugin
Definition plugin.h:64
PSplaynode psplay_insert(PSplay self, PSplaynode node, int splayfactor)
Insert a element into a splay tree.
Definition psplay.c:246
PSplaynode psplaynode_init(PSplaynode self)
Initialise a splay tree node The user has to place this nodes within his datastructure and must Initi...
Definition psplay.c:122
PSplaynode psplay_remove(PSplay self, PSplaynode node)
Remove a node from a splay tree.
Definition psplay.c:340
PSplaynode psplay_find(PSplay self, const void *key, int splayfactor)
Find a element in a splay tree.
Definition psplay.c:300
Probabilistic splay tree.
psplaynode * PSplaynode
Definition psplay.h:40
psplay * PSplay
Definition psplay.h:82
Mutual exclusion locking, header.
#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx)
Recursive Mutual exclusive section.
Definition recmutex.h:32
char * lumiera_strndup(const char *str, size_t len)
Duplicate a C string.
Definition safeclib.c:166
void * lumiera_malloc(size_t size)
Allocate memory.
Definition safeclib.c:113
Portable and safe wrappers around some C-Lib functions.
record the extension and a callback function for loading the associated plugin for each plugin type
Definition plugin.c:70
void(* lumiera_plugin_unload_fn)(LumieraPlugin)
Definition plugin.c:72
LumieraPlugin(* lumiera_plugin_load_fn)(const char *)
Definition plugin.c:71
char * lumiera_tmpbuf_snprintf(size_t size, const char *fmt,...)
Construct a string in a tmpbuf.
Definition tmpbuf.c:116
Round robin temporary buffers.