aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2009-03-14 11:53:28 +0100
committerMax Kellermann <max@duempel.org>2009-03-14 11:53:28 +0100
commit7deade857733e2a38d2da926acfc69b235fa4d0f (patch)
tree623e432726c254954035351566ce202a209d41c8
parent82963ee0238ec9977161b27183294d39a817336f (diff)
downloadmpd-7deade857733e2a38d2da926acfc69b235fa4d0f.tar.gz
mpd-7deade857733e2a38d2da926acfc69b235fa4d0f.tar.xz
mpd-7deade857733e2a38d2da926acfc69b235fa4d0f.zip
mixer: protect the mixer struct with a mutex
In some rare cases, there was a race condition between the output thread and the main thread: when you disable/enable an output device in the main thread, this caused a crash in the output thread. Protect the whole mixer struct with a GMutex to prevent that.
-rw-r--r--src/mixer_api.c3
-rw-r--r--src/mixer_api.h8
-rw-r--r--src/mixer_control.c31
3 files changed, 37 insertions, 5 deletions
diff --git a/src/mixer_api.c b/src/mixer_api.c
index 1e0aabb10..aaa250d33 100644
--- a/src/mixer_api.c
+++ b/src/mixer_api.c
@@ -19,8 +19,6 @@
#include "mixer_api.h"
-#include <glib.h>
-
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "mixer"
@@ -28,4 +26,5 @@ void
mixer_init(struct mixer *mixer, const struct mixer_plugin *plugin)
{
mixer->plugin = plugin;
+ mixer->mutex = g_mutex_new();
}
diff --git a/src/mixer_api.h b/src/mixer_api.h
index 62c277b9d..9af49cd87 100644
--- a/src/mixer_api.h
+++ b/src/mixer_api.h
@@ -23,8 +23,16 @@
#include "mixer_plugin.h"
#include "mixer_list.h"
+#include <glib.h>
+
struct mixer {
const struct mixer_plugin *plugin;
+
+ /**
+ * This mutex protects all of the mixer struct, including its
+ * implementation, so plugins don't have to deal with that.
+ */
+ GMutex *mutex;
};
void
diff --git a/src/mixer_control.c b/src/mixer_control.c
index ba49e2ec4..d3f246800 100644
--- a/src/mixer_control.c
+++ b/src/mixer_control.c
@@ -62,6 +62,9 @@ mixer_free(struct mixer *mixer)
return;
}
assert(mixer->plugin != NULL);
+ assert(mixer->mutex != NULL);
+
+ g_mutex_free(mixer->mutex);
mixer->plugin->finish(mixer);
}
@@ -69,11 +72,18 @@ mixer_free(struct mixer *mixer)
bool
mixer_open(struct mixer *mixer)
{
+ bool success;
+
if (!mixer) {
return false;
}
assert(mixer->plugin != NULL);
- return mixer->plugin->open(mixer);
+
+ g_mutex_lock(mixer->mutex);
+ success = mixer->plugin->open(mixer);
+ g_mutex_unlock(mixer->mutex);
+
+ return success;
}
void
@@ -83,17 +93,32 @@ mixer_close(struct mixer *mixer)
return;
}
assert(mixer->plugin != NULL);
+
+ g_mutex_lock(mixer->mutex);
mixer->plugin->close(mixer);
+ g_mutex_unlock(mixer->mutex);
}
int
mixer_get_volume(struct mixer *mixer)
{
- return mixer->plugin->get_volume(mixer);
+ int volume;
+
+ g_mutex_lock(mixer->mutex);
+ volume = mixer->plugin->get_volume(mixer);
+ g_mutex_unlock(mixer->mutex);
+
+ return volume;
}
bool
mixer_set_volume(struct mixer *mixer, unsigned volume)
{
- return mixer->plugin->set_volume(mixer, volume);
+ bool success;
+
+ g_mutex_lock(mixer->mutex);
+ success = mixer->plugin->set_volume(mixer, volume);
+ g_mutex_unlock(mixer->mutex);
+
+ return success;
}