On Fri, Aug 22, 2008 at 6:06 AM, Andy Hefner ahefner@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@gmail.com Date: Sat, Jul 12, 2008 at 5:27 AM Subject: Re: [Sbcl-devel] breaking the clx xid cache To: sbcl-devel@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