diff options
author | David Herrmann <dh.herrmann@googlemail.com> | 2012-11-05 14:18:41 +0100 |
---|---|---|
committer | David Herrmann <dh.herrmann@googlemail.com> | 2012-11-05 14:18:41 +0100 |
commit | e7c8e7b5312dd8e05991ae9a7301f5749bf259c7 (patch) | |
tree | 06f01e5853bd26f2adb964453872837836aaafe4 /src | |
parent | 68af0640404334d71992e3366f4e9b2fec09c65a (diff) |
uterm: vt: allow VT-deactivation to fail
If we dispatch VT-deactivation to child-processes, we might allow them to
abort the VT-switch, so the upper layer (uterm_vt) must also allow us to
abort the VT-switch.
During shutdown, we need to force the deactivation to guarantee that a VT
is inactive during shutdown.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/kmscon_seat.c | 5 | ||||
-rw-r--r-- | src/uterm.h | 11 | ||||
-rw-r--r-- | src/uterm_vt.c | 85 |
3 files changed, 70 insertions, 31 deletions
diff --git a/src/kmscon_seat.c b/src/kmscon_seat.c index 1d5c302..117b7e9 100644 --- a/src/kmscon_seat.c +++ b/src/kmscon_seat.c @@ -281,13 +281,14 @@ static void seat_remove_display(struct kmscon_seat *seat, free(d); } -static int seat_vt_event(struct uterm_vt *vt, unsigned int event, void *data) +static int seat_vt_event(struct uterm_vt *vt, struct uterm_vt_event *ev, + void *data) { struct kmscon_seat *seat = data; struct shl_dlist *iter; struct kmscon_display *d; - switch (event) { + switch (ev->action) { case UTERM_VT_ACTIVATE: seat->awake = true; if (seat->cb) diff --git a/src/uterm.h b/src/uterm.h index 9f6c909..9209357 100644 --- a/src/uterm.h +++ b/src/uterm.h @@ -352,12 +352,21 @@ enum uterm_vt_action { UTERM_VT_DEACTIVATE, }; +enum uterm_vt_flags { + UTERM_VT_FORCE = 0x01, +}; + +struct uterm_vt_event { + unsigned int action; + unsigned int flags; +}; + enum uterm_vt_mode { UTERM_VT_REAL, UTERM_VT_FAKE, }; -typedef int (*uterm_vt_cb) (struct uterm_vt *vt, unsigned int action, +typedef int (*uterm_vt_cb) (struct uterm_vt *vt, struct uterm_vt_event *ev, void *data); int uterm_vt_master_new(struct uterm_vt_master **out, diff --git a/src/uterm_vt.c b/src/uterm_vt.c index db3591d..63bb5d6 100644 --- a/src/uterm_vt.c +++ b/src/uterm_vt.c @@ -80,34 +80,59 @@ struct uterm_vt_master { struct shl_dlist vts; }; -static void vt_call(struct uterm_vt *vt, unsigned int event) +static int vt_call(struct uterm_vt *vt, unsigned int event, bool force) { int ret; + struct uterm_vt_event ev; + + memset(&ev, 0, sizeof(ev)); + ev.action = event; + if (force) + ev.flags |= UTERM_VT_FORCE; switch (event) { case UTERM_VT_ACTIVATE: - if (!vt->active) { - if (vt->cb) { - ret = vt->cb(vt, event, vt->data); - if (ret) - log_warning("vt event handler returned %d instead of 0 on activation", - ret); - } - vt->active = true; - } + if (vt->active) + return 0; + if (!vt->cb) + break; + + ret = vt->cb(vt, &ev, vt->data); + if (ret) + log_warning("vt event handler returned %d instead of 0 on activation", + ret); break; case UTERM_VT_DEACTIVATE: - if (vt->active) { - if (vt->cb) { - ret = vt->cb(vt, event, vt->data); - if (ret) - log_warning("vt event handler returned %d instead of 0 on deactivation", - ret); - } - vt->active = false; + if (!vt->active) + return 0; + if (!vt->cb) + break; + + ret = vt->cb(vt, &ev, vt->data); + if (ret) { + if (force) + log_warning("vt event handler returned %d instead of 0 on forced deactivation", + ret); + else + return ret; } break; + default: + return -EINVAL; } + + vt->active = !vt->active; + return 0; +} + +static void vt_call_activate(struct uterm_vt *vt) +{ + vt_call(vt, UTERM_VT_ACTIVATE, false); +} + +static int vt_call_deactivate(struct uterm_vt *vt, bool force) +{ + return vt_call(vt, UTERM_VT_DEACTIVATE, force); } /* @@ -147,7 +172,7 @@ static void real_delayed(struct ev_eloop *eloop, void *unused, void *data) log_debug("enter VT %d %p during startup", vt->real_num, vt); vt->real_delayed = false; ev_eloop_unregister_idle_cb(eloop, real_delayed, vt); - vt_call(vt, UTERM_VT_ACTIVATE); + vt_call_activate(vt); } static void real_sig_enter(struct uterm_vt *vt, struct signalfd_siginfo *info) @@ -182,7 +207,7 @@ static void real_sig_enter(struct uterm_vt *vt, struct signalfd_siginfo *info) if (ioctl(vt->real_fd, KDSETMODE, KD_GRAPHICS)) log_warn("cannot set graphics mode on vt %p (%d): %m", vt, errno); - vt_call(vt, UTERM_VT_ACTIVATE); + vt_call_activate(vt); } static void real_sig_leave(struct uterm_vt *vt, struct signalfd_siginfo *info) @@ -214,7 +239,12 @@ static void real_sig_leave(struct uterm_vt *vt, struct signalfd_siginfo *info) } log_debug("leaving VT %d %p due to VT signal", vt->real_num, vt); - vt_call(vt, UTERM_VT_DEACTIVATE); + ret = vt_call_deactivate(vt, false); + if (ret) { + ioctl(vt->real_fd, VT_RELDISP, 0); + log_debug("not leaving VT %d %p", vt->real_num, vt); + return; + } ioctl(vt->real_fd, VT_RELDISP, 1); if (ioctl(vt->real_fd, KDSETMODE, KD_TEXT)) log_warn("cannot set text mode on vt %p (%d): %m", vt, errno); @@ -427,7 +457,7 @@ static void real_close(struct uterm_vt *vt) log_debug("closing VT %d", vt->real_num); - vt_call(vt, UTERM_VT_DEACTIVATE); + vt_call_deactivate(vt, true); if (vt->real_delayed) { vt->real_delayed = false; ev_eloop_unregister_idle_cb(vt->vtm->eloop, real_delayed, vt); @@ -616,15 +646,14 @@ static void real_input(struct uterm_vt *vt, struct uterm_input_event *ev) static int fake_activate(struct uterm_vt *vt) { log_debug("activating fake VT due to user request"); - vt_call(vt, UTERM_VT_ACTIVATE); + vt_call_activate(vt); return 0; } static int fake_deactivate(struct uterm_vt *vt) { log_debug("deactivating fake VT due to user request"); - vt_call(vt, UTERM_VT_DEACTIVATE); - return 0; + return vt_call_deactivate(vt, false); } static void fake_input(struct uterm_vt *vt, struct uterm_input_event *ev) @@ -637,10 +666,10 @@ static void fake_input(struct uterm_vt *vt, struct uterm_input_event *ev) ev->handled = true; if (vt->active) { log_debug("deactivating fake VT due to user input"); - vt_call(vt, UTERM_VT_DEACTIVATE); + vt_call_deactivate(vt, false); } else { log_debug("activating fake VT due to user input"); - vt_call(vt, UTERM_VT_ACTIVATE); + vt_call_activate(vt); } } } @@ -773,7 +802,7 @@ void uterm_vt_deallocate(struct uterm_vt *vt) if (vt->mode == UTERM_VT_REAL) { real_close(vt); } else if (vt->mode == UTERM_VT_FAKE) { - vt_call(vt, UTERM_VT_DEACTIVATE); + vt_call_deactivate(vt, true); uterm_input_sleep(vt->input); } |