[Bf-blender-cvs] [d488a87d701] master: GHOST/Wayland: postpone reading from the clipboard until needed

Campbell Barton noreply at git.blender.org
Fri Oct 28 02:16:38 CEST 2022


Commit: d488a87d7015cc5303e7bea46b40fad467594f1c
Author: Campbell Barton
Date:   Fri Oct 28 09:41:53 2022 +1100
Branches: master
https://developer.blender.org/rBd488a87d7015cc5303e7bea46b40fad467594f1c

GHOST/Wayland: postpone reading from the clipboard until needed

A copy of the clipboard was always being, changes would re-read it.
Now read the clipboard on request. This avoids having to keep a copy
of the clipboard in memory as well as the need to keep a thread
to running to read the clipboard for each data-offer.

To prevent a deadlock when pasting from Blender's own clipboard.

- Sending the clipboard (using write(..)) runs in a background thread.
- Reading the clipboard uses a thread that performs round-trips to the
  Wayland server to prevent until the read is complete.

This is an update to [0] that resolves the deadlock.

[0]: c03838dbc8cc4a85cfc93914493a0f1562a53366

===================================================================

M	intern/ghost/intern/GHOST_SystemWayland.cpp
M	intern/ghost/intern/GHOST_SystemWayland.h

===================================================================

diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 36894807e73..49bed2f9c0e 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -280,15 +280,6 @@ static void gwl_simple_buffer_free_data(GWL_SimpleBuffer *buffer)
   buffer->data_size = 0;
 }
 
-static void gwl_simple_buffer_set_and_take_ownership(GWL_SimpleBuffer *buffer,
-                                                     const char *data,
-                                                     size_t data_size)
-{
-  free(const_cast<char *>(buffer->data));
-  buffer->data = data;
-  buffer->data_size = data_size;
-}
-
 static void gwl_simple_buffer_set_from_string(GWL_SimpleBuffer *buffer, const char *str)
 {
   free(const_cast<char *>(buffer->data));
@@ -298,14 +289,6 @@ static void gwl_simple_buffer_set_from_string(GWL_SimpleBuffer *buffer, const ch
   buffer->data = data;
 }
 
-static char *gwl_simple_buffer_as_string(const GWL_SimpleBuffer *buffer)
-{
-  char *buffer_str = static_cast<char *>(malloc(buffer->data_size + 1));
-  memcpy(buffer_str, buffer->data, buffer->data_size);
-  buffer_str[buffer->data_size] = '\0';
-  return buffer_str;
-}
-
 /** \} */
 
 /* -------------------------------------------------------------------- */
@@ -798,10 +781,6 @@ struct GWL_Display {
   struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr;
 
   struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_device_manager = nullptr;
-
-  GWL_SimpleBuffer clipboard;
-  GWL_SimpleBuffer clipboard_primary;
-  std::mutex clipboard_mutex;
 };
 
 static void gwl_display_destroy(GWL_Display *display)
@@ -838,12 +817,6 @@ static void gwl_display_destroy(GWL_Display *display)
     wl_display_disconnect(display->wl_display);
   }
 
-  {
-    std::lock_guard lock{display->clipboard_mutex};
-    gwl_simple_buffer_free_data(&display->clipboard);
-    gwl_simple_buffer_free_data(&display->clipboard_primary);
-  }
-
   delete display;
 }
 
@@ -1613,7 +1586,7 @@ static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event)
  * Read from `fd` into a buffer which is returned.
  * \return the buffer or null on failure.
  */
