diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/libtc/tcmodule.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/libtc/tcmodule.c | 1015 |
1 files changed, 1015 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/libtc/tcmodule.c b/debian/transcode/transcode-1.1.7/libtc/tcmodule.c new file mode 100644 index 00000000..ca2d59ff --- /dev/null +++ b/debian/transcode/transcode-1.1.7/libtc/tcmodule.c @@ -0,0 +1,1015 @@ +/* + * tcmodule.c -- transcode module system, take two. + * (C) 2005-2010 - Francesco Romani <fromani -at- gmail -dot- com> + * + * This file is part of transcode, a video stream processing tool. + * + * transcode is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * transcode is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "config.h" + +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#else +# ifdef OS_DARWIN +# include "libdldarwin/dlfcn.h" +# endif +#endif + +#include <string.h> + +#include "libtc.h" +#include "tccodecs.h" +#include "tcmodule-data.h" +#include "tcmodule-core.h" +#include "transcode.h" + +#define TC_FACTORY_MAX_HANDLERS (16) +#define MOD_TYPE_MAX_LEN (TC_BUF_MIN * 2) + +#define tc_module_init(module, features) \ + (module)->klass->init(&((module)->instance), features) +#define tc_module_fini(module) \ + (module)->klass->fini(&((module)->instance)) + +/* module entry point */ +typedef const TCModuleClass* (*TCModuleEntry)(void); + +typedef enum { + TC_DESCRIPTOR_FREE = 0, /* free to use */ + TC_DESCRIPTOR_CREATED, /* reserved, but not yet registered */ + TC_DESCRIPTOR_DONE, /* ok, all donw and ready to run */ +} TCHandleStatus; + +typedef struct tcmoduledescriptor_ TCModuleDescriptor; +struct tcmoduledescriptor_ { + const char *type; /* packed class + name using make_modtype below */ + void *so_handle; /* used by dl*() stuff */ + TCHandleStatus status; + TCModuleInfo info; + + /* main copy of module class data. + * all instance pointers will refer to this. */ + TCModuleClass klass; + + int ref_count; /* how many instances are floating around? */ +}; + +struct tcfactory_ { + const char *mod_path; /* base directory for plugin search */ + int verbose; + + TCModuleDescriptor descriptors[TC_FACTORY_MAX_HANDLERS]; + int descriptor_count; + + int instance_count; +}; + +/************************************************************************* + * dummy/fake default module class. Always fails complaining loudly. * + * Using this as default, every module class has already valid * + * (but sometimes useless) pointers to every method. * + *************************************************************************/ + +#define DUMMY_HEAVY_CHECK(self, method_name) do { \ + if (self != NULL) { \ + tc_log_warn(self->type, "critical: module doesn't provide" \ + " %s method", method_name); \ + } else { \ + tc_log_error(__FILE__, "critical: %s method missing AND bad" \ + " instance pointer", method_name); \ + } \ +} while (0) + +#define DUMMY_CHECK(self, method_name) do { \ + if (self != NULL) { \ + tc_log_warn(self->type, \ + "module doesn't provide %s method", method_name); \ + } else { \ + tc_log_error(__FILE__, "%s method missing AND bad" \ + " instance pointer", method_name); \ + } \ +} while (0) + + +static int dummy_init(TCModuleInstance *self, uint32_t features) +{ + DUMMY_HEAVY_CHECK(self, "initialization"); + return TC_ERROR; +} + +static int dummy_fini(TCModuleInstance *self) +{ + DUMMY_HEAVY_CHECK(self, "finalization"); + return TC_ERROR; +} + +static int dummy_configure(TCModuleInstance *self, + const char *options, vob_t *vob) +{ + DUMMY_HEAVY_CHECK(self, "configuration"); + return TC_ERROR; +} + +static int dummy_stop(TCModuleInstance *self) +{ + DUMMY_HEAVY_CHECK(self, "stopping"); + return TC_ERROR; +} + +static int dummy_inspect(TCModuleInstance *self, + const char *param, const char **value) +{ + DUMMY_HEAVY_CHECK(self, "inspect"); + return TC_ERROR; +} + +static int dummy_encode_video(TCModuleInstance *self, + vframe_list_t *inframe, + vframe_list_t *outframe) +{ + DUMMY_CHECK(self, "encode_video"); + return TC_ERROR; +} + +static int dummy_encode_audio(TCModuleInstance *self, + aframe_list_t *inframe, + aframe_list_t *outframe) +{ + DUMMY_CHECK(self, "encode_audio"); + return TC_ERROR; +} + +static int dummy_decode_video(TCModuleInstance *self, + vframe_list_t *inframe, + vframe_list_t *outframe) +{ + DUMMY_CHECK(self, "decode_video"); + return TC_ERROR; +} + +static int dummy_decode_audio(TCModuleInstance *self, + aframe_list_t *inframe, + aframe_list_t *outframe) +{ + DUMMY_CHECK(self, "decode_audio"); + return TC_ERROR; +} + +static int dummy_filter_video(TCModuleInstance *self, + vframe_list_t *frame) +{ + DUMMY_CHECK(self, "filter_video"); + return TC_ERROR; +} + +static int dummy_filter_audio(TCModuleInstance *self, + aframe_list_t *frame) +{ + DUMMY_CHECK(self, "filter_audio"); + return TC_ERROR; +} + +static int dummy_multiplex(TCModuleInstance *self, + vframe_list_t *vframe, aframe_list_t *aframe) +{ + DUMMY_CHECK(self, "multiplex"); + return TC_ERROR; +} + +static int dummy_demultiplex(TCModuleInstance *self, + vframe_list_t *vframe, aframe_list_t *aframe) +{ + DUMMY_CHECK(self, "demultiplex"); + return TC_ERROR; +} + +#undef DUMMY_HEAVY_CHECK +#undef DUMMY_CHECK + +static const TCCodecID dummy_codecs_in[] = { + TC_CODEC_ANY, TC_CODEC_ERROR +}; +static const TCCodecID dummy_codecs_out[] = { + TC_CODEC_ANY, TC_CODEC_ERROR +}; +static const TCFormatID dummy_formats_in[] = { + TC_FORMAT_RAW, TC_FORMAT_ERROR +}; +static const TCFormatID dummy_formats_out[] = { + TC_FORMAT_RAW, TC_FORMAT_ERROR +}; + +static TCModuleInfo dummy_info = { + .features = TC_MODULE_FEATURE_NONE, + .flags = TC_MODULE_FLAG_NONE, + .name = "dummy", + .version = "internal fake module class", + .description = "can't do anyhing", + .codecs_in = dummy_codecs_in, + .codecs_out = dummy_codecs_out, + .formats_in = dummy_formats_in, + .formats_out = dummy_formats_out +}; + +static const TCModuleClass dummy_class = { + .id = 0, + + .info = &dummy_info, + + .init = dummy_init, + .fini = dummy_fini, + .configure = dummy_configure, + .inspect = dummy_inspect, + .stop = dummy_stop, + + .encode_audio = dummy_encode_audio, + .encode_video = dummy_encode_video, + .decode_audio = dummy_decode_audio, + .decode_video = dummy_decode_video, + .filter_audio = dummy_filter_audio, + .filter_video = dummy_filter_video, + + .multiplex = dummy_multiplex, + .demultiplex = dummy_demultiplex +}; + +/************************************************************************* + * private helpers * + *************************************************************************/ + +/* + * translate_modclass: + * validate a module class name, represented by a given string. + * + * Parameters: + * modclass: a class nome to validate. + * Return Value: + * TC_MOFULE_FEATURE_* correspondent. + */ +static uint32_t translate_modclass(const char *modclass) +{ + uint32_t ret = TC_MODULE_FEATURE_NONE; + + if (modclass != NULL) { + if (!strcmp(modclass, "filter")) { + ret = TC_MODULE_FEATURE_FILTER; + } else if (!strcmp(modclass, "demultiplex") + || !strcmp(modclass, "demux")) { + ret = TC_MODULE_FEATURE_DEMULTIPLEX; + } else if (!strcmp(modclass, "decode")) { + ret = TC_MODULE_FEATURE_DECODE; + } else if (!strcmp(modclass, "encode")) { + ret = TC_MODULE_FEATURE_ENCODE; + } else if (!strcmp(modclass, "multiplex") + || !strcmp(modclass, "mplex")) { + ret = TC_MODULE_FEATURE_MULTIPLEX; + } + } + return ret; +} + +/* FIXME: writeme */ +static uint32_t translate_media(int media) +{ + uint32_t ret = TC_MODULE_FEATURE_NONE; + + switch (media) { + case TC_VIDEO: + ret = TC_MODULE_FEATURE_VIDEO; + break; + case TC_AUDIO: + ret = TC_MODULE_FEATURE_AUDIO; + break; + case TC_EXTRA: + ret = TC_MODULE_FEATURE_EXTRA; + break; + } + return ret; +} + +/* + * TCModuleDescriptorIter: + * generic iterator function on factory descriptors. + * In some different contexts, a iterator can be applied on all module + * descriptors in a given factory. Specific iterator functions can do + * arbitrary actions on descriptor data. + * See below to get some usage examples. + * + * Parameters: + * desc: pointer to a TCModuleDescriptor. + * userdata: opaque pointer to function-specific data. + * Return Value: + * 0 -> keep on going + * <0 -> stop iteration and return code verbatim + * >0 -> stop iteration and return current iteration index + * Side effects: + * Arbitrary, defined by specific function. + * Preconditions: + * given factory (but isn't guaranteed that also descriptors are) already + * initialized and contains valid data. + */ +typedef int (*TCModuleDescriptorIter)(TCModuleDescriptor *desc, void *userdata); + +/* + * tc_foreach_descriptor: + * apply given iterator with given data to all internal descriptors, + * *both used and unused*. + * + * Parameters: + * factory: factory instance to use + * iterator: iterator to apply at factory descriptors + * userdata: opaque data to pass to iterator along with each descriptor + * index: pointer to an integer. If not NULL, will be filled + * with index of last descriptor elaborated + * Return Value: + * return code of the last execution of iterator. + * Side effects: + * None (see specific descriptor for this). + * Postconditions: + * If return value is 0, given iteratr wass applied to *all* + * descriptors in factory. + */ +static int tc_foreach_descriptor(TCFactory factory, + TCModuleDescriptorIter iterator, + void *userdata, + int *index) +{ + int ret, i = 0; + + if (!factory || !iterator) { + return -1; + } + + for (i = 0; i < TC_FACTORY_MAX_HANDLERS; i++) { + ret = iterator(&(factory->descriptors[i]), userdata); + if (ret != 0) { + break; + } + } + /* iteration stopped, so we mark the interruption point */ + if (ret != 0 && index != NULL) { + *index = i; + } + return ret; +} + +/* + * descriptor_something: some iterator functions + */ + +/* + * descriptor_match_modtype: + * verify the match for a given descriptor and a given module type. + * + * Parameters: + * desc: descriptor to verify + * modtype_: module type to look for. + * Return Value: + * 1 if given descriptor has given module type, + * 0 succesfull. + * -1 if a given parameter is bogus. + */ +static int descriptor_match_modtype(TCModuleDescriptor *desc, + void *modtype_) +{ + char *modtype = modtype_; + if (!desc || !modtype) { + return -1; + } + if (desc->status == TC_DESCRIPTOR_DONE + && desc->type != NULL + && (strcmp(desc->type, modtype) == 0)) { + /* found it! */ + return 1; + } + return 0; +} + +/* + * descriptor_is_free: + * verify the match for a given descriptor is an unitialized one. + * + * Parameters: + * desc: descriptor to verify + * unused: dummy parameter to achieve API conformancy. + * Return Value: + * 1 if given descriptor is a free one (uninitialized), + * 0 succesfull. + * -1 if a given parameter is bogus. + */ +static int descriptor_is_free(TCModuleDescriptor *desc, void *unused) +{ + if (!desc) { + return -1; + } + if (desc->status == TC_DESCRIPTOR_FREE) { + return 1; + } + return 0; +} + +/* + * descriptor_init: + * initialize a plugin descriptor with valid defaults. + * + * Parameters: + * desc: descriptor to initialize. + * unused: dummy parameter to achieve API conformancy. + * Return Value: + * 0 succesfull. + * -1 if a given parameter is bogus. + */ +static int descriptor_init(TCModuleDescriptor *desc, void *unused) +{ + if (!desc) { + return -1; + } + + desc->status = TC_DESCRIPTOR_FREE; + memcpy(&(desc->info), &dummy_info, sizeof(TCModuleInfo)); + desc->klass.info = &(desc->info); + desc->type = NULL; + desc->so_handle = NULL; + desc->ref_count = 0; + + return 0; +} + +/* + * descriptor_fini: + * finalize a plugin descriptor, releasing all acquired + * resources. + * + * Parameters: + * desc: descriptor to finalize. + * unused: dummy parameter to achieve API conformancy. + * Return Value: + * 1 if given descriptor has still some live instances around, + * 0 succesfull. + * -1 if a given parameter is bogus. + * Side effects: + * A plugin will be released and unloaded (via dlclose()). + */ +static int descriptor_fini(TCModuleDescriptor *desc, void *unused) +{ + if (!desc) { + return -1; + } + + /* can't finalize an descriptor with some living instances still around */ + if (desc->ref_count > 0) { + return 1; + } + + if (desc->status == TC_DESCRIPTOR_DONE) { + if (desc->type != NULL) { + tc_free((void*)desc->type); /* avoid const warning */ + desc->type = NULL; + } + if (desc->so_handle != NULL) { + dlclose(desc->so_handle); + desc->so_handle = NULL; + } + desc->status = TC_DESCRIPTOR_FREE; + } + return 0; +} + +/* just a thin wrapper to adapt API */ +static int find_by_modtype(TCFactory factory, const char *modtype) +{ + int ret, id; + ret = tc_foreach_descriptor(factory, descriptor_match_modtype, + (void*)modtype, &id); + /* ret >= 1 -> found something */ + return (ret >= 1) ?id : -1; +} + +/* just a thin wrapper to adapt API */ +static int find_first_free_descriptor(TCFactory factory) +{ + int ret, id; + ret = tc_foreach_descriptor(factory, descriptor_is_free, NULL, &id); + /* ret >= 1 -> found something */ + return (ret >= 1) ?id : -1; +} + +/* Yeah, is that simple. Yet. ;) */ +static void make_modtype(char *buf, size_t bufsize, + const char *modclass, const char *modname) +{ + tc_snprintf(buf, bufsize, "%s:%s", modclass, modname); +} + +/* + * tc_module_class_copy: + * copy a module class into another one. Can perform + * a soft (reference) copy or a hard (full) one. + * Only non-null function pointer to plugin operations + * will be copied. + * soft copy: make the two classes points to same real data. + * hard copy: make two independent copies duplicating the data. + * + * Parameters: + * klass: source class to be copied. + * nklass: class destionation of copy. + * soft_copy: boolean flag: if !0 do a soft copy, + * do an hard one otherwise. + * Return Value: + * 0 successfull + * -1 given (at least) a bad TCModuleClass reference + * 1 not enough memory to perform a full copy + * Postconditions: + * destination class is a copy of source class. + */ + +#define COPY_IF_NOT_NULL(field) do { \ + if (klass->field != NULL) { \ + nklass->field = klass->field; \ + } \ +} while (0) + +static int tc_module_class_copy(const TCModuleClass *klass, + TCModuleClass *nklass) +{ + if (!klass || !nklass) { + /* 'impossible' condition */ + tc_log_error(__FILE__, "bad module class reference for setup: %s%s", + (!klass) ?"plugin class" :"", + (!nklass) ?"core class" :""); + return -1; + } + + if (!klass->init || !klass->fini || !klass->configure || !klass->stop + || !klass->inspect) { + /* should'nt happen */ + tc_log_error(__FILE__, "can't setup a module class without " + "one or more mandatory methods"); + return -1; + } + + /* register only method really provided by given class */ + nklass->init = klass->init; + nklass->fini = klass->fini; + nklass->configure = klass->configure; + nklass->stop = klass->stop; + nklass->inspect = klass->inspect; + + nklass->info = klass->info; + + COPY_IF_NOT_NULL(encode_audio); + COPY_IF_NOT_NULL(encode_video); + COPY_IF_NOT_NULL(decode_audio); + COPY_IF_NOT_NULL(decode_video); + COPY_IF_NOT_NULL(filter_audio); + COPY_IF_NOT_NULL(filter_video); + COPY_IF_NOT_NULL(multiplex); + COPY_IF_NOT_NULL(demultiplex); + + return 0; +} + +#undef COPY_IF_NOT_NULL + +/************************************************************************* + * module versioning helpers * + *************************************************************************/ + +struct tcmodver { + int reserved; + int major; + int minor; + int micro; +}; + +static void expand_version(uint32_t version, struct tcmodver *modver) +{ + modver->reserved = (version & 0xFF000000) >> 24; + modver->major = (version & 0x00FF0000) >> 16; + modver->minor = (version & 0x0000FF00) >> 8; + modver->micro = (version & 0x000000FF); +} + +/* + * tc_module_version_matches: + * check compatibilty between the transcode core version and + * a supplied module version. + * Only a major version mismatch gives incompatibility (...yet). + * + * Parameters: + * modversion: the module version being checked. + * Return Value: + * 0 if module is incompatible with transcode core + * !0 otherwise. + * Side Effects: + * in case of incompatibilty (of any degree), messages are + * tc_log()'d out. + */ +static int tc_module_version_matches(uint32_t modversion) +{ + struct tcmodver ver_core, ver_mod; + + expand_version(TC_MODULE_VERSION, &ver_core); + expand_version(modversion, &ver_mod); + + if (ver_core.reserved != ver_mod.reserved) { + tc_log_error(__FILE__, "internal version error"); + return 0; + } + + /* different major versions are a no-no */ + if (ver_core.major != ver_mod.major) { + tc_log_error(__FILE__, "incompatible module version " + "(core=%i.%i.%i|module=%i.%i.%i)", + ver_core.major, ver_core.minor, ver_core.micro, + ver_mod.major, ver_mod.minor, ver_mod.micro); + return 0; + } + /* if you use different minor version, you've to know that */ + if (ver_core.minor != ver_mod.minor) { + tc_log_error(__FILE__, "old module version " + "(core=%i.%i.%i|module=%i.%i.%i)", + ver_core.major, ver_core.minor, ver_core.micro, + ver_mod.major, ver_mod.minor, ver_mod.micro); + /* still compatible! */ + } + /* different micro version are ok'd silently */ + return 1; +} + + +/************************************************************************* + * main private helpers: _load and _unload * + *************************************************************************/ + +#define RETURN_IF_INVALID_STRING(str, msg, errval) do { \ + if (!str || !strlen(str)) { \ + tc_log_error(__FILE__, msg); \ + return (errval); \ + } \ +} while (0) + +#define RETURN_IF_INVALID_QUIET(val, errval) do { \ + if (!(val)) { \ + return (errval); \ + } \ +} while (0) + +#define TC_LOG_DEBUG(fp, level, format, ...) do { \ + if ((fp)->verbose >= level) { \ + tc_log_info(__FILE__, format, __VA_ARGS__); \ + } \ +} while (0) + + +/* + * tc_load_module: + * load in a given factory a plugin needed for a given module. + * please note that here 'plugin' and 'module' terms are used + * interchangeably since a given module name from a given module + * class usually (almost always, even if such constraint doesn't + * exist) originates from a plugin with same class and same name. + * + * In other words, doesn't exist (yet, nor is planned) a plugin + * that can generate more than one module and/or more than one + * module class + * + * Parameters: + * factory: module factory to loads module in + * modclass: class of plugin to load + * modname: name of plugin to load + * Return Value: + * >= 0 identifier (slot) of newly loaded plugin + * -1 error occcurred (and notified via tc_log*()) + * Side effects: + * a plugin (.so) is loaded into process + * Preconditions: + * none. + * Postconditions: + * none + */ +static int tc_load_module(TCFactory factory, + const char *modclass, const char *modname) +{ + int id = -1, ret = -1; + char full_modpath[PATH_MAX]; + char modtype[MOD_TYPE_MAX_LEN]; + TCModuleEntry modentry = NULL; + TCModuleDescriptor *desc = NULL; + const TCModuleClass *nclass; + + /* 'impossible' conditions */ + RETURN_IF_INVALID_STRING(modclass, "empty module class", -1); + RETURN_IF_INVALID_STRING(modname, "empty module name", -1); + + make_modtype(modtype, PATH_MAX, modclass, modname); + tc_snprintf(full_modpath, PATH_MAX, "%s/%s_%s.so", + factory->mod_path, modclass, modname); + + id = find_first_free_descriptor(factory); + if (id == -1) { + /* should'nt happen */ + tc_log_error(__FILE__, "already loaded the maximum number " + "of modules (%i)", TC_FACTORY_MAX_HANDLERS); + return -1; + } + TC_LOG_DEBUG(factory, TC_DEBUG, "using slot %i for plugin '%s'", + id, modtype); + desc = &(factory->descriptors[id]); + desc->ref_count = 0; + + desc->so_handle = dlopen(full_modpath, RTLD_GLOBAL | RTLD_NOW); + if (!desc->so_handle) { + TC_LOG_DEBUG(factory, TC_INFO, "can't load module '%s'; reason: %s", + modtype, dlerror()); + goto failed_dlopen; + } + desc->type = tc_strdup(modtype); + if (!desc->type) { + goto failed_strdup; + } + desc->status = TC_DESCRIPTOR_CREATED; + + /* soft copy is enough here, since information will be overwritten */ + tc_module_class_copy(&dummy_class, &(desc->klass)); + + modentry = dlsym(desc->so_handle, "tc_plugin_setup"); + if (!modentry) { + TC_LOG_DEBUG(factory, TC_INFO, "module '%s' doesn't have new style" + " entry point", modtype); + goto failed_setup; + } + nclass = modentry(); + + if (!tc_module_version_matches(nclass->version)) { + /* reason already tc_log'd out */ + goto failed_setup; + } + + ret = tc_module_class_copy(nclass, &(desc->klass)); + + if (ret != 0) { + /* should'nt happen */ + tc_log_error(__FILE__, "failed class registration for module '%s'", + modtype); + goto failed_setup; + } + + desc->klass.id = id; /* enforce class/descriptor id */ + desc->status = TC_DESCRIPTOR_DONE; + factory->descriptor_count++; + + return id; + +failed_setup: + desc->status = TC_DESCRIPTOR_FREE; + tc_free((void*)desc->type); /* avoid const warning */ +failed_strdup: + dlclose(desc->so_handle); +failed_dlopen: + return -1; +} + +#define CHECK_VALID_ID(id, where) do { \ + if (id < 0 || id > TC_FACTORY_MAX_HANDLERS) { \ + if (factory->verbose >= TC_DEBUG) { \ + tc_log_error(__FILE__, "%s: invalid id (%i)", where, id); \ + } \ + return -1; \ + } \ +} while (0) + +/* + * tc_unload_module: + * unload a given (by id) plugin from given factory. + * This means that module belonging to such plugin is no longer + * avalaible from given factory, unless, of course, reloading such + * plugin. + * + * Parameters: + * factory: a module factory + * id: id of plugin to unload + * Return Value: + * 0 plugin unloaded correctly + * != 0 error occcurred (and notified via tc_log*()) + * Side effects: + * a plugin (.so) is UNloaded from process + * Preconditions: + * reference count for given plugin is zero. + * This means that no modules instances created by such plugin are + * still active. + * Postconditions: + * none + */ +static int tc_unload_module(TCFactory factory, int id) +{ + int ret = 0; + TCModuleDescriptor *desc = NULL; + + CHECK_VALID_ID(id, "tc_unload_module"); + desc = &(factory->descriptors[id]); + + if (desc->ref_count > 0) { + TC_LOG_DEBUG(factory, TC_DEBUG, "can't unload a module with active" + " ref_count (id=%i, ref_count=%i)", + desc->klass.id, desc->ref_count); + return 1; + } + + ret = descriptor_fini(desc, NULL); + if (ret == 0) { + factory->descriptor_count--; + return 0; + } + return ret; +} + +/************************************************************************* + * implementation of exported functions * + *************************************************************************/ + +TCFactory tc_new_module_factory(const char *modpath, int verbose) +{ + TCFactory factory = NULL; + RETURN_IF_INVALID_STRING(modpath, "empty module path", NULL); + + factory = tc_zalloc(sizeof(struct tcfactory_)); + RETURN_IF_INVALID_QUIET(factory, NULL); + + factory->mod_path = modpath; + factory->verbose = verbose; + factory->descriptor_count = 0; + factory->instance_count = 0; + + tc_foreach_descriptor(factory, descriptor_init, NULL, NULL); + + return factory; +} + +int tc_del_module_factory(TCFactory factory) +{ + RETURN_IF_INVALID_QUIET(factory, 1); + + tc_foreach_descriptor(factory, descriptor_fini, NULL, NULL); + + if (factory->descriptor_count > 0) { + /* should'nt happpen */ + tc_log_warn(__FILE__, "left out %i module descriptors", + factory->descriptor_count); + return -1; + } + + tc_free(factory); + return 0; +} + +TCModule tc_new_module(TCFactory factory, + const char *modclass, const char *modname, + int media) +{ + char modtype[MOD_TYPE_MAX_LEN]; + uint32_t flags = translate_modclass(modclass); + int id = -1, ret; + TCModule module = NULL; + + RETURN_IF_INVALID_QUIET(factory, NULL); + if (flags == TC_MODULE_FEATURE_NONE) { + TC_LOG_DEBUG(factory, TC_INFO, "unknown module class '%s'", + modclass); + return NULL; + } + + make_modtype(modtype, MOD_TYPE_MAX_LEN, modclass, modname); + TC_LOG_DEBUG(factory, TC_DEBUG, "trying to load '%s'", modtype); + id = find_by_modtype(factory, modtype); + if (id == -1) { + /* module type not already known */ + TC_LOG_DEBUG(factory, TC_STATS, "plugin not found for '%s'," + " loading...", modtype); + id = tc_load_module(factory, modclass, modname); + if (id == -1) { + /* load failed, give up */ + return NULL; + } + } + TC_LOG_DEBUG(factory, TC_DEBUG, "module descriptor found: id %i", id); + + module = tc_zalloc(sizeof(struct tcmodule_)); + module->instance.type = factory->descriptors[id].type; + module->instance.id = factory->instance_count + 1; + module->klass = &(factory->descriptors[id].klass); + + ret = tc_module_init(module, flags|translate_media(media)); + if (ret != 0) { + TC_LOG_DEBUG(factory, TC_DEBUG, "initialization of '%s' failed" + " (code=%i)", modtype, ret); + tc_free(module); + return NULL; + } + + factory->descriptors[id].ref_count++; + factory->instance_count++; + TC_LOG_DEBUG(factory, TC_DEBUG, "module created: type='%s'" + " instance id=(%i)", module->instance.type, + module->instance.id); + TC_LOG_DEBUG(factory, TC_STATS, "descriptor ref_count=(%i) instances" + " so far=(%i)", factory->descriptors[id].ref_count, + factory->instance_count); + + return module; +} + +int tc_del_module(TCFactory factory, TCModule module) +{ + int ret = 0, id = -1; + + RETURN_IF_INVALID_QUIET(factory, 1); + RETURN_IF_INVALID_QUIET(module, -1); + + id = module->klass->id; + CHECK_VALID_ID(id, "tc_del_module"); + + ret = tc_module_fini(module); + if (ret != 0) { + TC_LOG_DEBUG(factory, TC_DEBUG, "finalization of '%s' failed" + " (code=%i)", module->instance.type, ret); + return ret; + } + tc_free(module); + + factory->instance_count--; + factory->descriptors[id].ref_count--; + if (factory->descriptors[id].ref_count == 0) { + ret = tc_unload_module(factory, id); + } + return ret; +} + +/************************************************************************* + * Debug helpers. * + *************************************************************************/ + +int tc_plugin_count(const TCFactory factory) +{ + RETURN_IF_INVALID_QUIET(factory, -1); + return factory->descriptor_count; +} + +int tc_instance_count(const TCFactory factory) +{ + RETURN_IF_INVALID_QUIET(factory, -1); + return factory->instance_count; +} + + +#include <assert.h> + +int tc_compare_modules(const TCModule amod, const TCModule bmod) +{ + assert(amod != NULL && bmod != NULL); + + if ((amod == bmod) || (amod->instance.id == bmod->instance.id)) { + return 1; + } + + if (strcmp(amod->instance.type, bmod->instance.type) == 0) { + /* some internal sanity checks. + * assert()s are used here because those conditions + * WILL NOT *NEVER* BE FALSE! + * otherwise something _*really*_ evil is going on + */ + assert(amod->klass != NULL && bmod->klass != NULL); + assert(amod->klass == bmod->klass); + assert(amod->klass->id == bmod->klass->id); + assert(amod->klass->info == bmod->klass->info); + /* we should check method pointers as well? */ + return 0; + } + return -1; +} + +/*************************************************************************/ + +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */ |
