[systemd-devel] [PATCH] logind: implement generic multi-session

Lennart Poettering lennart at poettering.net
Tue Sep 17 15:16:03 PDT 2013


On Tue, 17.09.13 23:40, David Herrmann (dh.herrmann at gmail.com) wrote:

Applied both! Thanks a lot!

> 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.
> ---
>  src/login/logind-seat.c           | 15 +++++++++++++++
>  src/login/logind-seat.h           |  2 ++
>  src/login/logind-session-device.c | 28 ++++++++++++++++++++++++++++
>  src/login/logind-session-device.h |  1 +
>  src/login/logind-session.c        | 31 ++++++++++++++++++++++++++-----
>  5 files changed, 72 insertions(+), 5 deletions(-)
> 
> diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
> index f88738a..4a4d40a 100644
> --- a/src/login/logind-seat.c
> +++ b/src/login/logind-seat.c
> @@ -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);
>  
> diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h
> index d3438b8..be6db6e 100644
> --- a/src/login/logind-seat.h
> +++ b/src/login/logind-seat.h
> @@ -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);
> diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c
> index 80fd364..e92bb54 100644
> --- a/src/login/logind-session-device.c
> +++ b/src/login/logind-session-device.c
> @@ -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;
> +}
> diff --git a/src/login/logind-session-device.h b/src/login/logind-session-device.h
> index 511fce0..eac7ca7 100644
> --- a/src/login/logind-session-device.h
> +++ b/src/login/logind-session-device.h
> @@ -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);
> diff --git a/src/login/logind-session.c b/src/login/logind-session.c
> index fcc1901..eea0bfb 100644
> --- a/src/login/logind-session.c
> +++ b/src/login/logind-session.c
> @@ -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) {


Lennart

-- 
Lennart Poettering - Red Hat, Inc.


More information about the systemd-devel mailing list