diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 48202ba7..0ab1dadb 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -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; diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c index ee3def1e..8e86611a 100644 --- a/src/compositor-wayland.c +++ b/src/compositor-wayland.c @@ -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; diff --git a/src/compositor-x11.c b/src/compositor-x11.c index f2f0cb11..e27555d6 100644 --- a/src/compositor-x11.c +++ b/src/compositor-x11.c @@ -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; diff --git a/src/compositor.c b/src/compositor.c index 62ae79b1..bd2a0d2c 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -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; diff --git a/src/compositor.h b/src/compositor.h index 22c0174c..7112796b 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -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); diff --git a/src/tty.c b/src/tty.c index a8b2aed2..d8df2b59 100644 --- a/src/tty.c +++ b/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);