wayland-server: Add mutex for wl_client's resources 35/295135/3
authorSeunghun Lee <shiin.lee@samsung.com>
Thu, 18 May 2023 05:21:28 +0000 (14:21 +0900)
committerSeunghun Lee <shiin.lee@samsung.com>
Tue, 4 Jul 2023 01:50:19 +0000 (10:50 +0900)
This patch is to prevent threads from accessing wl_client's resources at
the same time.

Change-Id: I5da933efd426b8535ba1cb6144ad0f47fe2e4415

src/wayland-server.c

index 2ffcd8c..b082d3e 100644 (file)
@@ -43,6 +43,7 @@
 #include <sys/eventfd.h>
 #include <sys/file.h>
 #include <sys/stat.h>
+#include <pthread.h>
 
 #include "wayland-util.h"
 #include "wayland-private.h"
@@ -87,6 +88,8 @@ struct wl_client {
        char proc_name[WL_CLIENT_NAME_MAX];
        int error;
        struct wl_priv_signal resource_created_signal;
+       pthread_mutex_t connection_mutex;
+       pthread_mutex_t objects_mutex;
 };
 
 struct wl_display {
@@ -247,6 +250,7 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
 
        log_closure(resource, closure, true);
 
+       pthread_mutex_lock(&resource->client->connection_mutex);
        if (send_func(closure, resource->client->connection)) {
                if (errno == EAGAIN) {
                        wl_event_source_fd_update(resource->client->source,
@@ -256,6 +260,7 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
                        resource->client->error = 1;
                }
        }
+       pthread_mutex_unlock(&resource->client->connection_mutex);
 
        wl_closure_destroy(closure);
 }
@@ -379,16 +384,19 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
        int len;
        int pid;
 
+       pthread_mutex_lock(&client->connection_mutex);
+       pthread_mutex_lock(&client->objects_mutex);
+
        if (mask & WL_EVENT_HANGUP) {
                wl_log("Mask has hangup flag set, client_proc(%s) PID(%d) mask[%x]\n",
                           client->proc_name, client->pid, mask);
                wl_client_destroy(client);
-               return 1;
+               goto end;
        }
 
        if (mask & WL_EVENT_ERROR) {
                destroy_client_with_error(client, "socket error");
-               return 1;
+               goto end;
        }
 
        if (mask & WL_EVENT_WRITABLE) {
@@ -399,7 +407,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
                if (len < 0 && errno != EAGAIN) {
                        destroy_client_with_error(
                            client, "failed to flush client connection");
-                       return 1;
+                       goto end;
                } else if (len >= 0) {
                        wl_event_source_fd_update(client->source,
                                                  WL_EVENT_READABLE);
@@ -415,7 +423,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
                if (len == 0 || (len < 0 && errno != EAGAIN)) {
                        destroy_client_with_error(
                            client, "failed to read client connection");
-                       return 1;
+                       goto end;
                }
        }
 
@@ -505,6 +513,10 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
                                          "error in client communication");
        }
 
+end:
+       pthread_mutex_unlock(&client->objects_mutex);
+       pthread_mutex_unlock(&client->connection_mutex);
+
        return 1;
 }
 
