diff options
| -rw-r--r-- | src/Makefile.am | 3 | ||||
| -rw-r--r-- | src/canberra-gtk.c | 8 | ||||
| -rw-r--r-- | src/canberra.h | 3 | ||||
| -rw-r--r-- | src/common.c | 17 | ||||
| -rw-r--r-- | src/fork-detect.c | 51 | ||||
| -rw-r--r-- | src/fork-detect.h | 26 | 
6 files changed, 104 insertions, 4 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index 1fb5168..e40ec1f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,7 +52,8 @@ libcanberra_la_SOURCES = \  	sound-theme-spec.c sound-theme-spec.h \  	llist.h \  	macro.h macro.c \ -	malloc.c malloc.h +	malloc.c malloc.h \ +	fork-detect.c fork-detect.h  libcanberra_la_CFLAGS = \  	$(AM_CFLAGS) \  	$(VORBIS_CFLAGS) diff --git a/src/canberra-gtk.c b/src/canberra-gtk.c index 70b8d7e..cb36a0f 100644 --- a/src/canberra-gtk.c +++ b/src/canberra-gtk.c @@ -31,6 +31,7 @@  #include "common.h"  #include "malloc.h"  #include "proplist.h" +#include "fork-detect.h"  /**   * SECTION:canberra-gtk @@ -93,7 +94,8 @@ ca_context *ca_gtk_context_get(void) {      if ((c = g_static_private_get(&context_private)))          return c; -    ca_assert_se(ca_context_create(&c) == CA_SUCCESS); +    if (ca_context_create(&c) != CA_SUCCESS) +        return NULL;      if ((name = g_get_application_name()))          ca_context_change_props(c, CA_PROP_APPLICATION_NAME, name, NULL); @@ -154,6 +156,7 @@ int ca_gtk_proplist_set_for_widget(ca_proplist *p, GtkWidget *widget) {      ca_return_val_if_fail(p, CA_ERROR_INVALID);      ca_return_val_if_fail(widget, CA_ERROR_INVALID); +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      if (!(w = get_toplevel(widget)))          return CA_ERROR_INVALID; @@ -224,6 +227,7 @@ int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e) {      ca_return_val_if_fail(p, CA_ERROR_INVALID);      ca_return_val_if_fail(e, CA_ERROR_INVALID); +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      if ((gw = e->any.window)) {          gdk_window_get_user_data(gw, (gpointer*) &w); @@ -297,6 +301,7 @@ int ca_gtk_play_for_widget(GtkWidget *w, uint32_t id, ...) {      ca_proplist *p;      ca_return_val_if_fail(w, CA_ERROR_INVALID); +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      if ((ret = ca_proplist_create(&p)) < 0)          return ret; @@ -346,6 +351,7 @@ int ca_gtk_play_for_event(GdkEvent *e, uint32_t id, ...) {      ca_proplist *p;      ca_return_val_if_fail(e, CA_ERROR_INVALID); +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      if ((ret = ca_proplist_create(&p)) < 0)          return ret; diff --git a/src/canberra.h b/src/canberra.h index ff09146..9664ef2 100644 --- a/src/canberra.h +++ b/src/canberra.h @@ -414,7 +414,8 @@ enum {      CA_ERROR_IO = -14,      CA_ERROR_INTERNAL = -15,      CA_ERROR_DISABLED = -16, -    _CA_ERROR_MAX = -17 +    CA_ERROR_FORKED = -17, +    _CA_ERROR_MAX = -18  };  /** diff --git a/src/common.c b/src/common.c index e1445f4..ac8b982 100644 --- a/src/common.c +++ b/src/common.c @@ -30,6 +30,7 @@  #include "driver.h"  #include "proplist.h"  #include "macro.h" +#include "fork-detect.h"  /**   * SECTION:canberra @@ -127,6 +128,7 @@ int ca_context_create(ca_context **_c) {      int ret;      const char *d; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(_c, CA_ERROR_INVALID);      if (!(c = ca_new0(ca_context, 1))) @@ -171,6 +173,7 @@ int ca_context_create(ca_context **_c) {  int ca_context_destroy(ca_context *c) {      int ret = CA_SUCCESS; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(c, CA_ERROR_INVALID);      /* There's no locking necessary here, because the application is @@ -209,6 +212,7 @@ int ca_context_set_driver(ca_context *c, const char *driver) {      char *n;      int ret; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      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); @@ -250,6 +254,7 @@ int ca_context_change_device(ca_context *c, const char *device) {      char *n;      int ret; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(c, CA_ERROR_INVALID);      ca_mutex_lock(c->mutex); @@ -277,6 +282,7 @@ fail:  static int context_open_unlocked(ca_context *c) {      int ret; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(c, CA_ERROR_INVALID);      if (c->opened) @@ -302,6 +308,7 @@ static int context_open_unlocked(ca_context *c) {  int ca_context_open(ca_context *c) {      int ret; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      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); @@ -336,6 +343,7 @@ int ca_context_change_props(ca_context *c, ...)  {      int ret;      ca_proplist *p = NULL; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(c, CA_ERROR_INVALID);      va_start(ap, c); @@ -368,6 +376,7 @@ int ca_context_change_props_full(ca_context *c, ca_proplist *p) {      int ret;      ca_proplist *merged; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(c, CA_ERROR_INVALID);      ca_return_val_if_fail(p, CA_ERROR_INVALID); @@ -438,6 +447,7 @@ int ca_context_play(ca_context *c, uint32_t id, ...) {      va_list ap;      ca_proplist *p = NULL; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(c, CA_ERROR_INVALID);      va_start(ap, id); @@ -478,6 +488,7 @@ int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_c      const char *t;      ca_bool_t enabled = TRUE; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      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); @@ -532,6 +543,7 @@ finish:  int ca_context_cancel(ca_context *c, uint32_t id)  {      int ret; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      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); @@ -566,6 +578,7 @@ int ca_context_cache(ca_context *c, ...) {      va_list ap;      ca_proplist *p = NULL; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(c, CA_ERROR_INVALID);      va_start(ap, c); @@ -599,6 +612,7 @@ int ca_context_cache(ca_context *c, ...) {  int ca_context_cache_full(ca_context *c, ca_proplist *p) {      int ret; +    ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);      ca_return_val_if_fail(c, CA_ERROR_INVALID);      ca_return_val_if_fail(p, CA_ERROR_INVALID); @@ -648,7 +662,8 @@ const char *ca_strerror(int code) {          [-CA_ERROR_ACCESS] = "Access forbidden",          [-CA_ERROR_IO] = "IO error",          [-CA_ERROR_INTERNAL] = "Internal error", -        [-CA_ERROR_DISABLED] = "Sound disabled" +        [-CA_ERROR_DISABLED] = "Sound disabled", +        [-CA_ERROR_FORKED] = "Process forked"      };      ca_return_val_if_fail(code <= 0, NULL); diff --git a/src/fork-detect.c b/src/fork-detect.c new file mode 100644 index 0000000..622037c --- /dev/null +++ b/src/fork-detect.c @@ -0,0 +1,51 @@ +/*** +  This file is part of libcanberra. + +  Copyright 2009 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, see +  <http://www.gnu.org/licenses/>. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <sys/types.h> + +#include "fork-detect.h" + +int ca_detect_fork(void) { +    static volatile pid_t pid = (pid_t) -1; +    pid_t v; + +    /* Some really stupid applications (Hey, vim, that means you!) +     * love to fork after initializing gtk/libcanberra. This is really +     * bad style. We however have to deal with this cleanly, so we try +     * to detect the forks making sure all our calls fail cleanly +     * after the fork. */ + +    /* Ideally we'd use atomic operations here, but we don't have them +     * and this is not exactly crucial, so we don't care */ + +    v = pid; + +    if (v == getpid() || v == (pid_t) -1) { +        pid = getpid(); +        return 0; +    } + +    return 1; +} diff --git a/src/fork-detect.h b/src/fork-detect.h new file mode 100644 index 0000000..9050ef8 --- /dev/null +++ b/src/fork-detect.h @@ -0,0 +1,26 @@ +#ifndef foocanberraforkdetecth +#define foocanberraforkdetecth + +/*** +  This file is part of libcanberra. + +  Copyright 2009 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, see +  <http://www.gnu.org/licenses/>. +***/ + +int ca_detect_fork(void); + +#endif | 
