seatd: cleaning up

This commit is contained in:
Tim Biermann 2022-05-27 14:04:15 +02:00
parent 0cc0732c62
commit dd1ba6bd8b

View File

@ -1,186 +0,0 @@
From 2eee9aa445e3f9dc6a7ca115489f87b10f60b9ba Mon Sep 17 00:00:00 2001
From: Kenny Levinsen <kl@kl.wtf>
Date: Mon, 20 Sep 2021 23:43:10 +0200
Subject: [PATCH] seatd: Implement ping request to wake up later
When device open or close messages are sent to seatd, libseat must read
messages from the socket until it sees the associated response message.
This means that it may drain enable/disable seat events from the socket,
queueing them internally for deferred processing.
As the socket is drained, the caller will not wake from a poll and have
no reason to dispatch libseat. To ensure that these messages would not
be left in the queue, 6fa82930d0c5660eea3102989c765dc864514e36 made it
so that open/close calls would execute all queued events just before
returning.
Unfortunately, this had the side-effect of having events fire from the
stack of libseat_open_device or libseat_close_device, which we now see
cause problems in compositors. Specifically, an issue has been observed
where libinput end up calling libseat_close_device, which in turn
dispatch a disable seat event that calls libinput_suspend. libinput does
not like this.
Instead, remove the execution from libseat_open_device and
libseat_close_device, and instead make a "ping" request to seatd if
events have been queued. The response to this will wake us up and ensure
that dispatch is called.
---
include/protocol.h | 2 ++
libseat/backend/seatd.c | 45 +++++++++++++++++++++++++++++++++++++----
seatd/client.c | 22 ++++++++++++++++++++
3 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/include/protocol.h b/include/protocol.h
index b3361ba..cb994fc 100644
--- a/include/protocol.h
+++ b/include/protocol.h
@@ -15,6 +15,7 @@
#define CLIENT_CLOSE_DEVICE CLIENT_EVENT(4)
#define CLIENT_DISABLE_SEAT CLIENT_EVENT(5)
#define CLIENT_SWITCH_SESSION CLIENT_EVENT(6)
+#define CLIENT_PING CLIENT_EVENT(7)
#define SERVER_SEAT_OPENED SERVER_EVENT(1)
#define SERVER_SEAT_CLOSED SERVER_EVENT(2)
@@ -22,6 +23,7 @@
#define SERVER_DEVICE_CLOSED SERVER_EVENT(4)
#define SERVER_DISABLE_SEAT SERVER_EVENT(5)
#define SERVER_ENABLE_SEAT SERVER_EVENT(6)
+#define SERVER_PONG SERVER_EVENT(7)
#define SERVER_ERROR SERVER_EVENT(0x7FFF)
#include <stdint.h>
diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c
index 85df9f5..26308d1 100644
--- a/libseat/backend/seatd.c
+++ b/libseat/backend/seatd.c
@@ -36,6 +36,7 @@ struct backend_seatd {
const struct libseat_seat_listener *seat_listener;
void *seat_listener_data;
struct linked_list pending_events;
+ bool awaiting_pong;
bool error;
char seat_name[MAX_SEAT_LEN];
@@ -243,6 +244,12 @@ static int dispatch_pending(struct backend_seatd *backend, int *opcode) {
while (connection_get(&backend->connection, &header, sizeof header) != -1) {
packets++;
switch (header.opcode) {
+ case SERVER_PONG:
+ // We care about whether or not the answer has been
+ // read from the connection, so handle it here instead
+ // of pushing it to the pending event list.
+ backend->awaiting_pong = false;
+ break;
case SERVER_DISABLE_SEAT:
case SERVER_ENABLE_SEAT:
if (queue_event(backend, header.opcode) == -1) {
@@ -450,6 +457,36 @@ static const char *seat_name(struct libseat *base) {
return backend->seat_name;
}
+static int send_ping(struct backend_seatd *backend) {
+ struct proto_header header = {
+ .opcode = CLIENT_PING,
+ .size = 0,
+ };
+ if (conn_put(backend, &header, sizeof header) == -1 || conn_flush(backend) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+static void check_pending_events(struct backend_seatd *backend) {
+ if (linked_list_empty(&backend->pending_events)) {
+ return;
+ }
+ if (backend->awaiting_pong) {
+ return;
+ }
+
+ // We have events pending execution, so a dispatch is required.
+ // However, we likely already drained our socket, so there will not be
+ // anything to read. Instead, send a ping request to seatd, so that the
+ // user will be woken up by its response.
+ if (send_ping(backend) == -1) {
+ log_errorf("Could not send ping request: %s", strerror(errno));
+ return;
+ }
+ backend->awaiting_pong = true;
+}
+
static int open_device(struct libseat *base, const char *path, int *fd) {
struct backend_seatd *backend = backend_seatd_from_libseat_backend(base);
if (backend->error) {
@@ -481,11 +518,11 @@ static int open_device(struct libseat *base, const char *path, int *fd) {
goto error;
}
- execute_events(backend);
+ check_pending_events(backend);
return rmsg.device_id;
error:
- execute_events(backend);
+ check_pending_events(backend);
return -1;
}
@@ -516,11 +553,11 @@ static int close_device(struct libseat *base, int device_id) {
goto error;
}
- execute_events(backend);
+ check_pending_events(backend);
return 0;
error:
- execute_events(backend);
+ check_pending_events(backend);
return -1;
}
diff --git a/seatd/client.c b/seatd/client.c
index 1bfe94a..220c5d3 100644
--- a/seatd/client.c
+++ b/seatd/client.c
@@ -309,6 +309,20 @@ error:
return client_send_error(client, errno);
}
+static int handle_ping(struct client *client) {
+ struct proto_header header = {
+ .opcode = SERVER_PONG,
+ .size = 0,
+ };
+
+ if (connection_put(&client->connection, &header, sizeof header) == -1) {
+ log_errorf("Could not write response: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
static int client_handle_opcode(struct client *client, uint16_t opcode, size_t size) {
int res = 0;
switch (opcode) {
@@ -372,6 +386,14 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s
res = handle_disable_seat(client);
break;
}
+ case CLIENT_PING: {
+ if (size != 0) {
+ log_error("Protocol error: invalid ping message");
+ return -1;
+ }
+ res = handle_ping(client);
+ break;
+ }
default:
log_errorf("Protocol error: unknown opcode: %d", opcode);
res = -1;
--
2.32.0