-static const char *read_file_as_buffer(const int fd, size_t *r_len)
+static char *read_file_as_buffer(const int fd, const bool nil_terminate, size_t *r_len)
 {
   struct ByteChunk {
     ByteChunk *next;
@@ -1649,14 +1622,23 @@ static const char *read_file_as_buffer(const int fd, size_t *r_len)
 
   char *buf = nullptr;
   if (ok) {
-    buf = static_cast<char *>(malloc(len));
+    buf = static_cast<char *>(malloc(len + (nil_terminate ? 1 : 0)));
     if (UNLIKELY(buf == nullptr)) {
       CLOG_WARN(LOG, "unable to allocate file buffer: %zu bytes", len);
       ok = false;
     }
   }
 
-  *r_len = ok ? len : 0;
+  if (ok) {
+    *r_len = len;
+    if (nil_terminate) {
+      buf[len] = '\0';
+    }
+  }
+  else {
+    *r_len = 0;
+  }
+
   char *buf_stride = buf;
   while (chunk_first) {
     if (ok) {
@@ -1673,10 +1655,11 @@ static const char *read_file_as_buffer(const int fd, size_t *r_len)
   return buf;
 }
 
-static const char *read_buffer_from_data_offer(GWL_DataOffer *data_offer,
-                                               const char *mime_receive,
-                                               std::mutex *mutex,
-                                               size_t *r_len)
+static char *read_buffer_from_data_offer(GWL_DataOffer *data_offer,
+                                         const char *mime_receive,
+                                         std::mutex *mutex,
+                                         const bool nil_terminate,
+                                         size_t *r_len)
 {
   int pipefd[2];
   if (UNLIKELY(pipe(pipefd) != 0)) {
@@ -1696,16 +1679,16 @@ static const char *read_buffer_from_data_offer(GWL_DataOffer *data_offer,
   }
   /* WARNING: `data_offer` may be freed from now on. */
 
-  const char *buf = read_file_as_buffer(pipefd[0], r_len);
+  char *buf = read_file_as_buffer(pipefd[0], nil_terminate, r_len);
   close(pipefd[0]);
   return buf;
 }
 
-static const char *read_buffer_from_primary_selection_offer(
-    GWL_PrimarySelection_DataOffer *data_offer,
-    const char *mime_receive,
-    std::mutex *mutex,
-    size_t *r_len)
+static char *read_buffer_from_primary_selection_offer(GWL_PrimarySelection_DataOffer *data_offer,
+                                                      const char *mime_receive,
+                                                      std::mutex *mutex,
+                                                      const bool nil_terminate,
+                                                      size_t *r_len)
 {
   int pipefd[2];
   if (UNLIKELY(pipe(pipefd) != 0)) {
@@ -1724,7 +1707,7 @@ static const char *read_buffer_from_primary_selection_offer(
     mutex->unlock();
   }
   /* WARNING: `data_offer` may be freed from now on. */
-  const char *buf = read_file_as_buffer(pipefd[0], r_len);
+  char *buf = read_file_as_buffer(pipefd[0], nil_terminate, r_len);
   close(pipefd[0]);
   return buf;
 }
@@ -1748,15 +1731,22 @@ static void data_source_handle_send(void *data,
                                     const int32_t fd)
 {
   GWL_Seat *seat = static_cast<GWL_Seat *>(data);
-  std::lock_guard lock{seat->data_source_mutex};
 
   CLOG_INFO(LOG, 2, "send");
 
-  const char *const buffer = seat->data_source->buffer_out.data;
-  if (UNLIKELY(write(fd, buffer, seat->data_source->buffer_out.data_size) < 0)) {
-    CLOG_WARN(LOG, "error writing to clipboard: %s", std::strerror(errno));
-  }
-  close(fd);
+  auto write_file_fn = [](GWL_Seat *seat, const int fd) {
+    if (UNLIKELY(write(fd,
+                       seat->data_source->buffer_out.data,
+                       seat->data_source->buffer_out.data_size) < 0)) {
+      CLOG_WARN(LOG, "error writing to clipboard: %s", std::strerror(errno));
+    }
+    close(fd);
+    seat->data_source_mutex.unlock();
+  };
+
+  seat->data_source_mutex.lock();
+  std::thread write_thread(write_file_fn, seat, fd);
+  write_thread.detach();
 }
 
 static void data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
@@ -1980,7 +1970,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
 
     size_t data_buf_len = 0;
     const char *data_buf = read_buffer_from_data_offer(
-        data_offer, mime_receive.c_str(), nullptr, &data_buf_len);
+        data_offer, mime_receive.c_str(), nullptr, false, &data_buf_len);
     std::string data = data_buf ? std::string(data_buf, data_buf_len) : "";
     free(const_cast<char *>(data_buf));
 
@@ -2084,34 +2074,6 @@ static void data_device_handle_selection(void *data,
   /* Get new data offer. */
   data_offer = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id));
   seat->data_offer_copy_paste = data_offer;
-
-  auto read_selection_fn = [](GWL_Seat *seat) {
-    GHOST_SystemWayland *const system = seat->system;
-    seat->data_offer_copy_paste_mutex.lock();
-
-    GWL_DataOffer *data_offer = seat->data_offer_copy_paste;
-    std::string mime_receive;
-    for (const std::string type : {mime_text_utf8, mime_text_plain}) {
-      if (data_offer->types.count(type)) {
-        mime_receive = type;
-        break;
-      }
-    }
-
-    size_t data_len = 0;
-    const char *data = read_buffer_from_data_offer(
-        data_offer, mime_receive.c_str(), &seat->data_offer_copy_paste_mutex, &data_len);
-
-    {
-      std::mutex &clipboard_mutex = system->clipboard_mutex();
-      std::lock_guard lock{clipboard_mutex};
-      GWL_SimpleBuffer *buf = system->clipboard_data(false);
-      gwl_simple_buffer_set_and_take_ownership(buf, data, data_len);
-    }
-  };
-
-  std::thread read_thread(read_selection_fn, seat);
-  read_thread.detach();
 }
 
 static const struct wl_data_device_listener data_device_listener = {
@@ -3664,33 +3626,6 @@ static void primary_selection_device_handle_selection(
   GWL_PrimarySelection_DataOffer *data_offer = static_cast<GWL_PrimarySelection_DataOffer *>(
       zwp_primary_selection_offer_v1_get_user_data(id));
   primary->data_offer = data_offer;
-
-  auto read_selection_fn = [](GWL_PrimarySelection *primary) {
-    GHOST_SystemWayland *system = static_cast<GHOST_SystemWayland *>(GHOST_ISystem::getSystem());
-    primary->data_offer_mutex.lock();
-
-    GWL_PrimarySelection_DataOffer *data_offer = primary->data_offer;
-    std::string mime_receive;
-    for (const std::string type : {mime_text_utf8, mime_text_plain}) {
-      if (data_offer->types.count(type)) {
-        mime_receive = type;
-        break;
-      }
-    }
-    size_t data_len = 0;
-    const char *data = read_buffer_from_primary_selection_offer(
-        data_offer, mime_receive.c_str(), &primary->data_offer_mutex, &data_len);
-
-    {
-      std::mutex &clipboard_mutex = system->clipboard_mutex();
-      std::lock_guard lock{clipboard_mutex};
-      GWL_SimpleBuffer *buf = system->clipboard_data(true);
-      gwl_simple_buffer_set_and_take_ownership(buf, data, data_len);
-    }
-  };
-
-  std::thread read_thread(read_selection_fn, primary);
-  read_thread.detach();
 }
 
 static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
@@ -3718,14 +3653,19 @@ static void primary_selection_source_send(void *data,
 
   GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data);
 
-  std::lock_guard lock{primary->data_source_mutex};
-  GWL_PrimarySelection_DataSource *data_source = primary->data_source;
+  auto write_file_fn = [](GWL_PrimarySelection *primary, const int fd) {
+    if (UNLIKELY(write(fd,
+                       primary->data_source->buffer_out.data,
+                       primary->data_source->buffer_out.data_size) < 0)) {
+      CLOG_WARN(LOG, "error writing to primary clipboard: %s", std::strerror(errno));
+    }
+    close(fd);
+    primary->data_source_mutex.unlock();
+  };
 
-  const char *const buffer = data_source->buffer_out.data;
-  if (UNLIKELY(write(fd, buffer, data_source->buffer_out.data_size) < 0)) {
-    CLOG_WARN(LOG, "error writing to primary clipboard: %s", std::strerror(errno));
-  }
-  close(fd)

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list