summaryrefslogtreecommitdiffstats
path: root/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'common.c')
-rw-r--r--common.c358
1 files changed, 173 insertions, 185 deletions
diff --git a/common.c b/common.c
index 9ae9d8e..bc535d8 100644
--- a/common.c
+++ b/common.c
@@ -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