aboutsummaryrefslogtreecommitdiff
path: root/libseat/backend/logind.c
diff options
context:
space:
mode:
authorKenny Levinsen <kl@kl.wtf>2021-09-20 23:43:11 +0200
committerKenny Levinsen <kl@kl.wtf>2021-09-21 11:18:18 +0200
commitdb08fb921f8ea13202a487dcea2fdd3914b87dfd (patch)
tree3173ceeccce6ecd5db3b51ee34a75bc6d9212323 /libseat/backend/logind.c
parent2eee9aa445e3f9dc6a7ca115489f87b10f60b9ba (diff)
logind: Send ping to wake us up later
sd_bus_call drains received messages into the receive queue, and peeks for its own return value. It does not dispatch the receive queue. As the socket is drained, the caller will not wake from a poll and have no reason to dispatch libseat. This has gone unnoticed largely due to logind sending an event for every device, making it unlikely that no unread message will be left on the socket. Like we have done for seatd, we fix this by sending a "ping" request to logind if anything is left in our receive queue as reported by sd_bus_get_events. The response to this will wake us up and ensure that dispatch is called.
Diffstat (limited to 'libseat/backend/logind.c')
-rw-r--r--libseat/backend/logind.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c
index cb809e7..dd050ce 100644
--- a/libseat/backend/logind.c
+++ b/libseat/backend/logind.c
@@ -41,6 +41,7 @@ struct backend_logind {
bool active;
bool initial_setup;
+ bool awaiting_pong;
int has_drm;
};
@@ -67,6 +68,48 @@ static int close_seat(struct libseat *base) {
return 0;
}
+static int ping_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ (void)ret_error;
+ struct backend_logind *session = userdata;
+ if (sd_bus_message_is_method_error(m, NULL)) {
+ const sd_bus_error *error = sd_bus_message_get_error(m);
+ log_errorf("Ping failed: %s: %s", error->name, error->message);
+ return -1;
+ }
+ session->awaiting_pong = false;
+ return 0;
+}
+
+static int send_ping(struct backend_logind *backend) {
+ int ret = sd_bus_call_method_async(backend->bus, NULL, "org.freedesktop.login1",
+ "/org/freedesktop/login1", "org.freedesktop.DBus.Peer",
+ "Ping", ping_handler, NULL, "");
+ if (ret < 0) {
+ return ret;
+ }
+ return 0;
+}
+
+static void check_pending_events(struct backend_logind *backend) {
+ if (sd_bus_get_events(backend->bus) <= 0) {
+ 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 logind so that the
+ // user will be woken up by its response.
+ int ret = send_ping(backend);
+ if (ret < 0) {
+ log_errorf("Could not send ping message: %s", strerror(-ret));
+ return;
+ }
+ backend->awaiting_pong = true;
+}
+
static int open_device(struct libseat *base, const char *path, int *fd) {
struct backend_logind *session = backend_logind_from_libseat_backend(base);
@@ -113,9 +156,11 @@ static int open_device(struct libseat *base, const char *path, int *fd) {
}
*fd = tmpfd;
+
out:
sd_bus_error_free(&error);
sd_bus_message_unref(msg);
+ check_pending_events(session);
return tmpfd;
}
@@ -150,7 +195,7 @@ static int close_device(struct libseat *base, int device_id) {
sd_bus_error_free(&error);
sd_bus_message_unref(msg);
-
+ check_pending_events(session);
return ret < 0 ? -1 : 0;
}
@@ -173,6 +218,7 @@ static int switch_session(struct libseat *base, int s) {
sd_bus_error_free(&error);
sd_bus_message_unref(msg);
+ check_pending_events(session);
return ret < 0 ? -1 : 0;
}