mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-08 05:57:26 +03:00
logind: implement generic multi-session
This enables the multi-session capability for seats that don't have VTs. For legacy seats with VTs, everything stays the same. However, all other seats now also get the multi-session capability. The only feature that was missing was session-switching. As logind can force a session-switch and signal that via the "Active" property, we only need a way to allow synchronized/delayed session switches. Compositors need to cleanup some devices before acknowledging the session switch. Therefore, we use the session-devices to give compositors a chance to block a session-switch until they cleaned everything up. If you activate a session on a seat without VTs, we send a PauseDevice signal to the active session for every active device. Only once the session acknowledged all these with a PauseDeviceComplete() call, we perform the final session switch. One important note is that delayed session-switching is meant for backwards compatibility. New compositors or other sessions should really try to deal correctly with forced session switches! They only need to handle EACCES/EPERM from syscalls and treat them as "PauseDevice" signal. Following logind patches will add a timeout to session-switches which forces the switch if the active session does not react in a timely fashion. Moreover, explicit ForceActivate() calls might also be supported. Hence, sessions must not crash if their devices get paused.
This commit is contained in:
parent
118ecf3242
commit
d7bd01b547
@ -425,6 +425,21 @@ int seat_attach_session(Seat *s, Session *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void seat_complete_switch(Seat *s) {
|
||||
Session *session;
|
||||
|
||||
assert(s);
|
||||
|
||||
/* if no session-switch is pending or if it got canceled, do nothing */
|
||||
if (!s->pending_switch)
|
||||
return;
|
||||
|
||||
session = s->pending_switch;
|
||||
s->pending_switch = NULL;
|
||||
|
||||
seat_set_active(s, session);
|
||||
}
|
||||
|
||||
bool seat_has_vts(Seat *s) {
|
||||
assert(s);
|
||||
|
||||
|
@ -38,6 +38,7 @@ struct Seat {
|
||||
LIST_HEAD(Device, devices);
|
||||
|
||||
Session *active;
|
||||
Session *pending_switch;
|
||||
LIST_HEAD(Session, sessions);
|
||||
|
||||
bool in_gc_queue:1;
|
||||
@ -59,6 +60,7 @@ int seat_read_active_vt(Seat *s);
|
||||
int seat_preallocate_vts(Seat *s);
|
||||
|
||||
int seat_attach_session(Seat *s, Session *session);
|
||||
void seat_complete_switch(Seat *s);
|
||||
|
||||
bool seat_has_vts(Seat *s);
|
||||
bool seat_is_seat0(Seat *s);
|
||||
|
@ -414,10 +414,21 @@ void session_device_free(SessionDevice *sd) {
|
||||
}
|
||||
|
||||
void session_device_complete_pause(SessionDevice *sd) {
|
||||
SessionDevice *iter;
|
||||
Iterator i;
|
||||
|
||||
if (!sd->active)
|
||||
return;
|
||||
|
||||
session_device_stop(sd);
|
||||
|
||||
/* if not all devices are paused, wait for further completion events */
|
||||
HASHMAP_FOREACH(iter, sd->session->devices, i)
|
||||
if (iter->active)
|
||||
return;
|
||||
|
||||
/* complete any pending session switch */
|
||||
seat_complete_switch(sd->session->seat);
|
||||
}
|
||||
|
||||
void session_device_resume_all(Session *s) {
|
||||
@ -449,3 +460,20 @@ void session_device_pause_all(Session *s) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int session_device_try_pause_all(Session *s) {
|
||||
SessionDevice *sd;
|
||||
Iterator i;
|
||||
unsigned int num_pending = 0;
|
||||
|
||||
assert(s);
|
||||
|
||||
HASHMAP_FOREACH(sd, s->devices, i) {
|
||||
if (sd->active) {
|
||||
session_device_notify(sd, SESSION_DEVICE_TRY_PAUSE);
|
||||
++num_pending;
|
||||
}
|
||||
}
|
||||
|
||||
return num_pending;
|
||||
}
|
||||
|
@ -57,3 +57,4 @@ void session_device_complete_pause(SessionDevice *sd);
|
||||
|
||||
void session_device_resume_all(Session *s);
|
||||
void session_device_pause_all(Session *s);
|
||||
unsigned int session_device_try_pause_all(Session *s);
|
||||
|
@ -100,6 +100,8 @@ void session_free(Session *s) {
|
||||
if (s->seat) {
|
||||
if (s->seat->active == s)
|
||||
s->seat->active = NULL;
|
||||
if (s->seat->pending_switch == s)
|
||||
s->seat->pending_switch = NULL;
|
||||
|
||||
LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
|
||||
}
|
||||
@ -375,21 +377,40 @@ int session_load(Session *s) {
|
||||
}
|
||||
|
||||
int session_activate(Session *s) {
|
||||
unsigned int num_pending;
|
||||
|
||||
assert(s);
|
||||
assert(s->user);
|
||||
|
||||
if (s->vtnr <= 0)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (!s->seat)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (s->seat->active == s)
|
||||
return 0;
|
||||
|
||||
assert(seat_has_vts(s->seat));
|
||||
/* on seats with VTs, we let VTs manage session-switching */
|
||||
if (seat_has_vts(s->seat)) {
|
||||
if (s->vtnr <= 0)
|
||||
return -ENOTSUP;
|
||||
|
||||
return chvt(s->vtnr);
|
||||
return chvt(s->vtnr);
|
||||
}
|
||||
|
||||
/* On seats without VTs, we implement session-switching in logind. We
|
||||
* try to pause all session-devices and wait until the session
|
||||
* controller acknowledged them. Once all devices are asleep, we simply
|
||||
* switch the active session and be done.
|
||||
* We save the session we want to switch to in seat->pending_switch and
|
||||
* seat_complete_switch() will perform the final switch. */
|
||||
|
||||
s->seat->pending_switch = s;
|
||||
|
||||
/* if no devices are running, immediately perform the session switch */
|
||||
num_pending = session_device_try_pause_all(s);
|
||||
if (!num_pending)
|
||||
seat_complete_switch(s->seat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_link_x11_socket(Session *s) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user