[mcclim-devel] [bug] Asynchronous ID-CHOICE-ERROR -- CLX or McCLIM?

Nikodemus Siivola nikodemus at random-state.net
Fri Aug 22 09:15:58 UTC 2008


On Fri, Aug 22, 2008 at 6:06 AM, Andy Hefner <ahefner at gmail.com> wrote:
> I just encountered the "Asynchronous ID-CHOICE-ERROR" myself tonight,
> in my case when multiple mcclim applications (in multiple threads) on
> one screen race to repaint. I don't know if it's related to Nikodemus'
> test case, which doesn't make any use of threads (excluding the
> omnipresent CLX event dispatching thread), but at least it's the same
> error.

I don't remember offhand for sure, but I think that was actually on a
single-threaded SBCL -- so there would perforce be only one thread in
Lisp Land.

Since it seems to be in danger of falling through the cracks, here is
a (possibly related) report from sbcl-devel.

Cheers,

 -- Nikodemus

---------- Forwarded message ----------
From: Shawn <sabetts at gmail.com>
Date: Sat, Jul 12, 2008 at 5:27 AM
Subject: Re: [Sbcl-devel] breaking the clx xid cache
To: sbcl-devel at lists.sf.net


Hi folks,

It looks like the portable-clx mailing list is down so I'm sending this here.

In stumpwm I've been getting more and more error reports where the
:window slot for events is a pixmap instead of a window. I've tracked
it to a problem with the xid cache in clx. X appears to be recycling
XIDs which confuses clx. Here's a function that exposes the bug:

(defun break-display-xid-cache ()
 (labels ((make-win (dpy)
            (xlib:create-window :parent (xlib:screen-root (first
(xlib:display-roots dpy))) :x 0 :y 0 :width 50 :height 50))
          (make-pixmap (window)
            (xlib:create-pixmap :width (random 100) :height (random
100) :depth 8 :drawable window))
          (first-pass (dpy)
            ;; Open a fresh connection. Create a window and a pixmap.
            (let* ((dpy2 (xlib:open-default-display))
                   (window (make-win dpy2))
                   (pixmap (make-pixmap window)))
              ;; make the pixmap the window's icon pixmap hint.
              (setf (xlib:wm-hints window) (xlib:make-wm-hints
:icon-pixmap pixmap))
              (format t "Window ID: ~s pixmap ID: ~s~%"
(xlib:window-id window) (xlib:pixmap-id pixmap))
              (xlib:display-finish-output dpy2)
              ;; On the old connection, list the root window children
              ;; and the icon pixmap hint to cache their XIDs.
              (loop for w in (xlib:query-tree (xlib:screen-root (first
(xlib:display-roots dpy))))
                 for hints = (xlib:wm-hints w)
                 when hints
                 do (format t "top level window id: ~s | icon pixmap
hint: ~s~%" (xlib:window-id w) (xlib:wm-hints-icon-pixmap hints)))
              (xlib:close-display dpy2)))
          (second-pass (dpy)
            ;; Open a fresh connection and create 2 windows.
            (let* ((dpy2 (xlib:open-default-display))
                   (window1 (make-win dpy2))
                   (window2 (make-win dpy2)))
              (format t "Window#1 ID: ~s Window#2 ID: ~s~%"
(xlib:window-id window1) (xlib:window-id window2))
              (xlib:display-finish-output dpy2)
              ;; On the old connection, list the root window children
              ;; and note the second window is erroneously a pixmap
              ;; due to too agressive caching in clx.
              (loop for w in (xlib:query-tree (xlib:screen-root (first
(xlib:display-roots dpy))))
                 do (format t "window: ~s~%" w))
              (xlib:close-display dpy2))))
   (let ((dpy (xlib:open-default-display)))
     (first-pass dpy)
     (second-pass dpy)
     (xlib:close-display dpy))))

Note that the last window in the window list printed at the end is a
pixmap and not a window! Here's the relevant output when i run it:


* (break-display-xid-cache)
Window ID: 14680065 pixmap ID: 14680066
top level window id: 14680065 | icon pixmap hint: #<XLIB:PIXMAP :0 E00002>
Window#1 ID: 14680065 Window#2 ID: 14680066
window: #<XLIB:WINDOW :0 E00001>
window: #<XLIB:PIXMAP :0 E00002>
NIL
*

I propose the following patch. Since a cache error isn't the sign of a
bug, I don't think checking the type should depend +type-check?+
constant. In the event of a lookup error, I've added two restarts for
invalidating the cache and creating fresh XID cache entries. This is
how it has been addressed in new-clx.

--- display.lisp        2005-08-26 03:13:28.000000000 -0700
+++ display.lisp        2008-07-11 17:22:39.000000000 -0700
@@ -199,17 +199,21 @@
                                                     :display display :id id))
                                        (save-id display id ,type))
                                       ;; Found.  Check the type
-                                       ,(cond ((null +type-check?+)
-                                               `(t ,type))
-                                              ((member type '(window pixmap))
-                                               `((type? ,type
'drawable) ,type))
-                                              (t `((type? ,type
',type) ,type)))
-                                       ,@(when +type-check?+
-                                           `((t (x-error 'lookup-error
-                                                         :id id
-                                                         :display display
-                                                         :type ',type
-                                                         :object ,type))))))
+                                        ((type? ,type ',type) ,type)
+                                        (t
+                                         (restart-case
+                                             (x-error 'lookup-error
+                                                      :id id
+                                                      :display display
+                                                      :type ',type
+                                                      :object ,type)
+                                           (one ()
+                                             :report "Invalidate this
cache entry"
+                                             (save-id display id
(,(xintern 'make- type) :display display :id id)))
+                                           (all ()
+                                             :report "Invalidate all
display cache"
+                                             (clrhash
(display-resource-id-map display))
+                                             (save-id display id
(,(xintern 'make- type) :display display :id id)))))))
                              ;; Not being cached.  Create a new one each time.
                              `(,(xintern 'make- type)
                                :display display :id id))))



-Shawn



More information about the mcclim-devel mailing list