X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/886041aab88930108953af0e9e14b39ec9d03809..fa499dad06ba6558111cdef64c18f2401e803cff:/polyp/module.c diff --git a/polyp/module.c b/polyp/module.c index 1deb7cde..67d7f44e 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ 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 + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. @@ -33,13 +33,17 @@ #include "module.h" #include "xmalloc.h" #include "subscribe.h" +#include "log.h" -#define UNLOAD_POLL_TIME 10 +#define PA_SYMBOL_INIT "pa__init" +#define PA_SYMBOL_DONE "pa__done" + +#define UNLOAD_POLL_TIME 2 static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { struct pa_core *c = userdata; struct timeval ntv; - assert(c && c->mainloop == m && c->auto_unload_event == e); + assert(c && c->mainloop == m && c->module_auto_unload_event == e); pa_module_unload_unused(c); @@ -54,51 +58,64 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char assert(c && name); + if (c->disallow_module_loading) + goto fail; + m = pa_xmalloc(sizeof(struct pa_module)); m->name = pa_xstrdup(name); m->argument = pa_xstrdup(argument); - if (!(m->dl = lt_dlopenext(name))) + if (!(m->dl = lt_dlopenext(name))) { + pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); goto fail; + } - if (!(m->init = lt_dlsym(m->dl, "pa_module_init"))) + if (!(m->init = (int (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, PA_SYMBOL_INIT))) { + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.\n", name); goto fail; + } - if (!(m->done = lt_dlsym(m->dl, "pa_module_done"))) + if (!(m->done = (void (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, PA_SYMBOL_DONE))) { + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.\n", name); goto fail; + } m->userdata = NULL; m->core = c; m->n_used = -1; m->auto_unload = 0; + m->unload_requested = 0; assert(m->init); - if (m->init(c, m) < 0) + if (m->init(c, m) < 0) { + pa_log(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.\n", name, argument ? argument : ""); goto fail; + } if (!c->modules) c->modules = pa_idxset_new(NULL, NULL); - if (!c->auto_unload_event) { + if (!c->module_auto_unload_event) { struct timeval ntv; gettimeofday(&ntv, NULL); ntv.tv_sec += UNLOAD_POLL_TIME; - c->auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); + c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } - assert(c->auto_unload_event); + assert(c->module_auto_unload_event); assert(c->modules); r = pa_idxset_put(c->modules, m, &m->index); assert(r >= 0 && m->index != PA_IDXSET_INVALID); - fprintf(stderr, "module: loaded %u \"%s\" with argument \"%s\".\n", m->index, m->name, m->argument); + pa_log(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").\n", m->name, m->index, m->argument ? m->argument : ""); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); return m; fail: + if (m) { pa_xfree(m->argument); pa_xfree(m->name); @@ -114,11 +131,17 @@ fail: static void pa_module_free(struct pa_module *m) { assert(m && m->done && m->core); + + if (m->core->disallow_module_loading) + return; + + pa_log(__FILE__": Unloading \"%s\" (index: #%u).\n", m->name, m->index); + m->done(m->core, m); lt_dlclose(m->dl); - fprintf(stderr, "module: unloaded %u \"%s\".\n", m->index, m->name); + pa_log(__FILE__": Unloaded \"%s\" (index: #%u).\n", m->name, m->index); pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); @@ -127,7 +150,6 @@ static void pa_module_free(struct pa_module *m) { pa_xfree(m); } - void pa_module_unload(struct pa_core *c, struct pa_module *m) { assert(c && m); @@ -164,9 +186,15 @@ void pa_module_unload_all(struct pa_core *c) { pa_idxset_free(c->modules, free_callback, NULL); c->modules = NULL; - if (c->auto_unload_event) - c->mainloop->time_free(c->auto_unload_event); - c->auto_unload_event = NULL; + if (c->module_auto_unload_event) { + c->mainloop->time_free(c->module_auto_unload_event); + c->module_auto_unload_event = NULL; + } + + if (c->module_defer_unload_event) { + c->mainloop->defer_free(c->module_defer_unload_event); + c->module_defer_unload_event = NULL; + } } static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { @@ -174,7 +202,7 @@ static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { time_t *now = userdata; assert(p && del && now); - if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->auto_unload_time <= *now) { + if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) { pa_module_free(m); *del = 1; } @@ -193,26 +221,38 @@ void pa_module_unload_unused(struct pa_core *c) { pa_idxset_foreach(c->modules, unused_callback, &now); } -struct once_info { - struct pa_core *core; - uint32_t index; -}; - -static void module_unload_once_callback(struct pa_mainloop_api *m, void *userdata) { - struct once_info *i = userdata; - assert(i); - pa_module_unload_by_index(i->core, i->index); - pa_xfree(i); +static int unload_callback(void *p, uint32_t index, int *del, void *userdata) { + struct pa_module *m = p; + assert(m); + + if (m->unload_requested) { + pa_module_free(m); + *del = 1; + } + + return 0; } -void pa_module_unload_request(struct pa_core *c, struct pa_module *m) { - struct once_info *i; - assert(c && m); +static void defer_cb(struct pa_mainloop_api*api, struct pa_defer_event *e, void *userdata) { + struct pa_core *core = userdata; + api->defer_enable(e, 0); + + if (!core->modules) + return; + + pa_idxset_foreach(core->modules, unload_callback, NULL); - i = pa_xmalloc(sizeof(struct once_info)); - i->core = c; - i->index = m->index; - pa_mainloop_api_once(c->mainloop, module_unload_once_callback, i); +} + +void pa_module_unload_request(struct pa_module *m) { + assert(m); + + m->unload_requested = 1; + + if (!m->core->module_defer_unload_event) + m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); + + m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1); } void pa_module_set_used(struct pa_module*m, int used) { @@ -227,3 +267,8 @@ void pa_module_set_used(struct pa_module*m, int used) { m->n_used = used; } +struct pa_modinfo *pa_module_get_info(struct pa_module *m) { + assert(m); + + return pa_modinfo_get_by_handle(m->dl); +}