You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
327 lines
9.6 KiB
327 lines
9.6 KiB
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Lloyd Pique <lpique@google.com>
|
|
Date: Fri, 29 Jan 2021 14:26:03 -0800
|
|
Subject: [PATCH 1/3] client: Support client protocol loggers
|
|
|
|
This is very much based on commit 450f06e2 which added server protocol
|
|
loggers.
|
|
|
|
Adds a new pair of public API functions:
|
|
|
|
* wl_display_add_protocol_logger_client allows the client to register a
|
|
function to be called to log each message that is sent or received.
|
|
|
|
* wl_protocol_logger_client_destroy allows the client to unregister the
|
|
function.
|
|
|
|
As with the server protocol loggers, this is akin to setting
|
|
WAYLAND_DEBUG=1, but allows the client code to choose how the messages
|
|
are logged, and it can also enable and disable logging at run time.
|
|
|
|
The logging logic for the client was also changed to log all events, not
|
|
just the ones that have listeners or dispatchers.
|
|
|
|
Signed-off-by: Lloyd Pique <lpique@google.com>
|
|
|
|
diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
|
|
index 0cd96e0..547ae04 100644
|
|
--- a/src/wayland-client-core.h
|
|
+++ b/src/wayland-client-core.h
|
|
@@ -267,6 +267,32 @@ wl_display_read_events(struct wl_display *display);
|
|
void
|
|
wl_log_set_handler_client(wl_log_func_t handler);
|
|
|
|
+enum wl_protocol_logger_client_type {
|
|
+ WL_PROTOCOL_LOGGER_CLIENT_REQUEST,
|
|
+ WL_PROTOCOL_LOGGER_CLIENT_EVENT,
|
|
+};
|
|
+
|
|
+struct wl_protocol_logger_client_message {
|
|
+ struct wl_proxy *proxy;
|
|
+ int message_opcode;
|
|
+ const struct wl_message *message;
|
|
+ int arguments_count;
|
|
+ const union wl_argument *arguments;
|
|
+};
|
|
+
|
|
+typedef void (*wl_protocol_logger_client_func_t)(
|
|
+ void *user_data,
|
|
+ enum wl_protocol_logger_client_type direction,
|
|
+ const struct wl_protocol_logger_client_message *message);
|
|
+
|
|
+struct wl_protocol_logger_client *
|
|
+wl_display_add_protocol_logger_client(struct wl_display *display,
|
|
+ wl_protocol_logger_client_func_t,
|
|
+ void *user_data);
|
|
+
|
|
+void
|
|
+wl_protocol_logger_client_destroy(struct wl_protocol_logger_client *logger);
|
|
+
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
diff --git a/src/wayland-client.c b/src/wayland-client.c
|
|
index 21d4606..7f5a651 100644
|
|
--- a/src/wayland-client.c
|
|
+++ b/src/wayland-client.c
|
|
@@ -107,12 +107,47 @@ struct wl_display {
|
|
int reader_count;
|
|
uint32_t read_serial;
|
|
pthread_cond_t reader_cond;
|
|
+
|
|
+ struct wl_list protocol_loggers;
|
|
};
|
|
|
|
/** \endcond */
|
|
|
|
+struct wl_protocol_logger_client {
|
|
+ struct wl_list link;
|
|
+ wl_protocol_logger_client_func_t func;
|
|
+ void *user_data;
|
|
+};
|
|
+
|
|
static int debug_client = 0;
|
|
|
|
+static void
|
|
+log_closure(struct wl_closure *closure, struct wl_proxy* proxy, int send)
|
|
+{
|
|
+ struct wl_display *display = proxy->display;
|
|
+ struct wl_protocol_logger_client *protocol_logger;
|
|
+ struct wl_protocol_logger_client_message message;
|
|
+
|
|
+ if (debug_client)
|
|
+ wl_closure_print(closure, &proxy->object, send);
|
|
+
|
|
+ if (!wl_list_empty(&display->protocol_loggers)) {
|
|
+ message.proxy = proxy;
|
|
+ message.message_opcode = closure->opcode;
|
|
+ message.message = closure->message;
|
|
+ message.arguments_count = closure->count;
|
|
+ message.arguments = closure->args;
|
|
+ wl_list_for_each(protocol_logger, &display->protocol_loggers,
|
|
+ link) {
|
|
+ protocol_logger->func(
|
|
+ protocol_logger->user_data,
|
|
+ send ? WL_PROTOCOL_LOGGER_CLIENT_REQUEST :
|
|
+ WL_PROTOCOL_LOGGER_CLIENT_EVENT,
|
|
+ &message);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* This helper function wakes up all threads that are
|
|
* waiting for display->reader_cond (i. e. when reading is done,
|
|
@@ -751,8 +786,7 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
|
|
goto err_unlock;
|
|
}
|
|
|
|
- if (debug_client)
|
|
- wl_closure_print(closure, &proxy->object, true);
|
|
+ log_closure(closure, proxy, true);
|
|
|
|
if (wl_closure_send(closure, proxy->display->connection)) {
|
|
wl_log("Error sending request: %s\n", strerror(errno));
|
|
@@ -1056,6 +1090,7 @@ wl_display_connect_to_fd(int fd)
|
|
pthread_mutex_init(&display->mutex, NULL);
|
|
pthread_cond_init(&display->reader_cond, NULL);
|
|
display->reader_count = 0;
|
|
+ wl_list_init(&display->protocol_loggers);
|
|
|
|
wl_map_insert_new(&display->objects, 0, NULL);
|
|
|
|
@@ -1177,6 +1212,7 @@ wl_display_disconnect(struct wl_display *display)
|
|
wl_map_release(&display->objects);
|
|
wl_event_queue_release(&display->default_queue);
|
|
wl_event_queue_release(&display->display_queue);
|
|
+ wl_list_remove(&display->protocol_loggers);
|
|
pthread_mutex_destroy(&display->mutex);
|
|
pthread_cond_destroy(&display->reader_cond);
|
|
close(display->fd);
|
|
@@ -1439,16 +1475,12 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
|
|
|
|
pthread_mutex_unlock(&display->mutex);
|
|
|
|
- if (proxy->dispatcher) {
|
|
- if (debug_client)
|
|
- wl_closure_print(closure, &proxy->object, false);
|
|
+ log_closure(closure, proxy, false);
|
|
|
|
+ if (proxy->dispatcher) {
|
|
wl_closure_dispatch(closure, proxy->dispatcher,
|
|
&proxy->object, opcode);
|
|
} else if (proxy->object.implementation) {
|
|
- if (debug_client)
|
|
- wl_closure_print(closure, &proxy->object, false);
|
|
-
|
|
wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
|
|
&proxy->object, opcode, proxy->user_data);
|
|
}
|
|
@@ -2280,3 +2312,60 @@ wl_log_set_handler_client(wl_log_func_t handler)
|
|
{
|
|
wl_log_handler = handler;
|
|
}
|
|
+
|
|
+/** Adds a new protocol client logger.
|
|
+ *
|
|
+ * When a new protocol message arrives or is sent from the client
|
|
+ * all the protocol logger functions will be called, carrying the
|
|
+ * \a user_data pointer, the type of the message (request or
|
|
+ * event) and the actual message.
|
|
+ * The lifetime of the messages passed to the logger function ends
|
|
+ * when they return so the messages cannot be stored and accessed
|
|
+ * later.
|
|
+ *
|
|
+ * \a errno is set on error.
|
|
+ *
|
|
+ * \param display The display object
|
|
+ * \param func The function to call to log a new protocol message
|
|
+ * \param user_data The user data pointer to pass to \a func
|
|
+ *
|
|
+ * \return The protocol logger object on success, NULL on failure.
|
|
+ *
|
|
+ * \sa wl_protocol_logger_client_destroy
|
|
+ *
|
|
+ * \memberof wl_display
|
|
+ */
|
|
+WL_EXPORT struct wl_protocol_logger_client *
|
|
+wl_display_add_protocol_logger_client(struct wl_display *display,
|
|
+ wl_protocol_logger_client_func_t func,
|
|
+ void *user_data)
|
|
+{
|
|
+ struct wl_protocol_logger_client *logger;
|
|
+
|
|
+ logger = malloc(sizeof *logger);
|
|
+ if (!logger)
|
|
+ return NULL;
|
|
+
|
|
+ logger->func = func;
|
|
+ logger->user_data = user_data;
|
|
+ wl_list_insert(&display->protocol_loggers, &logger->link);
|
|
+
|
|
+ return logger;
|
|
+}
|
|
+
|
|
+/** Destroys a protocol client logger.
|
|
+ *
|
|
+ * This function destroys a protocol client logger and removes it from the
|
|
+ * display it was added to with \a wl_display_add_protocol_logger_client.
|
|
+ * The \a logger object becomes invalid after calling this function.
|
|
+ *
|
|
+ * \sa wl_display_add_protocol_logger_client
|
|
+ *
|
|
+ * \memberof wl_protocol_logger_client
|
|
+ */
|
|
+WL_EXPORT void
|
|
+wl_protocol_logger_client_destroy(struct wl_protocol_logger_client *logger)
|
|
+{
|
|
+ wl_list_remove(&logger->link);
|
|
+ free(logger);
|
|
+}
|
|
diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c
|
|
index 80c74aa..e409368 100644
|
|
--- a/tests/protocol-logger-test.c
|
|
+++ b/tests/protocol-logger-test.c
|
|
@@ -52,6 +52,12 @@ struct compositor {
|
|
struct wl_client *client;
|
|
};
|
|
|
|
+struct client {
|
|
+ struct wl_display *display;
|
|
+ struct wl_callback *cb;
|
|
+ int message;
|
|
+};
|
|
+
|
|
struct message {
|
|
enum wl_protocol_logger_type type;
|
|
const char *class;
|
|
@@ -82,6 +88,36 @@ struct message {
|
|
},
|
|
};
|
|
|
|
+struct client_message {
|
|
+ enum wl_protocol_logger_client_type type;
|
|
+ const char *class;
|
|
+ int opcode;
|
|
+ const char *message_name;
|
|
+ int args_count;
|
|
+} client_messages[] = {
|
|
+ {
|
|
+ .type = WL_PROTOCOL_LOGGER_CLIENT_REQUEST,
|
|
+ .class = "wl_display",
|
|
+ .opcode = 0,
|
|
+ .message_name = "sync",
|
|
+ .args_count = 1,
|
|
+ },
|
|
+ {
|
|
+ .type = WL_PROTOCOL_LOGGER_CLIENT_EVENT,
|
|
+ .class = "wl_display",
|
|
+ .opcode = 1,
|
|
+ .message_name = "delete_id",
|
|
+ .args_count = 1,
|
|
+ },
|
|
+ {
|
|
+ .type = WL_PROTOCOL_LOGGER_CLIENT_EVENT,
|
|
+ .class = "wl_callback",
|
|
+ .opcode = 0,
|
|
+ .message_name = "done",
|
|
+ .args_count = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
static void
|
|
logger_func(void *user_data, enum wl_protocol_logger_type type,
|
|
const struct wl_protocol_logger_message *message)
|
|
@@ -98,6 +134,20 @@ logger_func(void *user_data, enum wl_protocol_logger_type type,
|
|
c->client = wl_resource_get_client(message->resource);
|
|
}
|
|
|
|
+static void
|
|
+client_logger_func(void *user_data, enum wl_protocol_logger_client_type type,
|
|
+ const struct wl_protocol_logger_client_message *message)
|
|
+{
|
|
+ struct client *c = user_data;
|
|
+ struct client_message *msg = &client_messages[c->message++];
|
|
+
|
|
+ assert(msg->type == type);
|
|
+ assert(strcmp(msg->class, wl_proxy_get_class(message->proxy)) == 0);
|
|
+ assert(msg->opcode == message->message_opcode);
|
|
+ assert(strcmp(msg->message_name, message->message->name) == 0);
|
|
+ assert(msg->args_count == message->arguments_count);
|
|
+}
|
|
+
|
|
static void
|
|
callback_done(void *data, struct wl_callback *cb, uint32_t time)
|
|
{
|
|
@@ -114,11 +164,9 @@ TEST(logger)
|
|
|
|
const char *socket;
|
|
struct compositor compositor = { 0 };
|
|
- struct {
|
|
- struct wl_display *display;
|
|
- struct wl_callback *cb;
|
|
- } client;
|
|
+ struct client client = { 0 };
|
|
struct wl_protocol_logger *logger;
|
|
+ struct wl_protocol_logger_client *logger_client;
|
|
|
|
require_xdg_runtime_dir();
|
|
|
|
@@ -130,6 +178,8 @@ TEST(logger)
|
|
logger_func, &compositor);
|
|
|
|
client.display = wl_display_connect(socket);
|
|
+ logger_client = wl_display_add_protocol_logger_client(
|
|
+ client.display, client_logger_func, &client);
|
|
client.cb = wl_display_sync(client.display);
|
|
wl_callback_add_listener(client.cb, &callback_listener, NULL);
|
|
wl_display_flush(client.display);
|
|
@@ -142,6 +192,7 @@ TEST(logger)
|
|
wl_display_dispatch(client.display);
|
|
wl_display_disconnect(client.display);
|
|
|
|
+ wl_protocol_logger_client_destroy(logger_client);
|
|
wl_client_destroy(compositor.client);
|
|
wl_protocol_logger_destroy(logger);
|
|
wl_display_destroy(compositor.display);
|