diff --git a/src/connection.c b/src/connection.c index a6ad4105..b89166fb 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1283,7 +1283,8 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) void wl_closure_print(struct wl_closure *closure, struct wl_object *target, - int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg)) + int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg), + const char *queue_name) { int i; struct argument_details arg; @@ -1302,8 +1303,12 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); - fprintf(f, "[%7u.%03u] %s%s%s#%u.%s(", - time / 1000, time % 1000, + fprintf(f, "[%7u.%03u] ", time / 1000, time % 1000); + + if (queue_name) + fprintf(f, "{%s} ", queue_name); + + fprintf(f, "%s%s%s#%u.%s(", discarded ? "discarded " : "", send ? " -> " : "", target->interface->name, target->id, diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h index af50f1e5..20b2a3b2 100644 --- a/src/wayland-client-core.h +++ b/src/wayland-client-core.h @@ -225,6 +225,12 @@ wl_proxy_get_display(struct wl_proxy *proxy); void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); +struct wl_event_queue * +wl_proxy_get_queue(const struct wl_proxy *proxy); + +const char * +wl_event_queue_get_name(const struct wl_event_queue *queue); + struct wl_display * wl_display_connect(const char *name); @@ -272,6 +278,10 @@ wl_display_roundtrip(struct wl_display *display); struct wl_event_queue * wl_display_create_queue(struct wl_display *display); +struct wl_event_queue * +wl_display_create_queue_with_name(struct wl_display *display, + const char *name); + int wl_display_prepare_read_queue(struct wl_display *display, struct wl_event_queue *queue); diff --git a/src/wayland-client.c b/src/wayland-client.c index 489f0a8d..94438e30 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -77,6 +77,7 @@ struct wl_event_queue { struct wl_list event_list; struct wl_list proxy_list; /**< struct wl_proxy::queue_link */ struct wl_display *display; + char *name; }; struct wl_display { @@ -220,11 +221,15 @@ display_protocol_error(struct wl_display *display, uint32_t code, } static void -wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display) +wl_event_queue_init(struct wl_event_queue *queue, + struct wl_display *display, + const char *name) { wl_list_init(&queue->event_list); wl_list_init(&queue->proxy_list); queue->display = display; + if (name) + queue->name = strdup(name); } static void @@ -305,8 +310,15 @@ wl_event_queue_release(struct wl_event_queue *queue) struct wl_proxy *proxy, *tmp; if (queue != &queue->display->default_queue) { - wl_log("warning: queue %p destroyed while proxies " - "still attached:\n", queue); + if (queue->name) { + wl_log("warning: queue \"%s\" " + "%p destroyed while proxies " + "still attached:\n", queue->name, queue); + } else { + wl_log("warning: queue " + "%p destroyed while proxies " + "still attached:\n", queue); + } } wl_list_for_each_safe(proxy, tmp, &queue->proxy_list, @@ -350,6 +362,7 @@ wl_event_queue_destroy(struct wl_event_queue *queue) pthread_mutex_lock(&display->mutex); wl_event_queue_release(queue); + free(queue->name); free(queue); pthread_mutex_unlock(&display->mutex); } @@ -371,7 +384,30 @@ wl_display_create_queue(struct wl_display *display) if (queue == NULL) return NULL; - wl_event_queue_init(queue, display); + wl_event_queue_init(queue, display, NULL); + + return queue; +} + +/** Create a new event queue for this display and give it a name + * + * \param display The display context object + * \param name A human readable queue name + * \return A new event queue associated with this display or NULL on + * failure. + * + * \memberof wl_display + */ +WL_EXPORT struct wl_event_queue * +wl_display_create_queue_with_name(struct wl_display *display, const char *name) +{ + struct wl_event_queue *queue; + + queue = zalloc(sizeof *queue); + if (queue == NULL) + return NULL; + + wl_event_queue_init(queue, display, name); return queue; } @@ -885,8 +921,13 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, goto err_unlock; } - if (debug_client) - wl_closure_print(closure, &proxy->object, true, false, NULL); + if (debug_client) { + struct wl_event_queue *queue; + + queue = wl_proxy_get_queue(proxy); + wl_closure_print(closure, &proxy->object, true, false, NULL, + wl_event_queue_get_name(queue)); + } if (wl_closure_send(closure, proxy->display->connection)) { wl_log("Error sending request: %s\n", strerror(errno)); @@ -1188,8 +1229,8 @@ wl_display_connect_to_fd(int fd) display->fd = fd; wl_map_init(&display->objects, WL_MAP_CLIENT_SIDE); - wl_event_queue_init(&display->default_queue, display); - wl_event_queue_init(&display->display_queue, display); + wl_event_queue_init(&display->default_queue, display, "Default Queue"); + wl_event_queue_init(&display->display_queue, display, "Display Queue"); pthread_mutex_init(&display->mutex, NULL); pthread_cond_init(&display->reader_cond, NULL); display->reader_count = 0; @@ -1321,7 +1362,9 @@ wl_display_disconnect(struct wl_display *display) wl_map_for_each(&display->objects, free_zombies, NULL); wl_map_release(&display->objects); wl_event_queue_release(&display->default_queue); + free(display->default_queue.name); wl_event_queue_release(&display->display_queue); + free(display->display_queue.name); pthread_mutex_destroy(&display->mutex); pthread_cond_destroy(&display->reader_cond); close(display->fd); @@ -1611,7 +1654,8 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); if (proxy_destroyed) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, true, id_from_object); + wl_closure_print(closure, &proxy->object, false, true, + id_from_object, queue->name); destroy_queued_closure(closure); return; } @@ -1620,13 +1664,15 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue) if (proxy->dispatcher) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, false, id_from_object); + wl_closure_print(closure, &proxy->object, false, false, + id_from_object, queue->name); wl_closure_dispatch(closure, proxy->dispatcher, &proxy->object, opcode); } else if (proxy->object.implementation) { if (debug_client) - wl_closure_print(closure, &proxy->object, false, false, id_from_object); + wl_closure_print(closure, &proxy->object, false, false, + id_from_object, queue->name); wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT, &proxy->object, opcode, proxy->user_data); @@ -2399,6 +2445,34 @@ wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) pthread_mutex_unlock(&proxy->display->mutex); } +/** Get a proxy's event queue + * + * \param proxy The proxy to query + * + * Return the event queue + */ +WL_EXPORT struct wl_event_queue * +wl_proxy_get_queue(const struct wl_proxy *proxy) +{ + return proxy->queue; + +} +/** Get the name of an event queue + * + * \param queue The queue to query + * + * Return the human readable name for the event queue + * + * This may be NULL if no name has been set. + * + * \memberof wl_proxy + */ +WL_EXPORT const char * +wl_event_queue_get_name(const struct wl_event_queue *queue) +{ + return queue->name; +} + /** Create a proxy wrapper for making queue assignments thread-safe * * \param proxy The proxy object to be wrapped diff --git a/src/wayland-private.h b/src/wayland-private.h index 9274f1b8..6b506584 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -213,7 +213,8 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection); void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, - uint32_t (*n_parse)(union wl_argument *arg)); + uint32_t (*n_parse)(union wl_argument *arg), + const char *queue_name); void wl_closure_destroy(struct wl_closure *closure); diff --git a/src/wayland-server.c b/src/wayland-server.c index e784ef6b..1534114b 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -157,7 +157,7 @@ log_closure(struct wl_resource *resource, struct wl_protocol_logger_message message; if (debug_server) - wl_closure_print(closure, object, send, false, NULL); + wl_closure_print(closure, object, send, false, NULL, NULL); if (!wl_list_empty(&display->protocol_loggers)) { message.resource = resource; diff --git a/tests/queue-test.c b/tests/queue-test.c index 6562139a..cb61a85b 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -471,6 +471,106 @@ client_test_queue_destroy_default_with_attached_proxies(void) free(callback); } +static void +check_queue_name(struct wl_proxy *proxy, const char *name) +{ + struct wl_event_queue *queue; + const char *queue_name; + + queue = wl_proxy_get_queue(proxy); + queue_name = wl_event_queue_get_name(queue); + if (!name) + assert(!queue_name); + else + assert(strcmp(queue_name, name) == 0); +} + +static struct wl_callback * +roundtrip_named_queue_nonblock(struct wl_display *display, + struct wl_event_queue *queue, + const char *name) +{ + struct wl_callback *callback; + struct wl_display *wrapped_display = NULL; + + if (queue) { + wrapped_display = wl_proxy_create_wrapper(display); + assert(wrapped_display); + wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue); + check_queue_name((struct wl_proxy *) wrapped_display, name); + + callback = wl_display_sync(wrapped_display); + } else + callback = wl_display_sync(display); + + check_queue_name((struct wl_proxy *) callback, name); + + if (wrapped_display) + wl_proxy_wrapper_destroy(wrapped_display); + + assert(callback != NULL); + + return callback; +} + +static void +client_test_queue_names(void) +{ + struct wl_event_queue *queue1, *queue2, *queue3; + struct wl_display *display; + struct wl_callback *callback1, *callback2, *callback3, *callback4; + struct wl_event_queue *default_queue; + char *log; + size_t log_len; + const char *default_queue_name; + + display = wl_display_connect(NULL); + assert(display); + + default_queue = wl_proxy_get_queue((struct wl_proxy *) display); + default_queue_name = wl_event_queue_get_name(default_queue); + assert(strcmp(default_queue_name, "Default Queue") == 0); + + /* Create some event queues both with and without names. */ + queue1 = wl_display_create_queue_with_name(display, "First"); + assert(queue1); + + queue2 = wl_display_create_queue_with_name(display, "Second"); + assert(queue2); + + queue3 = wl_display_create_queue(display); + assert(queue3); + + /* Create some requests and ensure their queues have the expected + * names. + */ + callback1 = roundtrip_named_queue_nonblock(display, queue1, "First"); + callback2 = roundtrip_named_queue_nonblock(display, queue2, "Second"); + callback3 = roundtrip_named_queue_nonblock(display, queue3, NULL); + callback4 = roundtrip_named_queue_nonblock(display, NULL, "Default Queue"); + + /* Destroy one queue with proxies still attached so we can verify + * that the queue name is in the log message. */ + wl_event_queue_destroy(queue2); + log = map_file(client_log_fd, &log_len); + assert(strstr(log, "Second")); + + /* There's no reason for the First queue name to be present. */ + assert(!strstr(log, "First")); + + munmap(log, log_len); + + wl_callback_destroy(callback1); + wl_callback_destroy(callback2); + wl_callback_destroy(callback3); + wl_callback_destroy(callback4); + + wl_event_queue_destroy(queue1); + wl_event_queue_destroy(queue3); + + wl_display_disconnect(display); +} + static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) @@ -597,3 +697,15 @@ TEST(queue_destroy_default_with_attached_proxies) display_destroy(d); } + +TEST(queue_names) +{ + struct display *d = display_create(); + + test_set_timeout(2); + + client_create_noarg(d, client_test_queue_names); + display_run(d); + + display_destroy(d); +}