Add synchronous debug functionality for X11.
X11 errors can be very difficult to debug because of the asynchronous
nature of the protocol. Add a helper that makes all X11 calls
synchronous and triggers a breakpoint if an error is detect, such that
looking at the backtrace gives hints as to what went wrong.
Bug: None
Change-Id: I5e92878a4cd62a426a8faf81beecbd596c47fcad
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/189703
Reviewed-by: Stephen White <senorblanco@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/X11Functions.cpp b/src/dawn/native/X11Functions.cpp
index 436854e..d5dd14e 100644
--- a/src/dawn/native/X11Functions.cpp
+++ b/src/dawn/native/X11Functions.cpp
@@ -27,11 +27,16 @@
#include "dawn/native/X11Functions.h"
+#include <memory>
+
+#include "dawn/common/Log.h"
+
namespace dawn::native {
X11Functions::X11Functions() {
if (!mX11Lib.Open("libX11.so.6") || !mX11Lib.GetProc(&xSetErrorHandler, "XSetErrorHandler") ||
- !mX11Lib.GetProc(&xGetWindowAttributes, "XGetWindowAttributes")) {
+ !mX11Lib.GetProc(&xGetWindowAttributes, "XGetWindowAttributes") ||
+ !mX11Lib.GetProc(&xSynchronize, "XSynchronize")) {
mX11Lib.Close();
}
@@ -50,4 +55,39 @@
return mX11XcbLib.Valid();
}
+struct DebugX11 {
+ static DebugX11* sDebug;
+ static void Init(Display* display) {
+ if (sDebug == nullptr) {
+ auto debug = std::make_unique<DebugX11>();
+ if (!debug->x.IsX11Loaded()) {
+ return;
+ }
+
+ debug->previousHandler = debug->x.xSetErrorHandler(&HandleError);
+ sDebug = debug.release();
+ }
+
+ // Make all X11 calls synchronous so that the error handler is called immediately.
+ sDebug->x.xSynchronize(display, true);
+ }
+
+ static int HandleError(Display* d, XErrorEvent* e) {
+ dawn::ErrorLog()
+ << "An X11 error happened, triggering a breakpoint, the culprit will be in the stack.";
+ dawn::BreakPoint();
+
+ int result = sDebug->previousHandler(d, e);
+ return result;
+ }
+
+ X11Functions x;
+ XErrorHandler previousHandler = nullptr;
+};
+DebugX11* DebugX11::sDebug = nullptr;
+
+void SynchronouslyDebugX11(Display* display) {
+ DebugX11::Init(display);
+}
+
} // namespace dawn::native
diff --git a/src/dawn/native/X11Functions.h b/src/dawn/native/X11Functions.h
index 3b54bbb..160431c 100644
--- a/src/dawn/native/X11Functions.h
+++ b/src/dawn/native/X11Functions.h
@@ -51,6 +51,9 @@
decltype(&::XSetErrorHandler) xSetErrorHandler = nullptr;
decltype(&::XGetWindowAttributes) xGetWindowAttributes = nullptr;
+ // Calling XSynchronize(display, true) can help debug "X Error of failed request" messages.
+ decltype(&::XSynchronize) xSynchronize = nullptr;
+
// Functions from x11-xcb
decltype(&::XGetXCBConnection) xGetXCBConnection = nullptr;
@@ -59,6 +62,9 @@
DynamicLib mX11XcbLib;
};
+// Make future X11 calls synchronously trigger a breakpoint if they cause an X11 error.
+void SynchronouslyDebugX11(Display* display);
+
} // namespace dawn::native
#endif // SRC_DAWN_NATIVE_X11FUNCTIONS_H_