From e2d22eebca3b2dc11279e6e6fd46aa3d60db8c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Mon, 12 Mar 2012 14:58:51 +0100 Subject: Updated to use the Thread affinity patch that we tried to upstream Change-Id: I11138634f4c3d5e673d764cdcb36e7b503aafca0 Reviewed-by: Laszlo Agocs --- ...01-Add-thread-affinity-to-wayland-clients.patch | 253 +++++++++++++++++++++ ...ed-superfluous-call-to-wl_copy_connection.patch | 31 --- ...2-Fix-for-issues-with-threaded-GL-drivers.patch | 171 -------------- src/plugins/platforms/wayland/qwaylanddisplay.cpp | 2 +- 4 files changed, 254 insertions(+), 203 deletions(-) create mode 100644 patches/0001-Add-thread-affinity-to-wayland-clients.patch delete mode 100644 patches/0001-Removed-superfluous-call-to-wl_copy_connection.patch delete mode 100644 patches/0002-Fix-for-issues-with-threaded-GL-drivers.patch diff --git a/patches/0001-Add-thread-affinity-to-wayland-clients.patch b/patches/0001-Add-thread-affinity-to-wayland-clients.patch new file mode 100644 index 000000000..3838a22b7 --- /dev/null +++ b/patches/0001-Add-thread-affinity-to-wayland-clients.patch @@ -0,0 +1,253 @@ +From 24b8dccb2f48bc8595d40288106d51d3f4605544 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B8rgen=20Lind?= +Date: Mon, 5 Mar 2012 12:44:37 +0100 +Subject: [PATCH 1/2] Add thread affinity to wayland clients + +This makes it possible to marshal requests from more than 1 thread in +wayland clients. However, its not possible to run wl_display_iterate +from other threads than the thread that made the wl_display. +--- + src/Makefile.am | 2 + + src/wayland-client.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++-- + src/wayland-client.h | 6 +++ + 3 files changed, 112 insertions(+), 5 deletions(-) + +diff --git a/src/Makefile.am b/src/Makefile.am +index f356b54..9aab9de 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -24,6 +24,8 @@ libwayland_server_la_SOURCES = \ + event-loop.c + + libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt ++libwayland_client_la_LDFLAGS = -pthread ++libwayland_client_la_CFLAGS = -pthread + libwayland_client_la_SOURCES = \ + wayland-protocol.c \ + wayland-client.c +diff --git a/src/wayland-client.c b/src/wayland-client.c +index 498a429..9eb4b25 100644 +--- a/src/wayland-client.c ++++ b/src/wayland-client.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "wayland-util.h" + #include "wayland-client.h" +@@ -62,6 +63,9 @@ struct wl_display { + struct wl_proxy proxy; + struct wl_connection *connection; + int fd; ++ int write_notification_event_fd; ++ pthread_t thread_id; ++ pthread_mutex_t marshalling_mutex; + uint32_t mask; + struct wl_map objects; + struct wl_list global_listener_list; +@@ -191,7 +195,11 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) + { + struct wl_closure *closure; + va_list ap; ++ int write_notification_event_fd; ++ uint64_t write_notification_value; ++ ssize_t success; + ++ pthread_mutex_lock(&proxy->display->marshalling_mutex); + va_start(ap, opcode); + closure = wl_connection_vmarshal(proxy->display->connection, + &proxy->object, opcode, ap, +@@ -212,6 +220,18 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) + wl_closure_print(closure, &proxy->object, true); + + wl_closure_destroy(closure); ++ ++ write_notification_event_fd = proxy->display->write_notification_event_fd; ++ write_notification_value = 1; ++ success = write(write_notification_event_fd,&write_notification_value,8); ++ if (success < 0) { ++ fprintf(stderr, ++ "Error writing to eventfd %d: %s\n", ++ write_notification_event_fd, ++ strerror(errno)); ++ } ++ ++ pthread_mutex_unlock(&proxy->display->marshalling_mutex); + } + + /* Can't do this, there may be more than one instance of an +@@ -347,6 +367,7 @@ wl_display_connect(const char *name) + const char *debug; + char *connection, *end; + int flags; ++ int success; + + debug = getenv("WAYLAND_DEBUG"); + if (debug) +@@ -396,6 +417,21 @@ wl_display_connect(const char *name) + return NULL; + } + ++ display->write_notification_event_fd = eventfd(0, EFD_CLOEXEC); ++ if (display->write_notification_event_fd < 0) { ++ fprintf(stderr, "Failed to create eventfd\n"); ++ } ++ ++ display->thread_id = pthread_self(); ++ pthread_mutexattr_t mutex_attr; ++ success = pthread_mutexattr_init(&mutex_attr); ++ success += pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_RECURSIVE); ++ success += pthread_mutex_init(&display->marshalling_mutex, &mutex_attr); ++ success += pthread_mutexattr_destroy(&mutex_attr); ++ ++ if (success) ++ fprintf(stderr, "Threading setup was unsuccessfull\n"); ++ + return display; + } + +@@ -432,6 +468,18 @@ wl_display_get_fd(struct wl_display *display, + return display->fd; + } + ++WL_EXPORT int ++wl_display_get_write_notification_fd(struct wl_display *display) ++{ ++ return display->write_notification_event_fd; ++} ++ ++WL_EXPORT pthread_t ++wl_display_thread(struct wl_display *display) ++{ ++ return display->thread_id; ++} ++ + static void + sync_callback(void *data, struct wl_callback *callback, uint32_t time) + { +@@ -445,18 +493,46 @@ static const struct wl_callback_listener sync_listener = { + sync_callback + }; + ++static void ++threaded_sync_callback(void *data, struct wl_callback *callback, uint32_t time) ++{ ++ fprintf(stderr, "threaded_sync_callback\n"); ++ pthread_cond_t *wait_condition = data; ++ ++ pthread_cond_broadcast(wait_condition); ++ wl_callback_destroy(callback); ++} ++ ++static const struct wl_callback_listener threaded_sync_listener = { ++ threaded_sync_callback ++}; ++ + WL_EXPORT void + wl_display_roundtrip(struct wl_display *display) + { + struct wl_callback *callback; + int done; ++ pthread_cond_t wait_cond; ++ pthread_mutex_t wait_mutex; + +- done = 0; + callback = wl_display_sync(display); +- wl_callback_add_listener(callback, &sync_listener, &done); +- wl_display_flush(display); +- while (!done) +- wl_display_iterate(display, WL_DISPLAY_READABLE); ++ ++ if (wl_display_thread(display) == pthread_self()) { ++ done = 0; ++ wl_callback_add_listener(callback, &sync_listener, &done); ++ wl_display_flush(display); ++ while (!done) ++ wl_display_iterate(display, WL_DISPLAY_READABLE); ++ } else { ++ pthread_mutex_init(&wait_mutex,NULL); ++ pthread_cond_init(&wait_cond, NULL); ++ pthread_mutex_lock(&wait_mutex); ++ ++ wl_callback_add_listener(callback, &threaded_sync_listener, &wait_cond); ++ pthread_cond_wait(&wait_cond,&wait_mutex); ++ pthread_cond_destroy(&wait_cond); ++ pthread_mutex_destroy(&wait_mutex); ++ } + } + + static void +@@ -500,7 +576,11 @@ WL_EXPORT void + wl_display_iterate(struct wl_display *display, uint32_t mask) + { + uint32_t p[2], object, opcode, size; ++ uint64_t write_fd; + int len; ++ ssize_t success; ++ ++ pthread_mutex_lock(&display->marshalling_mutex); + + mask &= display->mask; + if (mask == 0) { +@@ -509,6 +589,23 @@ wl_display_iterate(struct wl_display *display, uint32_t mask) + return; + } + ++ if (mask & WL_DISPLAY_WRITABLE) { ++ if (pthread_self() != display->thread_id) { ++ fprintf(stderr, ++ "wl_display_iterate called with WL_DISPLAY_WRITABLE" ++ "from another thread than the thead that created " ++ "wl_display. This will result in events being dispatched" ++ "in other threads\n"); ++ } ++ success = read(display->write_notification_event_fd, &write_fd, 8); ++ if (success < 0) { ++ fprintf(stderr, ++ "wl_display_iterate eventfd %d error at read: %s\n", ++ display->write_notification_event_fd, ++ strerror(errno)); ++ } ++ } ++ + len = wl_connection_data(display->connection, mask); + + while (len > 0) { +@@ -526,6 +623,8 @@ wl_display_iterate(struct wl_display *display, uint32_t mask) + len -= size; + } + ++ pthread_mutex_unlock(&display->marshalling_mutex); ++ + if (len < 0) { + fprintf(stderr, "read error: %m\n"); + exit(EXIT_FAILURE); +diff --git a/src/wayland-client.h b/src/wayland-client.h +index b04a7ef..a680cab 100644 +--- a/src/wayland-client.h ++++ b/src/wayland-client.h +@@ -25,6 +25,9 @@ + + #include "wayland-util.h" + ++#include ++#define WAYLAND_CLIENT_THREAD_AFFINITY ++ + #ifdef __cplusplus + extern "C" { + #endif +@@ -94,6 +97,9 @@ uint32_t + wl_display_get_global(struct wl_display *display, + const char *interface, uint32_t version); + ++int wl_display_get_write_notification_fd(struct wl_display *display); ++pthread_t wl_display_thread(struct wl_display *display); ++ + #ifdef __cplusplus + } + #endif +-- +1.7.5.4 + diff --git a/patches/0001-Removed-superfluous-call-to-wl_copy_connection.patch b/patches/0001-Removed-superfluous-call-to-wl_copy_connection.patch deleted file mode 100644 index 4a9ebf4cf..000000000 --- a/patches/0001-Removed-superfluous-call-to-wl_copy_connection.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 42a5ccf0f6e42c1487fef1d5422939bc6836044d Mon Sep 17 00:00:00 2001 -From: Andy Nichols -Date: Thu, 24 Nov 2011 10:19:18 +0100 -Subject: [PATCH 1/2] Removed superfluous call to wl_copy_connection - -The only purpose those code seems to serve is to introduce a buffer -overflow when events contain more than 128 bytes of data. ---- - src/wayland-client.c | 2 -- - 1 files changed, 0 insertions(+), 2 deletions(-) - -diff --git a/src/wayland-client.c b/src/wayland-client.c -index 939c17d..fd5a8fa 100644 ---- a/src/wayland-client.c -+++ b/src/wayland-client.c -@@ -445,12 +445,10 @@ static void - handle_event(struct wl_display *display, - uint32_t id, uint32_t opcode, uint32_t size) - { -- uint32_t p[32]; - struct wl_proxy *proxy; - struct wl_closure *closure; - const struct wl_message *message; - -- wl_connection_copy(display->connection, p, size); - proxy = wl_map_lookup(&display->objects, id); - - if (proxy == WL_ZOMBIE_OBJECT) { --- -1.7.8.rc2 - diff --git a/patches/0002-Fix-for-issues-with-threaded-GL-drivers.patch b/patches/0002-Fix-for-issues-with-threaded-GL-drivers.patch deleted file mode 100644 index 902d7f4bf..000000000 --- a/patches/0002-Fix-for-issues-with-threaded-GL-drivers.patch +++ /dev/null @@ -1,171 +0,0 @@ -From d0fb8027cea418531f25be8750c8da1d7fcfe5e2 Mon Sep 17 00:00:00 2001 -From: Paul Olav Tvete -Date: Wed, 16 Nov 2011 16:55:33 +0100 -Subject: [PATCH 2/2] Fix for issues with threaded GL drivers - -Two problems arise with asynchronous GL drivers that allow issuing -GL commands for the next frame before the GPU is done with the current frame: - -1. The client code never knows when it is necessary to call wl_display_iterate. - -Solution: Write to a pipe when there is data to be sent. The client can then select() on -the pipe's fd. - -2. The GL library might call wl_surface_attach/wl_surface_damage while the main thread is -doing wl_display_iterate. - -Solution: Protect wl_display_iterate and wl_proxy_marshal with a mutex ---- - src/wayland-client.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++- - src/wayland-client.h | 9 +++++++ - 2 files changed, 69 insertions(+), 1 deletions(-) - -diff --git a/src/wayland-client.c b/src/wayland-client.c -index fd5a8fa..979dadf 100644 ---- a/src/wayland-client.c -+++ b/src/wayland-client.c -@@ -34,6 +34,7 @@ - #include - #include - #include -+#include - - #include "wayland-util.h" - #include "wayland-client.h" -@@ -62,6 +63,9 @@ struct wl_display { - struct wl_proxy proxy; - struct wl_connection *connection; - int fd; -+#ifdef QTWAYLAND_EXPERIMENTAL_THREAD_SUPPORT -+ int pipefd[2]; -+#endif - uint32_t mask; - struct wl_map objects; - struct wl_list global_listener_list; -@@ -186,9 +190,42 @@ wl_proxy_add_listener(struct wl_proxy *proxy, - return 0; - } - -+static void -+display_signal_flush_needed(struct wl_display *display) -+{ -+#ifdef QTWAYLAND_EXPERIMENTAL_THREAD_SUPPORT -+ const char data = '!'; -+ if (display->pipefd[1]) -+ write(display->pipefd[1], &data, 1); -+#endif -+} -+ -+ -+#ifdef QTWAYLAND_EXPERIMENTAL_THREAD_SUPPORT -+static pthread_mutex_t foo_mutex = PTHREAD_MUTEX_INITIALIZER; -+static pthread_t foo_locker; -+ -+#define FOO_MUTEX_LOCK \ -+ int foo_needLock = (pthread_self() != foo_locker); \ -+ if (foo_needLock) { \ -+ pthread_mutex_lock(&foo_mutex); \ -+ foo_locker = pthread_self(); \ -+ } -+ -+#define FOO_MUTEX_UNLOCK \ -+ if (foo_needLock) { \ -+ foo_locker = 0; \ -+ pthread_mutex_unlock(&foo_mutex); \ -+ } -+#else -+#define FOO_MUTEX_LOCK -+#define FOO_MUTEX_UNLOCK -+#endif -+ - WL_EXPORT void - wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) - { -+ FOO_MUTEX_LOCK; - struct wl_closure *closure; - va_list ap; - -@@ -204,6 +241,8 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) - wl_closure_print(closure, &proxy->object, true); - - wl_closure_destroy(closure); -+ display_signal_flush_needed(proxy->display); -+ FOO_MUTEX_UNLOCK; - } - - /* Can't do this, there may be more than one instance of an -@@ -414,6 +453,17 @@ wl_display_get_fd(struct wl_display *display, - return display->fd; - } - -+#ifdef QTWAYLAND_EXPERIMENTAL_THREAD_SUPPORT -+WL_EXPORT int -+wl_display_get_write_notification_fd(struct wl_display *display) -+{ -+ if (!display->pipefd[0]) { -+ pipe2(display->pipefd, O_CLOEXEC | O_NONBLOCK); -+ } -+ return display->pipefd[0]; -+} -+#endif -+ - static void - sync_callback(void *data, struct wl_callback *callback, uint32_t time) - { -@@ -482,16 +532,24 @@ handle_event(struct wl_display *display, - WL_EXPORT void - wl_display_iterate(struct wl_display *display, uint32_t mask) - { -+ FOO_MUTEX_LOCK; - uint32_t p[2], object, opcode, size; - int len; -- -+#ifdef QTWAYLAND_EXPERIMENTAL_THREAD_SUPPORT -+ if ((mask & WL_DISPLAY_WRITABLE) && display->pipefd[0]) { -+ char buf[80]; -+ int n = read(display->pipefd[0], buf, 80); -+ } -+#endif - mask &= display->mask; - if (mask == 0) { - fprintf(stderr, - "wl_display_iterate called with unsolicited flags"); -+ FOO_MUTEX_UNLOCK; - return; - } - -+ - len = wl_connection_data(display->connection, mask); - - while (len > 0) { -@@ -513,6 +571,7 @@ wl_display_iterate(struct wl_display *display, uint32_t mask) - fprintf(stderr, "read error: %m\n"); - exit(EXIT_FAILURE); - } -+ FOO_MUTEX_UNLOCK; - } - - WL_EXPORT void -diff --git a/src/wayland-client.h b/src/wayland-client.h -index efeee4a..050f7f2 100644 ---- a/src/wayland-client.h -+++ b/src/wayland-client.h -@@ -94,6 +94,15 @@ uint32_t - wl_display_get_global(struct wl_display *display, - const char *interface, uint32_t version); - -+ -+ -+#define QTWAYLAND_EXPERIMENTAL_THREAD_SUPPORT -+ -+#ifdef QTWAYLAND_EXPERIMENTAL_THREAD_SUPPORT -+int wl_display_get_write_notification_fd(struct wl_display *display); -+#endif -+ -+ - #ifdef __cplusplus - } - #endif --- -1.7.8.rc2 - diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 73b46c459..fb3e947ce 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -132,7 +132,7 @@ QWaylandDisplay::QWaylandDisplay(void) mFd = wl_display_get_fd(mDisplay, dummyUpdate, 0); -#ifdef QTWAYLAND_EXPERIMENTAL_THREAD_SUPPORT +#ifdef WAYLAND_CLIENT_THREAD_AFFINITY mWritableNotificationFd = wl_display_get_write_notification_fd(mDisplay); QSocketNotifier *wn = new QSocketNotifier(mWritableNotificationFd, QSocketNotifier::Read, this); connect(wn, SIGNAL(activated(int)), this, SLOT(flushRequests())); -- cgit v1.2.3