wayland: Add synchronized requests to WlDisplay
authorDamian Hobson-Garcia <dhobsong@igel.co.jp>
Thu, 15 Feb 2024 21:42:13 +0000 (16:42 -0500)
committerDamian Hobson-Garcia <dhobsong@igel.co.jp>
Tue, 27 Feb 2024 17:20:42 +0000 (17:20 +0000)
Add synchonized versions of wl_display_sync() and wl_callback_destroy()
that will ensure that to callbacks can be managed in a thread safe way
on the display queue even when they are dispatched from a separate
thread.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6133>

subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.c
subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.h

index 1ec9fb79ea11e4880b4ce1c9f7f11db9f030b851..8d386593a665c573afdc5abc5c172d777acfcd79 100644 (file)
@@ -62,6 +62,8 @@ typedef struct _GstWlDisplayPrivate
   GThread *thread;
   GstPoll *wl_fd_poll;
 
+  GRecMutex sync_mutex;
+
   GMutex buffers_mutex;
   GHashTable *buffers;
   gboolean shutting_down;
@@ -93,6 +95,7 @@ gst_wl_display_init (GstWlDisplay * self)
   priv->wl_fd_poll = gst_poll_new (TRUE);
   priv->buffers = g_hash_table_new (g_direct_hash, g_direct_equal);
   g_mutex_init (&priv->buffers_mutex);
+  g_rec_mutex_init (&priv->sync_mutex);
 
   gst_wl_linux_dmabuf_init_once ();
   gst_shm_allocator_init_once ();
@@ -132,6 +135,7 @@ gst_wl_display_finalize (GObject * gobject)
   gst_poll_free (priv->wl_fd_poll);
   g_hash_table_unref (priv->buffers);
   g_mutex_clear (&priv->buffers_mutex);
+  g_rec_mutex_clear (&priv->sync_mutex);
 
   if (priv->viewporter)
     wp_viewporter_destroy (priv->viewporter);
@@ -360,8 +364,10 @@ gst_wl_display_thread_run (gpointer data)
 
   /* main loop */
   while (1) {
+    g_rec_mutex_lock (&priv->sync_mutex);
     while (wl_display_prepare_read_queue (priv->display, priv->queue) != 0)
       wl_display_dispatch_queue_pending (priv->display, priv->queue);
+    g_rec_mutex_unlock (&priv->sync_mutex);
     wl_display_flush (priv->display);
 
     if (gst_poll_wait (priv->wl_fd_poll, GST_CLOCK_TIME_NONE) < 0) {
@@ -374,7 +380,10 @@ gst_wl_display_thread_run (gpointer data)
     }
     if (wl_display_read_events (priv->display) == -1)
       goto error;
+
+    g_rec_mutex_lock (&priv->sync_mutex);
     wl_display_dispatch_queue_pending (priv->display, priv->queue);
+    g_rec_mutex_unlock (&priv->sync_mutex);
   }
 
   return NULL;
@@ -523,6 +532,51 @@ gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer gstmem)
   g_mutex_unlock (&priv->buffers_mutex);
 }
 
+/* gst_wl_display_sync
+ *
+ * A syncronized version of `wl_display_sink` that ensures that the
+ * callback will not be dispatched before the listener has been attached.
+ */
+struct wl_callback *
+gst_wl_display_sync (GstWlDisplay * self,
+    const struct wl_callback_listener *listener, gpointer data)
+{
+  GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self);
+  struct wl_callback *callback;
+
+  g_rec_mutex_lock (&priv->sync_mutex);
+
+  callback = wl_display_sync (priv->display_wrapper);
+  if (callback && listener)
+    wl_callback_add_listener (callback, listener, data);
+
+  g_rec_mutex_unlock (&priv->sync_mutex);
+
+  return callback;
+}
+
+/* gst_wl_display_callback_destroy
+ *
+ * A syncronized version of `wl_callback_destroy` that ensures that the
+ * once this function returns, the callback will either have already completed,
+ * or will never be called.
+ */
+void
+gst_wl_display_callback_destroy (GstWlDisplay * self,
+    struct wl_callback **callback)
+{
+  GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self);
+
+  g_rec_mutex_lock (&priv->sync_mutex);
+
+  if (*callback) {
+    wl_callback_destroy (*callback);
+    *callback = NULL;
+  }
+
+  g_rec_mutex_unlock (&priv->sync_mutex);
+}
+
 struct wl_display *
 gst_wl_display_get_display (GstWlDisplay * self)
 {
index e9b32c65f1f4acc6dcee76c4c7fc1976e9f94da7..3d29b4ea4645ab93b17a5005a52f5b5bf9f994bb 100644 (file)
@@ -52,6 +52,13 @@ void gst_wl_display_register_buffer (GstWlDisplay * self, gpointer gstmem,
 GST_WL_API
 void gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer gstmem);
 
+GST_WL_API
+struct wl_callback * gst_wl_display_sync(GstWlDisplay * self, const struct wl_callback_listener *listener,
+       gpointer data);
+
+GST_WL_API
+void gst_wl_display_callback_destroy(GstWlDisplay * self, struct wl_callback ** callback);
+
 GST_WL_API
 gpointer gst_wl_display_lookup_buffer (GstWlDisplay * self, gpointer gstmem);