compositor: Use a minimal restore handler for crash clean up
When we hit a segv, it's often the case that we might crash again in the attempt to clean up. Instead we introduce a minimal restore callback in the backend abstraction, that shuts down as simply as possible. Then we can call that from the segv handler, and then to aid debugging, we raise SIGTRAP in the segv handler. This lets us run gdb on weston from a different vt, and if we tell gdb (gdb) handle SIGSEGV nostop gdb won't stop when the segv happens but let weston clean up and switch vt, and then stop when SIGTRAP is raised. It's also possible to just let gdb catch the segv, and then use sysrq+k followed by manual vt switch to get back.
This commit is contained in:
parent
023be102d7
commit
7b884bc0de
@ -1754,6 +1754,16 @@ udev_drm_event(int fd, uint32_t mask, void *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_restore(struct weston_compositor *ec)
|
||||
{
|
||||
struct drm_compositor *d = (struct drm_compositor *) ec;
|
||||
|
||||
if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
|
||||
weston_log("failed to drop master: %m\n");
|
||||
tty_reset(d->tty);
|
||||
}
|
||||
|
||||
static void
|
||||
drm_destroy(struct weston_compositor *ec)
|
||||
{
|
||||
@ -1951,6 +1961,7 @@ drm_compositor_create(struct wl_display *display,
|
||||
}
|
||||
|
||||
ec->base.destroy = drm_destroy;
|
||||
ec->base.restore = drm_restore;
|
||||
|
||||
ec->base.focus = 1;
|
||||
|
||||
|
@ -823,6 +823,11 @@ wayland_input_create(struct wayland_compositor *c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
wayland_restore(struct weston_compositor *ec)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wayland_destroy(struct weston_compositor *ec)
|
||||
{
|
||||
@ -871,6 +876,7 @@ wayland_compositor_create(struct wl_display *display,
|
||||
goto err_display;
|
||||
|
||||
c->base.destroy = wayland_destroy;
|
||||
c->base.restore = wayland_restore;
|
||||
|
||||
if (weston_compositor_init_gl(&c->base) < 0)
|
||||
goto err_display;
|
||||
|
@ -1028,6 +1028,11 @@ x11_compositor_get_resources(struct x11_compositor *c)
|
||||
xcb_free_pixmap(c->conn, pixmap);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_restore(struct weston_compositor *ec)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
x11_destroy(struct weston_compositor *ec)
|
||||
{
|
||||
@ -1087,6 +1092,7 @@ x11_compositor_create(struct wl_display *display,
|
||||
goto err_xdisplay;
|
||||
|
||||
c->base.destroy = x11_destroy;
|
||||
c->base.restore = x11_restore;
|
||||
|
||||
if (weston_compositor_init_gl(&c->base) < 0)
|
||||
goto err_egl;
|
||||
|
@ -57,7 +57,7 @@
|
||||
#include "git-version.h"
|
||||
|
||||
static struct wl_list child_process_list;
|
||||
static jmp_buf segv_jmp_buf;
|
||||
static struct weston_compositor *segv_compositor;
|
||||
|
||||
static int
|
||||
sigchld_handler(int signal_number, void *data)
|
||||
@ -3309,6 +3309,14 @@ on_segv_signal(int s, siginfo_t *siginfo, void *context)
|
||||
int i, count;
|
||||
Dl_info info;
|
||||
|
||||
/* This SIGSEGV handler will do a best-effort backtrace, and
|
||||
* then call the backend restore function, which will switch
|
||||
* back to the vt we launched from or ungrab X etc and then
|
||||
* raise SIGTRAP. If we run weston under gdb from X or a
|
||||
* different vt, and tell gdb "handle SIGSEGV nostop", this
|
||||
* will allow weston to switch back to gdb on crash and then
|
||||
* gdb will catch the crash with SIGTRAP. */
|
||||
|
||||
weston_log("caught segv\n");
|
||||
|
||||
count = backtrace(buffer, ARRAY_LENGTH(buffer));
|
||||
@ -3320,7 +3328,9 @@ on_segv_signal(int s, siginfo_t *siginfo, void *context)
|
||||
info.dli_fname);
|
||||
}
|
||||
|
||||
longjmp(segv_jmp_buf, 1);
|
||||
segv_compositor->restore(segv_compositor);
|
||||
|
||||
raise(SIGTRAP);
|
||||
}
|
||||
|
||||
|
||||
@ -3513,11 +3523,6 @@ int main(int argc, char *argv[])
|
||||
signals[3] = wl_event_loop_add_signal(loop, SIGCHLD, sigchld_handler,
|
||||
NULL);
|
||||
|
||||
segv_action.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
||||
segv_action.sa_sigaction = on_segv_signal;
|
||||
sigemptyset(&segv_action.sa_mask);
|
||||
sigaction(SIGSEGV, &segv_action, NULL);
|
||||
|
||||
if (!backend) {
|
||||
if (getenv("WAYLAND_DISPLAY"))
|
||||
backend = "wayland-backend.so";
|
||||
@ -3542,6 +3547,12 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
segv_action.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
||||
segv_action.sa_sigaction = on_segv_signal;
|
||||
sigemptyset(&segv_action.sa_mask);
|
||||
sigaction(SIGSEGV, &segv_action, NULL);
|
||||
segv_compositor = ec;
|
||||
|
||||
for (i = 1; argv[i]; i++)
|
||||
weston_log("fatal: unhandled option: %s\n", argv[i]);
|
||||
if (argv[1]) {
|
||||
@ -3589,12 +3600,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
weston_compositor_dpms_on(ec);
|
||||
weston_compositor_wake(ec);
|
||||
if (setjmp(segv_jmp_buf) == 0)
|
||||
wl_display_run(display);
|
||||
else
|
||||
ret = EXIT_FAILURE;
|
||||
|
||||
out:
|
||||
wl_display_run(display);
|
||||
|
||||
out:
|
||||
/* prevent further rendering while shutting down */
|
||||
ec->state = WESTON_COMPOSITOR_SLEEPING;
|
||||
|
||||
|
@ -335,6 +335,7 @@ struct weston_compositor {
|
||||
int has_bind_display;
|
||||
|
||||
void (*destroy)(struct weston_compositor *ec);
|
||||
void (*restore)(struct weston_compositor *ec);
|
||||
int (*authenticate)(struct weston_compositor *c, uint32_t id);
|
||||
|
||||
void (*ping_handler)(struct weston_surface *surface, uint32_t serial);
|
||||
@ -702,6 +703,9 @@ tty_create(struct weston_compositor *compositor,
|
||||
void
|
||||
tty_destroy(struct tty *tty);
|
||||
|
||||
void
|
||||
tty_reset(struct tty *tty);
|
||||
|
||||
int
|
||||
tty_activate_vt(struct tty *tty, int vt);
|
||||
|
||||
|
15
src/tty.c
15
src/tty.c
@ -257,14 +257,10 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
tty_destroy(struct tty *tty)
|
||||
void tty_reset(struct tty *tty)
|
||||
{
|
||||
struct vt_mode mode = { 0 };
|
||||
|
||||
if (tty->input_source)
|
||||
wl_event_source_remove(tty->input_source);
|
||||
|
||||
if (ioctl(tty->fd, KDSKBMODE, tty->kb_mode))
|
||||
weston_log("failed to restore keyboard mode: %m\n");
|
||||
|
||||
@ -282,9 +278,18 @@ tty_destroy(struct tty *tty)
|
||||
ioctl(tty->fd, VT_ACTIVATE, tty->starting_vt);
|
||||
ioctl(tty->fd, VT_WAITACTIVE, tty->starting_vt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tty_destroy(struct tty *tty)
|
||||
{
|
||||
if (tty->input_source)
|
||||
wl_event_source_remove(tty->input_source);
|
||||
|
||||
wl_event_source_remove(tty->vt_source);
|
||||
|
||||
tty_reset(tty);
|
||||
|
||||
close(tty->fd);
|
||||
|
||||
free(tty);
|
||||
|
Loading…
x
Reference in New Issue
Block a user