aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2013-06-10 14:22:02 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2013-06-10 14:22:02 +0200
commit36a2529f8ae07fabda5a88b867307dde806a52f6 (patch)
tree098b1b8d214a5d4a5262931b4a2460ca4e6c635f
parent1f1b5114d4a94750d02a38357ecf45f72f3dd3a3 (diff)
downloadexperiment-player-36a2529f8ae07fabda5a88b867307dde806a52f6.tar.gz
gtk-vlc-player widget: fixed VLC callback processing (dead locks)
either libVLC 2.0.5 changed the semantics of their callbacks (they can be invoked from the main thread, i.e. from the VLC method resulting in the event); or GTK+ 2.24 silently changed the type of the GDK mutex from recursive to simple. in either case to avoid GDK mutex deadlocks we must check whether the VLC callback's thread already holds the lock or owns the main context
-rw-r--r--lib/gtk-vlc-player/gtk-vlc-player.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/lib/gtk-vlc-player/gtk-vlc-player.c b/lib/gtk-vlc-player/gtk-vlc-player.c
index 03179ed..97a7115 100644
--- a/lib/gtk-vlc-player/gtk-vlc-player.c
+++ b/lib/gtk-vlc-player/gtk-vlc-player.c
@@ -38,6 +38,7 @@
#include <glib/gprintf.h>
#include <gtk/gtk.h>
+#include <gdk/gdk.h>
#ifdef G_OS_WIN32
#include <gdk/gdkwin32.h>
#else
@@ -57,6 +58,9 @@ static void gtk_vlc_player_init(GtkVlcPlayer *klass);
static void gtk_vlc_player_dispose(GObject *gobject);
static void gtk_vlc_player_finalize(GObject *gobject);
+static inline void maybe_lock_gdk(void);
+static inline void maybe_unlock_gdk(void);
+
#ifdef G_OS_WIN32
static BOOL CALLBACK enumerate_vlc_windows_cb(HWND hWndvlc, LPARAM lParam);
static gboolean poll_vlc_event_window_cb(gpointer data);
@@ -308,6 +312,34 @@ gtk_vlc_player_finalize(GObject *gobject)
G_OBJECT_CLASS(gtk_vlc_player_parent_class)->finalize(gobject);
}
+/**
+ * @brief Locks GDK mutex if necessary.
+ *
+ * When GTK+ functions are invoked from another than the main
+ * thread (the one with the \e gtk_main() event loop),
+ * \e gdk_threads_enter() must be called.
+ * This auxiliary function is for callers (like VLC callbacks) that
+ * may or may not be invoked from the main event loop to avoid dead locks.
+ */
+static inline void
+maybe_lock_gdk(void)
+{
+ if (!g_main_context_is_owner(g_main_context_default()))
+ gdk_threads_enter();
+}
+
+/**
+ * @brief Unlocks GDK mutex if necessary.
+ *
+ * @see maybe_lock_gdk
+ */
+static inline void
+maybe_unlock_gdk(void)
+{
+ if (!g_main_context_is_owner(g_main_context_default()))
+ gdk_threads_leave();
+}
+
#ifdef G_OS_WIN32
static BOOL CALLBACK
@@ -478,11 +510,11 @@ vlc_time_changed(const struct libvlc_event_t *event, void *user_data)
{
assert(event->type == libvlc_MediaPlayerTimeChanged);
- /* VLC callbacks are invoked from another thread! */
- gdk_threads_enter();
+ /* VLC callbacks may be invoked from another thread! */
+ maybe_lock_gdk();
update_time(GTK_VLC_PLAYER(user_data),
(gint64)event->u.media_player_time_changed.new_time);
- gdk_threads_leave();
+ maybe_unlock_gdk();
}
static void
@@ -490,11 +522,11 @@ vlc_length_changed(const struct libvlc_event_t *event, void *user_data)
{
assert(event->type == libvlc_MediaPlayerLengthChanged);
- /* VLC callbacks are invoked from another thread! */
- gdk_threads_enter();
+ /* VLC callbacks may be invoked from another thread! */
+ maybe_lock_gdk();
update_length(GTK_VLC_PLAYER(user_data),
(gint64)event->u.media_player_length_changed.new_length);
- gdk_threads_leave();
+ maybe_unlock_gdk();
}
static void