Hi,

I had some time today update the patch to add thread affinity to
wayland-clients wl_display.

Jørgen
>From eca8c247e18c66d691aa07fc16cbaa9ea1e5e843 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B8rgen=20Lind?= <[email protected]>
Date: Mon, 5 Mar 2012 12:44:37 +0100
Subject: [PATCH] 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 |  102 +++++++++++++++++++++++++++++++++++++++++++++++--
 src/wayland-client.h |    5 ++
 3 files changed, 104 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..b5a2853 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -34,6 +34,8 @@
 #include <assert.h>
 #include <fcntl.h>
 #include <sys/poll.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
 
 #include "wayland-util.h"
 #include "wayland-client.h"
@@ -62,6 +64,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 +196,10 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, 
...)
 {
        struct wl_closure *closure;
        va_list ap;
+       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,14 @@ wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, 
...)
                wl_closure_print(closure, &proxy->object, true);
 
        wl_closure_destroy(closure);
+
+       write_notification_value = 1;
+       success = 
write(proxy->display->write_notification_event_fd,&write_notification_value,8);
+       if (success < 0) {
+               fprintf(stderr, "Error writing to eventfd\n");
+       }
+
+       pthread_mutex_unlock(&proxy->display->marshalling_mutex);
 }
 
 /* Can't do this, there may be more than one instance of an
@@ -347,6 +363,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 +413,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 not successfull\n");
+
        return display;
 }
 
@@ -432,6 +464,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 +489,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 +572,17 @@ WL_EXPORT void
 wl_display_iterate(struct wl_display *display, uint32_t mask)
 {
        uint32_t p[2], object, opcode, size;
+       uint64_t write_notification_value;
        int len;
+       ssize_t success;
+
+       if (pthread_self() != display->thread_id)
+               fprintf(stderr,
+                       "wl_display_iterate called from another thread than "
+                       "the thead that created wl_display. This will result "
+                       "in undefined behavior\n");
+
+       pthread_mutex_lock(&display->marshalling_mutex);
 
        mask &= display->mask;
        if (mask == 0) {
@@ -509,6 +591,14 @@ wl_display_iterate(struct wl_display *display, uint32_t 
mask)
                return;
        }
 
+       if (mask & WL_DISPLAY_WRITABLE) {
+               success = read(display->write_notification_event_fd,
+                       &write_notification_value, 8);
+               if (success < 0)
+                       fprintf(stderr,
+                               "wl_display_iterate eventfd error at read\n");
+       }
+
        len = wl_connection_data(display->connection, mask);
 
        while (len > 0) {
@@ -526,6 +616,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..f5c722b 100644
--- a/src/wayland-client.h
+++ b/src/wayland-client.h
@@ -25,6 +25,8 @@
 
 #include "wayland-util.h"
 
+#include <pthread.h>
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
@@ -94,6 +96,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

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to