89 lines
3.7 KiB
Diff
89 lines
3.7 KiB
Diff
|
From 2ec3ff668ff03410e94cfef8e3ee9384a8222211 Mon Sep 17 00:00:00 2001
|
||
|
From: David Herrmann <dh.herrmann@gmail.com>
|
||
|
Date: Fri, 19 Sep 2014 13:26:39 +0200
|
||
|
Subject: [PATCH] login: pause devices before acknowledging VT switches
|
||
|
|
||
|
If a session controller does not need synchronous VT switches, we allow
|
||
|
them to pass VT control to logind, which acknowledges all VT switches
|
||
|
unconditionally. This works fine with all sessions using the dbus API,
|
||
|
but causes out-of-sync device use if we switch to legacy sessions that
|
||
|
are notified via VT signals. Those are processed before logind notices
|
||
|
the session-switch via sysfs. Therefore, leaving the old session still
|
||
|
active for a short amount of time.
|
||
|
|
||
|
This, in fact, may cause the legacy session to prepare graphics devices
|
||
|
before the old session was deactivated, and thus, maybe causing the old
|
||
|
session to interfer with graphics device usage.
|
||
|
|
||
|
Fix this by releasing devices immediately before acknowledging VT
|
||
|
switches. This way, sessions without VT handlers are required to support
|
||
|
async session switching (which they do in that case, anyway).
|
||
|
---
|
||
|
src/login/logind-session.c | 21 +++++++++++++++++++++
|
||
|
src/login/logind-session.h | 1 +
|
||
|
src/login/logind.c | 4 ++--
|
||
|
3 files changed, 24 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
|
||
|
index eeb58c9031..477ac9ab1b 100644
|
||
|
--- a/src/login/logind-session.c
|
||
|
+++ b/src/login/logind-session.c
|
||
|
@@ -1053,6 +1053,27 @@ void session_restore_vt(Session *s) {
|
||
|
s->vtfd = safe_close(s->vtfd);
|
||
|
}
|
||
|
|
||
|
+void session_leave_vt(Session *s) {
|
||
|
+ assert(s);
|
||
|
+
|
||
|
+ /* This is called whenever we get a VT-switch signal from the kernel.
|
||
|
+ * We acknowledge all of them unconditionally. Note that session are
|
||
|
+ * free to overwrite those handlers and we only register them for
|
||
|
+ * sessions with controllers. Legacy sessions are not affected.
|
||
|
+ * However, if we switch from a non-legacy to a legacy session, we must
|
||
|
+ * make sure to pause all device before acknowledging the switch. We
|
||
|
+ * process the real switch only after we are notified via sysfs, so the
|
||
|
+ * legacy session might have already started using the devices. If we
|
||
|
+ * don't pause the devices before the switch, we might confuse the
|
||
|
+ * session we switch to. */
|
||
|
+
|
||
|
+ if (s->vtfd < 0)
|
||
|
+ return;
|
||
|
+
|
||
|
+ session_device_pause_all(s);
|
||
|
+ ioctl(s->vtfd, VT_RELDISP, 1);
|
||
|
+}
|
||
|
+
|
||
|
bool session_is_controller(Session *s, const char *sender) {
|
||
|
assert(s);
|
||
|
|
||
|
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
|
||
|
index 9fb0188a84..a007fb5e84 100644
|
||
|
--- a/src/login/logind-session.h
|
||
|
+++ b/src/login/logind-session.h
|
||
|
@@ -174,6 +174,7 @@ KillWho kill_who_from_string(const char *s) _pure_;
|
||
|
|
||
|
int session_prepare_vt(Session *s);
|
||
|
void session_restore_vt(Session *s);
|
||
|
+void session_leave_vt(Session *s);
|
||
|
|
||
|
bool session_is_controller(Session *s, const char *sender);
|
||
|
int session_set_controller(Session *s, const char *sender, bool force);
|
||
|
diff --git a/src/login/logind.c b/src/login/logind.c
|
||
|
index f1b6a86298..8f00c46339 100644
|
||
|
--- a/src/login/logind.c
|
||
|
+++ b/src/login/logind.c
|
||
|
@@ -750,11 +750,11 @@ static int manager_vt_switch(sd_event_source *src, const struct signalfd_siginfo
|
||
|
}
|
||
|
|
||
|
if (active->vtfd >= 0) {
|
||
|
- ioctl(active->vtfd, VT_RELDISP, 1);
|
||
|
+ session_leave_vt(active);
|
||
|
} else {
|
||
|
LIST_FOREACH(sessions_by_seat, iter, m->seat0->sessions) {
|
||
|
if (iter->vtnr == active->vtnr && iter->vtfd >= 0) {
|
||
|
- ioctl(iter->vtfd, VT_RELDISP, 1);
|
||
|
+ session_leave_vt(iter);
|
||
|
break;
|
||
|
}
|
||
|
}
|