diff options
Diffstat (limited to 'common.c')
-rw-r--r-- | common.c | 358 |
1 files changed, 173 insertions, 185 deletions
@@ -1,302 +1,292 @@ +/* $Id$ */ + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra 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.1 of the + License, or (at your option) any later version. + + libcanberra 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, If not, see + <http://www.gnu.org/licenses/>. +***/ + +#include <stdarg.h> + #include "canberra.h" #include "common.h" +#include "malloc.h" +#include "driver.h" +#include "proplist.h" -int ca_context_create(ca_context_t **c) { - ca_return_val_if_fail(c, CA_ERROR_INVALID); +int ca_context_create(ca_context **_c) { + ca_context *c; + int ret; + + ca_return_val_if_fail(_c, CA_ERROR_INVALID); + + if (!(c = ca_new0(ca_context, 1))) + return CA_ERROR_OOM; - if (!(*c = ca_new0(ca_context_t, 1))) + if (!(c->mutex = ca_mutex_new())) { + ca_free(c); return CA_ERROR_OOM; + } + + if ((ret = ca_proplist_create(&c->props)) < 0) { + ca_mutex_free(c->mutex); + ca_free(c); + return ret; + } + *_c = c; return CA_SUCCESS; } -int ca_context_destroy(ca_context_t *c) { - int ret; - unsigned i; - ca_prop *p, *n; +int ca_context_destroy(ca_context *c) { + int ret = CA_SUCCESS; ca_return_val_if_fail(c, CA_ERROR_INVALID); - ret = driver_destroy(c); + /* There's no locking necessary here, because the application is + * broken anyway if it destructs this object in one thread and + * still is calling a method of it in another. */ - for (p = c->first_item; p; p = n) { - n = p->next_item; - ca_free(p); - } + if (c->opened) + ret = driver_destroy(c); + + if (c->props) + ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS); + ca_mutex_free(c->mutex); ca_free(c); return ret; } -int ca_context_open(ca_context_t *c) { +static int context_open_unlocked(ca_context *c) { int ret; ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(!c->opened, CA_ERROR_STATE); - if ((ret = driver_open(c)) == 0) + if (c->opened) + return CA_SUCCESS; + + if ((ret = driver_open(c)) == CA_SUCCESS) c->opened = TRUE; return ret; } -int ca_context_sets(ca_context_t *c, ...) { - va_list ap; - int ret = CA_SUCCESS; +int ca_context_open(ca_context *c) { + int ret; ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex); - va_start(ap, c); + ret = context_open_unlocked(c); + + ca_mutex_unlock(c->mutex); + + return ret; +} + +static int ca_proplist_from_ap(ca_proplist **_p, va_list ap) { + int ret; + ca_proplist *p; + + ca_assert(_p); + + if ((ret = ca_proplist_create(&p)) < 0) + return ret; for (;;) { const char *key, *value; int ret; - if (!(key = v_arg(ap, const char*))) + if (!(key = va_arg(ap, const char*))) break; - if (!(value = v_arg(ap, const char *))) { + if (!(value = va_arg(ap, const char*))) { ret = CA_ERROR_INVALID; - break; + goto fail; } - if ((ret = ca_context_set(c, key, value, strlen(value)+1)) < 0) - break; + if ((ret = ca_proplist_sets(p, key, value)) < 0) + goto fail; } - va_end(ap); + *_p = p; + + return CA_SUCCESS; + +fail: + ca_assert_se(ca_proplist_destroy(p) == CA_SUCCESS); return ret; } -static int _unset(ca_context_t *c, const char *key) { - ca_prop *p, *np; - unsigned i; +int ca_context_change_props(ca_context *c, ...) { + va_list ap; + int ret; + ca_proplist *p = NULL; ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(key, CA_ERROR_INVALID); - - i = calc_hash(key) % N_HASHTABLE; - np = NULL; - for (p = c->props[i]; p; np = p, p = p->next_in_slot) - if (strcmp(p->key, key) == 0) - break; + va_start(ap, c); + ret = ca_proplist_from_ap(&p, ap); + va_end(ap); - if (p) { - if (np) - np->next_in_slot = p->next_in_slot; - else - c->props[i] = p->next_in_slot; + if (ret < 0) + return ret; - if (p->prev_item) - p->prev_item->next_item = p->next_item; - else - c->first_item = p->next_item; + ret = ca_context_change_props_full(c, p); - if (p->next_item) - p->next_item->prev_item = p->prev_item; + ca_assert_se(ca_proplist_destroy(p) == 0); - ca_free(p); - } + return ret; } -int ca_context_set(ca_context_t *c, const char *key, const void *data, size_t nbytes) { +int ca_context_change_props_full(ca_context *c, ca_proplist *p) { int ret; - ca_prop *p; - char *k; + ca_proplist *merged; ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(key, CA_ERROR_INVALID); - ca_return_val_if_fail(!nbytes || data, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); - if (!(k = ca_strdup(key))) - return CA_ERROR_OOM; + ca_mutex_lock(c->mutex); - if (!(p = ca_malloc(CA_ALIGN(sizeof(ca_prop)) + nbytes))) { - ca_free(k); - return CA_ERROR_OOM; - } - - if ((ret = _unset(c, key)) < 0) { - ca_free(p); - ca_free(k); - return ret; - } + if ((ret = ca_proplist_merge(&merged, c->props, p)) < 0) + goto finish; - p->key = k; - p->nbytes = nbytes; - memcpy(CA_PROP_DATA(p), data, nbytes); + ret = c->opened ? driver_change_props(c, p, merged) : CA_SUCCESS; - i = calc_hash(key) % N_HASHTABLE; + if (ret == CA_SUCCESS) { + ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS); + c->props = merged; + } else + ca_assert_se(ca_proplist_destroy(merged) == CA_SUCCESS); - p->next_in_slot = c->props[i]; - c->props[i] = p; +finish: - p->prev_item = NULL; - p->next_item = c->first_item; - c->first_item = p; + ca_mutex_unlock(c->mutex); - if (c->opened) - if ((ret = driver_set(c, key, data, nbytes)) < 0) - return ret; - - return CA_SUCCESS; + return ret; } -int ca_context_unset(ca_context *c, ...) { - int ret = CA_SUCCESS; +int ca_context_play(ca_context *c, uint32_t id, ...) { + int ret; va_list ap; + ca_proplist *p = NULL; ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(key, CA_ERROR_INVALID); - - va_start(ap, c); - - for (;;) { - const char *key; - if (!(key = v_arg(ap, const char*))) - break; + va_start(ap, id); + ret = ca_proplist_from_ap(&p, ap); + va_end(ap); - if (c->opened) { - if ((ret = driver_unset(c, key)) < 0) - break; - } + if (ret < 0) + return ret; - if ((ret = _unset(c, key)) < 0) - break; - } + ret = ca_context_play_full(c, id, p, NULL, NULL); - va_end(ap); + ca_assert_se(ca_proplist_destroy(p) == 0); return ret; } -/* Not exported */ -ca_prop* ca_context_get(ca_context *c, const char *key) { - ca_prop *p; - unsigned i; +int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata) { + int ret; - ca_return_val_if_fail(c, NULL); - ca_return_val_if_fail(key, NULL); + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); - i = calc_hash(key) % N_HASHTABLE; + ca_mutex_lock(c->mutex); - for (p = c->props[i]; p; p = p->next_in_slot) - if (strcmp(p->key, key) == 0) - return p; + ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) || + ca_proplist_contains(c->props, CA_PROP_EVENT_ID), CA_ERROR_INVALID, c->mutex); - return NULL; -} + if ((ret = context_open_unlocked(c)) < 0) + goto finish; -/* Not exported */ -const char* ca_context_gets(ca_context *c, const char *key) { - ca_prop *p; + ca_assert(c->opened); - ca_return_val_if_fail(c, NULL); - ca_return_val_if_fail(key, NULL); + ret = driver_play(c, id, p, cb, userdata); - if (!(p = ca_context_get(c, key))) - return NULL; +finish: - if (memchr(CA_PROP_DATA(p), 0, p->nbytes)) - return CA_PROP_DATA(p); + ca_mutex_unlock(c->mutex); - return NULL; + return ret; } -int ca_context_play(ca_context_t *c, uint32_t id, ...) { +int ca_context_cancel(ca_context *c, uint32_t id) { int ret; - va_list ap; ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(key, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex); - if (!c->opened) - if ((ret = ca_context_open(c)) < 0) - return ret; - - ca_assert(c->opened); + ret = driver_cancel(c, id); - /* make sure event.id is set */ + ca_mutex_unlock(c->mutex); - va_start(ap, c); - for (;;) { - const char *key, *value; + return ret; +} - if (!(key = va_arg(ap, const char *))) - break; +int ca_context_cache(ca_context *c, ...) { + int ret; + va_list ap; + ca_proplist *p = NULL; - if (!(value = va_arg(ap, const char *))) { - va_end(ap); - return CA_ERROR_INVALID; - } + ca_return_val_if_fail(c, CA_ERROR_INVALID); - found = found || strcmp(key, CA_PROP_EVENT_ID) == 0; - } + va_start(ap, c); + ret = ca_proplist_from_ap(&p, ap); va_end(ap); - found = found || ca_context_gets(c, CA_PROP_EVENT_ID); + if (ret < 0) + return ret; - if (!found) - return CA_ERROR_INVALID; + ret = ca_context_cache_full(c, p); - va_start(ap, id); - ret = driver_play(c, id, ap); - va_end(ap); + ca_assert_se(ca_proplist_destroy(p) == 0); return ret; } -int ca_context_cancel(ca_context_t *c, uint32_ id) { - - ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(c->opened, CA_ERROR_STATE); - - return driver_cancel(c, id); -} - -int ca_context_cache(ca_context_t *c, ...) { +int ca_context_cache_full(ca_context *c, ca_proplist *p) { int ret; - va_list ap; - ca_bool_t found = FALSE; ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); - if (!c->opened) - if ((ret = ca_context_open(c)) < 0) - return ret; + ca_mutex_lock(c->mutex); - ca_assert(c->opened); + ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) || + ca_proplist_contains(c->props, CA_PROP_EVENT_ID), CA_ERROR_INVALID, c->mutex); - /* make sure event.id is set */ + if ((ret = context_open_unlocked(c)) < 0) + goto finish; - va_start(ap, c); - for (;;) { - const char *key, *value; - - if (!(key = va_arg(ap, const char *))) - break; - - if (!(value = va_arg(ap, const char *))) { - va_end(ap); - return CA_ERROR_INVALID; - } + ca_assert(c->opened); - found = found || strcmp(key, CA_PROP_EVENT_ID) == 0; - } - va_end(ap); + ret = driver_cache(c, p); - found = found || ca_context_gets(c, CA_PROP_EVENT_ID); +finish: - if (!found) - return CA_ERROR_INVALID; - - va_start(ap, c); - ret = driver_cache(c, ap); - va_end(ap); + ca_mutex_unlock(c->mutex); return ret; } @@ -315,9 +305,7 @@ const char *ca_strerror(int code) { }; ca_return_val_if_fail(code <= 0, NULL); - ca_return_val_if_fail(code > _SA_ERROR_MAX, NULL); + ca_return_val_if_fail(code > _CA_ERROR_MAX, NULL); return error_table[-code]; } - -#endif |