diff --git a/src/lib/plugin.c b/src/lib/plugin.c index 18c4b7630..364dc3b7a 100644 --- a/src/lib/plugin.c +++ b/src/lib/plugin.c @@ -5,16 +5,42 @@ #include "plugin.h" +/* TODO should be set by the build system to the actual plugin path */ +#define CINELERRA_PLUGIN_PATH "~/.cinelerra3/plugins:/usr/local/lib/cinelerra3/plugins" + +/* recognized extensions */ +#define CINELERRA_PLUGIN_EXT "plugin:so" + +/* + For future: + #define CINELERRA_PLUGIN_EXT "plugin:so:cplugin:c" + imagine using C source plugins compiled with libtcc on the fly +*/ + NOBUG_DEFINE_FLAG (cinelerra_plugin); +/* errors */ +const char* CINELERRA_PLUGIN_SUCCESS = NULL; +const char* CINELERRA_PLUGIN_EALLOC = "Memory allocation failure"; +const char* CINELERRA_PLUGIN_ENFOUND = "No such plugin"; +const char* CINELERRA_PLUGIN_ENIFACE = "No such interface"; +const char* CINELERRA_PLUGIN_EREVISION = "Interface revision too old"; struct cinelerra_plugin { - const char* name; /*TODO store full and short name, sort by shortname?*/ + /* short name as queried ("effects/audio/normalize") used for sorting/finding */ + const char* name; + + /* long names as looked up ("/usr/local/lib/cinelerra3/plugins/effects/audio/normalize.so") */ + const char* pathname; + + /* pointer to the extension part of 'pathname' */ + const char* ext; /* use count for all interfaces of this plugin */ unsigned use_count; + /* time when the last open or close action happened */ time_t last; /* dlopen handle */ @@ -24,28 +50,62 @@ struct cinelerra_plugin /* global plugin registry */ void* cinelerra_plugin_registry = NULL; +/* plugin operations are protected by one big mutex */ +pthread_mutex_t cinelerra_plugin_mutex = PTHREAD_MUTEX_INITIALIZER; +/* Thread local storage, for now only the error state */ +static pthread_key_t cinelerra_plugin_tls_error; +static pthread_once_t cinelerra_plugin_initialized = PTHREAD_ONCE_INIT; + +void +cinelerra_plugin_tls_init (void) +{ + pthread_key_create (&cinelerra_plugin_tls_error, NULL); +} + +/* the compare function for the registry tree */ static int -cmp_plugin_name (const void* a, const void* b) +cinelerra_plugin_name_cmp (const void* a, const void* b) { return strcmp (((struct cinelerra_plugin*) a)->name, ((struct cinelerra_plugin*) b)->name); } +const char* +cinelerra_plugin_lookup (struct cinelerra_plugin* self, const char* name, const char* path, const char* ext) +{ + /*for each in path*/ + /*for each extension*/ + /*try to find name*/ + +} + struct cinelerra_interface* cinelerra_interface_open (const char* name, const char* interface, size_t min_revision) { REQUIRE (min_revision > sizeof(cinelerra_interface), "try to use an empty interface eh?"); - REQUIRE (interface, "interface name must be defined"); + REQUIRE (interface, "interface name must be given"); + + pthread_mutex_lock (&cinelerra_plugin_mutex); + + pthread_once (&cinelerra_plugin_initialized, cinelerra_plugin_tls_init); struct cinelerra_plugin plugin; struct cinelerra_plugin** found; - // TODO cook somewhere (pluginpath+name+.so) + // if (name) (NULL means main app) + + /*lookup for $CINELERRA_PLUGIN_PATH*/ + + /* else lookup for -DCINELERRA_PLUGIN_PATH */ +#ifdef CINELERRA_PLUGIN_PATH +#endif + /* else fail */ + plugin.name = name; - found = tsearch (&plugin, &cinelerra_plugin_registry, cmp_plugin_name); + found = tsearch (&plugin, &cinelerra_plugin_registry, cinelerra_plugin_name_cmp); if (!found) - return NULL; + goto ealloc0; if (*found == &plugin) { @@ -107,6 +167,7 @@ cinelerra_interface_open (const char* name, const char* interface, size_t min_re (*found)->use_count++; ret->use_count++; + pthread_mutex_unlock (&cinelerra_plugin_mutex); return ret; /* Error cleanup */ @@ -121,7 +182,9 @@ cinelerra_interface_open (const char* name, const char* interface, size_t min_re free (*found); ealloc1: *found = &plugin; - tdelete (&plugin, &cinelerra_plugin_registry, cmp_plugin_name); + tdelete (&plugin, &cinelerra_plugin_registry, cinelerra_plugin_name_cmp); + ealloc0: + pthread_mutex_lock (&cinelerra_plugin_mutex); return NULL; } @@ -131,6 +194,8 @@ cinelerra_interface_close (struct cinelerra_interface* self) if(!self) return; + pthread_mutex_lock (&cinelerra_plugin_mutex); + struct cinelerra_plugin* plugin = self->plugin; plugin->use_count--; @@ -151,9 +216,10 @@ cinelerra_interface_close (struct cinelerra_interface* self) destroy(); /* and now cleanup */ - tdelete (plugin, &cinelerra_plugin_registry, cmp_plugin_name); + tdelete (plugin, &cinelerra_plugin_registry, cinelerra_plugin_name_cmp); free ((char*)plugin->name); dlclose(plugin->handle); free (plugin); } + pthread_mutex_unlock (&cinelerra_plugin_mutex); } diff --git a/src/lib/plugin.h b/src/lib/plugin.h index 409d954e9..573d4a6ca 100644 --- a/src/lib/plugin.h +++ b/src/lib/plugin.h @@ -119,6 +119,10 @@ cinelerra_plugin_expire (time_t age); const char* cinelerra_plugin_error (); +/// success, NULL +extern const char* CINELERRA_PLUGIN_SUCCESS; +/// memory allocation error +extern const char* CINELERRA_PLUGIN_EALLOC; /// Plugin not found extern const char* CINELERRA_PLUGIN_ENFOUND; /// no such interface