X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/cc1d8213d6a58b0022017f8d231a346387aab507..eca082a93f2619cfa10733947a81fa779cb49573:/src/modules/gconf/module-gconf.c diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index 30e6292e..38857461 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -1,18 +1,18 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio 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 Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -23,7 +23,6 @@ #include #endif -#include #include #include #include @@ -32,39 +31,45 @@ #include #include +#include #include #include -#include #include #include #include -#include #include +#include #include "module-gconf-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("GConf Adapter") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("GConf Adapter"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(true); #define MAX_MODULES 10 #define BUF_MAX 2048 -#undef PA_GCONF_HELPER -#define PA_GCONF_HELPER "/home/lennart/projects/pulseaudio/src/gconf-helper" +struct userdata; + +struct module_item { + char *name; + char *args; + uint32_t index; +}; struct module_info { + struct userdata *userdata; char *name; - - unsigned n_indexes; - uint32_t indexes[MAX_MODULES]; + + struct module_item items[MAX_MODULES]; + unsigned n_items; }; struct userdata { pa_core *core; pa_module *module; - + pa_hashmap *module_infos; pid_t pid; @@ -79,44 +84,44 @@ struct userdata { static int fill_buf(struct userdata *u) { ssize_t r; - assert(u); + pa_assert(u); if (u->buf_fill >= BUF_MAX) { - pa_log(__FILE__": read buffer overflow"); + pa_log("read buffer overflow"); return -1; } if ((r = pa_read(u->fd, u->buf + u->buf_fill, BUF_MAX - u->buf_fill, &u->fd_type)) <= 0) return -1; - u->buf_fill += r; + u->buf_fill += (size_t) r; return 0; } static int read_byte(struct userdata *u) { int ret; - assert(u); + pa_assert(u); if (u->buf_fill < 1) if (fill_buf(u) < 0) return -1; ret = u->buf[0]; - assert(u->buf_fill > 0); + pa_assert(u->buf_fill > 0); u->buf_fill--; memmove(u->buf, u->buf+1, u->buf_fill); return ret; } static char *read_string(struct userdata *u) { - assert(u); + pa_assert(u); for (;;) { char *e; - + if ((e = memchr(u->buf, 0, u->buf_fill))) { char *ret = pa_xstrdup(u->buf); - u->buf_fill -= e - u->buf +1; + u->buf_fill -= (size_t) (e - u->buf +1); memmove(u->buf, e+1, u->buf_fill); return ret; } @@ -126,52 +131,81 @@ static char *read_string(struct userdata *u) { } } -static void unload_modules(struct userdata *u, struct module_info*m) { +static void unload_one_module(struct module_info *m, unsigned i) { + struct userdata *u; + + pa_assert(m); + pa_assert(i < m->n_items); + + u = m->userdata; + + if (m->items[i].index == PA_INVALID_INDEX) + return; + + pa_log_debug("Unloading module #%i", m->items[i].index); + pa_module_unload_by_index(u->core, m->items[i].index, true); + m->items[i].index = PA_INVALID_INDEX; + pa_xfree(m->items[i].name); + pa_xfree(m->items[i].args); + m->items[i].name = m->items[i].args = NULL; +} + +static void unload_all_modules(struct module_info *m) { unsigned i; - - assert(u); - assert(m); - for (i = 0; i < m->n_indexes; i++) { - pa_log_debug(__FILE__": Unloading module #%i", m->indexes[i]); - pa_module_unload_by_index(u->core, m->indexes[i]); - } + pa_assert(m); + + for (i = 0; i < m->n_items; i++) + unload_one_module(m, i); - m->n_indexes = 0; + m->n_items = 0; } static void load_module( - struct userdata *u, struct module_info *m, - const char *module, - const char *args) { + unsigned i, + const char *name, + const char *args, + bool is_new) { + struct userdata *u; pa_module *mod; - - assert(u); - assert(m); - assert(module); - assert(m->n_indexes < MAX_MODULES); + pa_assert(m); + pa_assert(name); + pa_assert(args); - pa_log_debug(__FILE__": Loading module '%s' with args '%s' due to GConf configuration.", module, args); - - if (!(mod = pa_module_load(u->core, module, args))) { - pa_log(__FILE__": pa_module_load() failed"); + u = m->userdata; + + if (!is_new) { + if (m->items[i].index != PA_INVALID_INDEX && + pa_streq(m->items[i].name, name) && + pa_streq(m->items[i].args, args)) + return; + + unload_one_module(m, i); + } + + pa_log_debug("Loading module '%s' with args '%s' due to GConf configuration.", name, args); + + m->items[i].name = pa_xstrdup(name); + m->items[i].args = pa_xstrdup(args); + m->items[i].index = PA_INVALID_INDEX; + + if (!(mod = pa_module_load(u->core, name, args))) { + pa_log("pa_module_load() failed"); return; } - - m->indexes[m->n_indexes++] = mod->index; + + m->items[i].index = mod->index; } -static void module_info_free(void *p, void *userdata) { +static void module_info_free(void *p) { struct module_info *m = p; - struct userdata *u = userdata; - assert(m); - assert(u); + pa_assert(m); - unload_modules(u, m); + unload_all_modules(m); pa_xfree(m->name); pa_xfree(m); } @@ -181,36 +215,41 @@ static int handle_event(struct userdata *u) { int ret = 0; do { - if ((opcode = read_byte(u)) < 0) + if ((opcode = read_byte(u)) < 0) { + if (errno == EINTR || errno == EAGAIN) + break; goto fail; - + } + switch (opcode) { case '!': /* The helper tool is now initialized */ ret = 1; break; - + case '+': { char *name; struct module_info *m; - + unsigned i, j; + if (!(name = read_string(u))) goto fail; - if ((m = pa_hashmap_get(u->module_infos, name))) { - unload_modules(u, m); - } else { + if (!(m = pa_hashmap_get(u->module_infos, name))) { m = pa_xnew(struct module_info, 1); - m->name = pa_xstrdup(name); - m->n_indexes = 0; + m->userdata = u; + m->name = name; + m->n_items = 0; pa_hashmap_put(u->module_infos, m->name, m); - } - - while (m->n_indexes < MAX_MODULES) { + } else + pa_xfree(name); + + i = 0; + while (i < MAX_MODULES) { char *module, *args; if (!(module = read_string(u))) { - pa_xfree(name); + if (i > m->n_items) m->n_items = i; goto fail; } @@ -220,36 +259,39 @@ static int handle_event(struct userdata *u) { } if (!(args = read_string(u))) { - pa_xfree(name); pa_xfree(module); + + if (i > m->n_items) m->n_items = i; goto fail; } - load_module(u, m, module, args); + load_module(m, i, module, args, i >= m->n_items); + + i++; pa_xfree(module); pa_xfree(args); } - pa_xfree(name); - + /* Unload all removed modules */ + for (j = i; j < m->n_items; j++) + unload_one_module(m, j); + + m->n_items = i; + break; } - + case '-': { char *name; struct module_info *m; - + if (!(name = read_string(u))) goto fail; - if ((m = pa_hashmap_get(u->module_infos, name))) { - pa_hashmap_remove(u->module_infos, name); - module_info_free(m, u); - } - + pa_hashmap_remove_and_free(u->module_infos, name); pa_xfree(name); - + break; } } @@ -258,7 +300,7 @@ static int handle_event(struct userdata *u) { return ret; fail: - pa_log(__FILE__": Unable to read or parse data from client."); + pa_log("Unable to read or parse data from client."); return -1; } @@ -271,78 +313,46 @@ static void io_event_cb( struct userdata *u = userdata; - handle_event(u); -} - -static int start_client(const char *n, pid_t *pid) { - pid_t child; - int pipe_fds[2] = { -1, -1 }; + if (handle_event(u) < 0) { - if (pipe(pipe_fds) < 0) { - pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); - goto fail; - } - - if ((child = fork()) == (pid_t) -1) { - pa_log(__FILE__": fork() failed: %s", pa_cstrerror(errno)); - goto fail; - } else if (child != 0) { - - /* Parent */ - close(pipe_fds[1]); - - if (pid) - *pid = child; - - return pipe_fds[0]; - } else { - - /* child */ - - close(pipe_fds[0]); - dup2(pipe_fds[1], 1); - - if (pipe_fds[1] != 1) - close(pipe_fds[1]); + if (u->io_event) { + u->core->mainloop->io_free(u->io_event); + u->io_event = NULL; + } - execl(n, n, NULL); - _exit(1); + pa_module_unload_request(u->module, true); } - -fail: - if (pipe_fds[0] >= 0) - close(pipe_fds[0]); - - if (pipe_fds[1] >= 0) - close(pipe_fds[1]); - - return -1; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { struct userdata *u; int r; u = pa_xnew(struct userdata, 1); - u->core = c; + u->core = m->core; u->module = m; - u->module_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + m->userdata = u; + u->module_infos = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) module_info_free); u->pid = (pid_t) -1; u->fd = -1; u->fd_type = 0; u->io_event = NULL; u->buf_fill = 0; - - if ((u->fd = start_client(PA_GCONF_HELPER, &u->pid)) < 0) + + if ((u->fd = pa_start_child_for_read( +#if defined(__linux__) && !defined(__OPTIMIZE__) + pa_run_from_build_tree() ? PA_BUILDDIR "/gconf-helper" : +#endif + PA_GCONF_HELPER, NULL, &u->pid)) < 0) goto fail; - - u->io_event = c->mainloop->io_new( - c->mainloop, + + u->io_event = m->core->mainloop->io_new( + m->core->mainloop, u->fd, PA_IO_EVENT_INPUT, io_event_cb, u); - + do { if ((r = handle_event(u)) < 0) goto fail; @@ -350,37 +360,44 @@ int pa__init(pa_core *c, pa_module*m) { /* Read until the client signalled us that it is ready with * initialization */ } while (r != 1); - + return 0; fail: - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!(u = m->userdata)) return; - if (u->io_event) - c->mainloop->io_free(u->io_event); - - if (u->fd >= 0) - close(u->fd); - if (u->pid != (pid_t) -1) { kill(u->pid, SIGTERM); - waitpid(u->pid, NULL, 0); + + for (;;) { + if (waitpid(u->pid, NULL, 0) >= 0) + break; + + if (errno != EINTR) { + pa_log("waitpid() failed: %s", pa_cstrerror(errno)); + break; + } + } } + if (u->io_event) + m->core->mainloop->io_free(u->io_event); + + if (u->fd >= 0) + pa_close(u->fd); + if (u->module_infos) - pa_hashmap_free(u->module_infos, module_info_free, u); + pa_hashmap_free(u->module_infos); pa_xfree(u); } -