AS_HELP_STRING([--disable-x11],[Disable optional X11 support]))
AS_IF([test "x$enable_x11" != "xno"],
- [PKG_CHECK_MODULES(X11, [ x11-xcb xcb >= 1.6 ice sm xtst ], HAVE_X11=1, HAVE_X11=0)],
- HAVE_X11=0)
+ [
+ PKG_CHECK_MODULES(X11, [ x11-xcb xcb >= 1.6 ice sm xtst ], HAVE_X11=1, HAVE_X11=0)
+ AC_CHECK_LIB(X11, XSetIOErrorExitHandler, [HAVE_XSETIOERROREXITHANDLER=yes], [HAVE_XSETIOERROREXITHANDLER=no])
+ ],
+ [
+ HAVE_X11=0
+ HAVE_XSETIOERROREXITHANDLER=no
+ ])
AS_IF([test "x$enable_x11" = "xyes" && test "x$HAVE_X11" = "x0"],
[AC_MSG_ERROR([*** X11 not found])])
AC_SUBST(HAVE_X11)
AM_CONDITIONAL([HAVE_X11], [test "x$HAVE_X11" = x1])
AS_IF([test "x$HAVE_X11" = "x1"], AC_DEFINE([HAVE_X11], 1, [Have X11?]))
+AS_IF([test "x$HAVE_XSETIOERROREXITHANDLER" = "xyes"], AC_DEFINE([HAVE_XSETIOERROREXITHANDLER], 1, [Have XSetIOErrorExitHandler function.]))
#### Capabilities (optional) ####
Enable memfd shared memory: ${ENABLE_MEMFD}
Enable X11: ${ENABLE_X11}
+ Safe X11 I/O errors: ${HAVE_XSETIOERROREXITHANDLER}
Enable OSS Output: ${ENABLE_OSS_OUTPUT}
Enable OSS Wrapper: ${ENABLE_OSS_WRAPPER}
Enable EsounD: ${ENABLE_ESOUND}
sm_dep = dependency('sm', required : true)
xtst_dep = dependency('xtst', required : true)
cdata.set('HAVE_X11', 1)
+ if cc.has_function('XSetIOErrorExitHandler', dependencies: x11_dep)
+ cdata.set('HAVE_XSETIOERROREXITHANDLER', 1)
+ endif
endif
# Module dependencies
'',
'Enable memfd shared memory: @0@'.format(cdata.has('HAVE_MEMFD')),
'Enable X11: @0@'.format(x11_dep.found()),
+ ' Safe X11 I/O errors: @0@'.format(cdata.has('HAVE_XSETIOERROREXITHANDLER')),
'Enable OSS Output: @0@'.format(cdata.has('HAVE_OSS_OUTPUT')),
'Enable OSS Wrapper: @0@'.format(cdata.has('HAVE_OSS_WRAPPER')),
# 'Enable EsounD: @0@'.format(${ENABLE_ESOUND}),
#include "x11wrap.h"
+#include <X11/Xlib.h>
+
typedef struct pa_x11_internal pa_x11_internal;
struct pa_x11_internal {
pa_defer_event* defer_event;
pa_io_event* io_event;
+ pa_defer_event* cleanup_event;
PA_LLIST_HEAD(pa_x11_client, clients);
PA_LLIST_HEAD(pa_x11_internal, internals);
void *userdata;
};
+static void x11_wrapper_kill(pa_x11_wrapper *w);
+
/* Dispatch all pending X11 events */
static void work(pa_x11_wrapper *w) {
pa_assert(w);
x11_internal_remove(w, (pa_x11_internal*) *watch_data);
}
+static int x11_error_handler(Display* display, XErrorEvent* error_event) {
+ pa_log_warn("X11 error handler called");
+ return 0;
+}
+
+static int x11_io_error_handler(Display* display) {
+ pa_log_warn("X11 I/O error handler called");
+ return 0;
+}
+
+static void deferred_x11_teardown(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
+ pa_x11_wrapper *w = userdata;
+
+ m->defer_enable(e, 0);
+
+ pa_log_debug("Start tearing down X11 modules after X11 I/O error");
+
+ x11_wrapper_kill(w);
+
+ pa_log_debug("Done tearing down X11 modules after X11 I/O error");
+}
+
+#ifdef HAVE_XSETIOERROREXITHANDLER
+static void x11_io_error_exit_handler(Display* display, void *userdata) {
+ pa_x11_wrapper *w = userdata;
+
+ pa_log_warn("X11 I/O error exit handler called, preparing to tear down X11 modules");
+
+ pa_x11_wrapper_kill_deferred(w);
+}
+#endif
+
static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) {
pa_x11_wrapper*w;
Display *d;
w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w);
w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w);
+ w->cleanup_event = c->mainloop->defer_new(c->mainloop, deferred_x11_teardown, w);
+ w->core->mainloop->defer_enable(w->cleanup_event, 0);
+ XSetErrorHandler(x11_error_handler);
+ XSetIOErrorHandler(x11_io_error_handler);
+#ifdef HAVE_XSETIOERROREXITHANDLER
+ XSetIOErrorExitHandler(d, x11_io_error_exit_handler, w);
+#endif
XAddConnectionWatch(d, x11_watch, (XPointer) w);
pa_assert_se(pa_shared_set(c, w->property_name, w) >= 0);
+ pa_log_debug("Created X11 connection wrapper '%s'", w->property_name);
+
return w;
}
pa_assert(!w->clients);
+ pa_log_debug("Destroying X11 connection wrapper '%s'", w->property_name);
+
XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w);
XCloseDisplay(w->display);
+ w->core->mainloop->defer_free(w->cleanup_event);
w->core->mainloop->io_free(w->io_event);
w->core->mainloop->defer_free(w->defer_event);
return XGetXCBConnection(pa_x11_wrapper_get_display(w));
}
-void pa_x11_wrapper_kill(pa_x11_wrapper *w) {
+void pa_x11_wrapper_kill_deferred(pa_x11_wrapper *w) {
+ pa_assert(w);
+
+ /* schedule X11 display teardown */
+ w->core->mainloop->defer_enable(w->cleanup_event, 1);
+}
+
+/* Kill the connection to the X11 display */
+static void x11_wrapper_kill(pa_x11_wrapper *w) {
pa_x11_client *c, *n;
pa_assert(w);