我有一个在20世纪90年代初编写的遗留Motif应用程序(如果不进行耗时的安全评估,我无法在QT中重写UI,甚至无法广泛修改应用程序)。这个应用程序曾经在AIX上运行,在高强度使用的情况下,它可以连续运行数周,而且非常稳定。我们现在已经将它移植到Linux。在长时间的持续测试中,该应用程序大约每周崩溃一次,并显示以下消息。
失败请求的错误:BadWindow(无效的Window参数)
失败请求的主要操作码:4(X_DestroyWindow)
我后来了解到,使用自定义X11错误处理程序可以忽略这些错误(默认的X11错误处理器只打印错误消息并退出),如下所述:
http://motifdeveloper.com/tips/tip29.html
我已经实现了一个自定义的X11错误处理程序,它可以忽略BadWindow错误,如本文所述。所以我的问题是:一个比我更了解X11开发和X服务器内部工作的人能告诉我BadWindow错误是否真的可以像那样被忽略吗
p.S。我将尝试通过在同步模式下运行我们的应用程序来进一步调试这个问题,但速度很慢,因为我无法按需重现这个错误。任何关于调试BadWindow错误的提示也将不胜感激
如果您的程序由单个进程组成(与X显示器的单个连接),则此错误几乎总是反映程序中的错误。
要知道的秘密是如何调试它。因为Xlib是异步的,XDestroyWindow()
将即发即弃,对窗口的一些销毁后操作也可能是即发即弃,你会在将来的某个时间(在其他一些无关的X调用中)得到错误。这意味着X错误的堆栈跟踪毫无意义,而且很难调试。
要解决此问题,请调用XSynchronize(dpy, True)
以强制所有调用同步。这会使应用程序速度变慢,所以不要在生产中一直打开它。http://www.x.org/releases/X11R7.6/doc/man/man3/XSynchronize.3.xhtml
但在同步模式下,如果Xlib调用使用了一个坏窗口,它将立即失败。因此,您可以设置调试断点,例如在错误处理程序函数上,并获得有意义的回溯。这应该会告诉你是哪个Xlib调用导致了问题,希望它能清楚地表明这是对小部件的双重删除,还是使用了销毁的小部件,还是什么。
如果你的应用程序确实有多个进程或多个显示连接,例如在窗口管理器中,那么BadWindow
可能是不可避免的(如果你试图破坏另一个应用程序的窗口,那么就会出现一场不可避免的竞争,另一个应用程序的窗口可能会被破坏)。在这种情况下,忽略BadWindow
是正确的解决方案,尽管最佳实践是仅在已知会触发它的调用期间忽略它,因此您仍然可能会得到可能是错误的错误。一个常见的习惯用法是实现error_trap_push()
/error_trap_pop()
,它只安装和卸载忽略错误的错误处理程序。当你触摸一个可能在你控制范围之外被删除的外部窗口时,按下一个错误陷阱。
这看起来像是一个按钮(或类似的UI元素)被多次删除。通常,按钮被实现为专用窗口,并在其中发出按钮图形,这样您就可以简单地将回调处理程序与关联窗口中的单击事件联系起来。
该错误表明您的程序已尝试删除不存在的窗口id,而最简单的方法确实是删除了两次(或者,某个UI元素的id发生了更改)。
在这一点上,您不希望忽略错误,您希望获得足够的日志记录,以找出应用程序的问题所在。
在这种情况下,错误告诉您,您的程序请求销毁一个不存在的窗口id。如果你忽略了它,那么你可能会泄露你真正想要破坏的任何窗口;或者,您可能只是试图破坏同一个窗口id两次,结果什么都不会改变。如果不追踪程序使用无效id调用XDestroyWindow的根本原因,很难说如果忽略它会发生什么。