@@ -522,7 +534,9 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
 WL_EXPORT void
 wl_client_flush(struct wl_client *client)
 {
+       pthread_mutex_lock(&client->connection_mutex);
        int ret = wl_connection_flush(client->connection);
+       pthread_mutex_unlock(&client->connection_mutex);
 
        if (ret < 0 && errno != EAGAIN && errno != EPIPE)
                wl_log("client_proc(%s) flush failed: ret(%d) errno(%d)\n",
@@ -643,6 +657,9 @@ wl_client_create(struct wl_display *display, int fd)
 
        wl_client_get_process_name(client);
 
+       pthread_mutex_init(&client->connection_mutex, NULL);
+       pthread_mutex_init(&client->objects_mutex, NULL);
+
        wl_list_insert(display->client_list.prev, &client->link);
 
        wl_priv_signal_emit(&display->create_client_signal, client);
@@ -798,13 +815,17 @@ wl_resource_post_no_memory(struct wl_resource *resource)
 static bool
 resource_is_deprecated(struct wl_resource *resource)
 {
-       struct wl_map *map = &resource->client->objects;
+       struct wl_client *client = resource->client;
        int id = resource->object.id;
 
+       pthread_mutex_lock(&client->objects_mutex);
+
        /* wl_client_add_resource() marks deprecated resources with the flag. */
-       if (wl_map_lookup_flags(map, id) & WL_MAP_ENTRY_LEGACY)
+       if (wl_map_lookup_flags(&client->objects, id) & WL_MAP_ENTRY_LEGACY)
                return true;
 
+       pthread_mutex_unlock(&client->objects_mutex);
+
        return false;
 }
 
@@ -835,6 +856,8 @@ wl_resource_destroy(struct wl_resource *resource)
        uint32_t id;
        uint32_t flags;
 
+       pthread_mutex_lock(&client->objects_mutex);
+
        id = resource->object.id;
        flags = wl_map_lookup_flags(&client->objects, id);
        destroy_resource(resource, NULL, flags);
@@ -848,6 +871,8 @@ wl_resource_destroy(struct wl_resource *resource)
        } else {
                wl_map_remove(&client->objects, id);
        }
+
+       pthread_mutex_unlock(&client->objects_mutex);
 }
 
 WL_EXPORT uint32_t
@@ -984,6 +1009,9 @@ wl_client_destroy(struct wl_client *client)
 
        wl_priv_signal_final_emit(&client->destroy_signal, client);
 
+       pthread_mutex_destroy(&client->objects_mutex);
+       pthread_mutex_destroy(&client->connection_mutex);
+
        wl_client_flush(client);
        wl_map_for_each(&client->objects, destroy_resource, &serial);
        wl_map_release(&client->objects);
@@ -1551,7 +1579,9 @@ wl_display_flush_clients(struct wl_display *display)
        int ret;
 
        wl_list_for_each_safe(client, next, &display->client_list, link) {
+               pthread_mutex_lock(&client->connection_mutex);
                ret = wl_connection_flush(client->connection);
+               pthread_mutex_unlock(&client->connection_mutex);
                if (ret < 0)
                        wl_log("client_proc(%s) PID(%d) flush failed: ret(%d) errno(%d)\n",
                                   client->proc_name, client->pid, ret, errno);
@@ -1963,14 +1993,19 @@ wl_resource_create(struct wl_client *client,
 {
        struct wl_resource *resource;
 
+       pthread_mutex_lock(&client->objects_mutex);
+
        resource = zalloc(sizeof *resource);
-       if (resource == NULL)
+       if (resource == NULL) {
+               pthread_mutex_unlock(&client->objects_mutex);
                return NULL;
+       }
 
        if (id == 0) {
                id = wl_map_insert_new(&client->objects, 0, NULL);
                if (id == 0) {
                        free(resource);
+                       pthread_mutex_unlock(&client->objects_mutex);
                        return NULL;
                }
        }
@@ -1995,9 +2030,12 @@ wl_resource_create(struct wl_client *client,
                                               "invalid new id %d", id);
                }
                free(resource);
+               pthread_mutex_unlock(&client->objects_mutex);
                return NULL;
        }
 
+       pthread_mutex_unlock(&client->objects_mutex);
+
        wl_priv_signal_emit(&client->resource_created_signal, resource);
        return resource;
 }
@@ -2095,6 +2133,11 @@ wl_display_add_shm_format(struct wl_display *display, uint32_t format)
        return p;
 }
 
+/* TIZEN_ONLY(20230704) : wayland-server: Add mutex for wl_client's resources
+ *
+ * WARNING: The `wl_map *` returned by this API is NOT thread-safe since the
+ * commit described above was introduced.
+ */
 WL_EXPORT struct wl_map *
 wl_client_get_resources(struct wl_client *client)
 {
@@ -2240,7 +2283,9 @@ wl_client_for_each_resource(struct wl_client *client,
                .it = iterator,
        };
 
+       pthread_mutex_lock(&client->objects_mutex);
        wl_map_for_each(&client->objects, resource_iterator_helper, &context);
+       pthread_mutex_unlock(&client->objects_mutex);
 }
 
 static void