xpra icon
Bug tracker and wiki

Ticket #475: xshm-debugging.patch

File xshm-debugging.patch, 10.9 KB (added by Antoine Martin, 7 years ago)

improve xshm debugging and add unique ids and thread checking

  • xpra/x11/bindings/ximage.pyx

     
    66
    77import os
    88import time
     9import threading
    910
    1011from xpra.util import dump_exc, AdHocStruct
    1112import errno as pyerrno
     
    340341            self.pixels = NULL
    341342
    342343
     344cdef long xshm_counter
     345
    343346cdef class XShmWrapper(object):
    344347    cdef Display *display                              #@DuplicatedSignature
    345348    cdef Visual *visual
     
    351354    cdef XImage *image
    352355    cdef int ref_count
    353356    cdef Bool closed
     357    cdef Bool freed
     358    cdef int unique_id
     359    cdef object thread
    354360
    355361    cdef init(self, Display *display, Window xwindow, Visual *visual, int width, int height, int depth):
    356362        self.display = display
     
    359365        self.width = width
    360366        self.height = height
    361367        self.depth = depth
     368        #all calls run in UI thread, so we can just increment without locking
     369        global xshm_counter
     370        self.unique_id = xshm_counter
     371        xshm_counter += 1
     372        self.thread = threading.currentThread()
    362373
     374    def __str__(self):                              #@DuplicatedSignature
     375        return "XShmWrapper(%s, %s, %s, %s, ID=%s)" % (self.window, self.width, self.height, self.depth, self.unique_id)
     376
     377
    363378    def setup(self):
    364379        #returns:
    365380        # (init_ok, may_retry_this_window, XShm_global_failure)
     381        xshm_debug("%s.setup()", self)
    366382        cdef size_t size
    367383        cdef Bool a
    368384        self.ref_count = 0
     
    372388        self.image = XShmCreateImage(self.display, self.visual, self.depth,
    373389                          ZPixmap, NULL, &self.shminfo,
    374390                          self.width, self.height)
    375         xshm_debug("XShmWrapper.XShmCreateImage(%sx%s-%s) %s", self.width, self.height, self.depth, self.image!=NULL)
    376391        if self.image==NULL:
    377             log.error("XShmWrapper.XShmCreateImage(%sx%s-%s) failed!", self.width, self.height, self.depth)
     392            log.error("XShmCreateImage(%sx%s-%s) failed", self.width, self.height, self.depth)
    378393            self.cleanup()
    379394            #if we cannot create an XShm XImage, we may try again
    380395            #(it could be dimensions are too big?)
    381396            return False, True, False
     397        xshm_debug("XShmCreateImage(%sx%s-%s)=%s", self.width, self.height, self.depth, hex(<unsigned long> self.image))
    382398        # Get the shared memory:
    383399        # (include an extra line to ensure we can read rowstride at a time,
    384400        #  even on the last line, without reading past the end of the buffer)
    385401        size = self.image.bytes_per_line * (self.image.height + 1)
    386402        self.shminfo.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777)
    387         xshm_debug("XShmWrapper.shmget(PRIVATE, %s bytes, %s) shmid=%s", size, IPC_CREAT | 0777, self.shminfo.shmid)
    388403        if self.shminfo.shmid < 0:
    389             log.error("XShmWrapper.shmget(PRIVATE, %s bytes, %s) failed, bytes_per_line=%s, width=%s, height=%s", size, IPC_CREAT | 0777, self.image.bytes_per_line, self.width, self.height)
     404            log.error("shmget(PRIVATE, %s bytes, %s) failed, bytes_per_line=%s, width=%s, height=%s", size, IPC_CREAT | 0777, self.image.bytes_per_line, self.width, self.height)
    390405            self.cleanup()
    391406            #only try again if we get EINVAL,
    392407            #the other error codes probably mean this is never going to work..
    393408            return False, errno==pyerrno.EINVAL, errno!=pyerrno.EINVAL
     409        xshm_debug("shmget(PRIVATE, %s bytes, %s) shmid=%s", size, IPC_CREAT | 0777, self.shminfo.shmid)
    394410        # Attach:
    395411        self.image.data = <char *> shmat(self.shminfo.shmid, NULL, 0)
    396412        self.shminfo.shmaddr = self.image.data
    397         xshm_debug("XShmWrapper.shmat(%s, NULL, 0) %s", self.shminfo.shmid, self.shminfo.shmaddr != <char *> -1)
    398413        if self.shminfo.shmaddr == <char *> -1:
    399             log.error("XShmWrapper.shmat(%s, NULL, 0) failed!", self.shminfo.shmid)
     414            log.error("shmat(%s, NULL, 0) failed!", self.shminfo.shmid)
    400415            self.cleanup()
    401416            #we may try again with this window, or any other window:
    402417            #(as this really shouldn't happen at all)
    403418            return False, True, False
     419        xshm_debug("shmat(%s, NULL, 0)=%s", self.shminfo.shmid, hex(<unsigned long> self.shminfo.shmaddr))
    404420
    405421        # set as read/write, and attach to the display:
    406422        self.shminfo.readOnly = False
    407423        a = XShmAttach(self.display, &self.shminfo)
    408         xshm_debug("XShmWrapper.XShmAttach(..) %s", bool(a))
    409424        if not a:
    410             log.error("XShmWrapper.XShmAttach(..) failed!")
     425            log.error("XShmAttach(..) failed!")
    411426            self.cleanup()
    412427            #we may try again with this window, or any other window:
    413428            #(as this really shouldn't happen at all)
    414429            return False, True, False
     430        xshm_debug("XShmAttach(..)=%s", bool(ret))
    415431        return True, True, False
    416432
    417433    def get_size(self):                                     #@DuplicatedSignature
     
    421437        assert self.image!=NULL, "cannot retrieve image wrapper: XImage is NULL!"
    422438        if self.closed:
    423439            return None
    424         xshm_debug("XShmWrapper.get_image%s", (xpixmap, x, y, w, h))
     440        xshm_debug("%s.get_image%s", self, (xpixmap, x, y, w, h))
    425441        if x>=self.width or y>=self.height:
    426             xshm_debug("XShmWrapper.get_pixels(%s, %s, %s, %s) position outside image dimensions %sx%s", x, y, w, h, self.width, self.height)
     442            xshm_debug("get_image%s position outside image dimensions %sx%s", (xpixmap, x, y, w, h), self.width, self.height)
    427443            return None
    428444        #clamp size to image size:
    429445        if x+w>self.width:
     
    431447        if y+h>self.height:
    432448            h = self.height-y
    433449        if not XShmGetImage(self.display, xpixmap, self.image, 0, 0, 0xFFFFFFFF):
    434             xshm_debug("XShmWrapper.get_image%s XShmGetImage failed!", (xpixmap, x, y, w, h))
     450            xshm_debug("get_image%s XShmGetImage failed!", (xpixmap, x, y, w, h))
    435451            return None
    436452        self.ref_count += 1
    437453        imageWrapper = XShmImageWrapper(x, y, w, h)
    438454        imageWrapper.set_image(self.image)
    439455        imageWrapper.set_free_callback(self.free_image)
    440         xshm_debug("XShmWrapper.get_image%s ref_count=%s, returning %s", (xpixmap, x, y, w, h), self.ref_count, imageWrapper)
     456        xshm_debug("get_image%s ref_count=%s, returning %s", (xpixmap, x, y, w, h), self.ref_count, imageWrapper)
    441457        return imageWrapper
    442458
    443459    def __dealloc__(self):                              #@DuplicatedSignature
    444         xshm_debug("XShmWrapper.__dealloc__() self=%s", self)
     460        xshm_debug("XShmWrapper.__dealloc__() ID=%s", self.unique_id)
    445461        self.cleanup()
    446462
     463    def is_closed(self):
     464        return self.closed
     465
     466    def is_freed(self):
     467        return self.freed
     468
    447469    def cleanup(self):
    448470        #ok, we want to free resources... problem is,
    449471        #we may have handed out some XShmImageWrappers
    450472        #and they will point to our Image XShm area.
    451473        #so we have to wait until *they* are freed,
    452474        #and rely on them telling us via the free_image callback.
    453         xshm_debug("XShmWrapper.cleanup() ref_count=%s", self.ref_count)
     475        xshm_debug("XShmWrapper.cleanup() ID=%s, ref_count=%s", self.unique_id, self.ref_count)
    454476        self.closed = True
    455         if self.ref_count==0:
     477        if self.ref_count==0 and not self.freed:
    456478            self.free()
    457479
    458480    def free_image(self):                               #@DuplicatedSignature
    459481        self.ref_count -= 1
    460         xshm_debug("XShmWrapper.free_image() closed=%s, new ref_count=%s", self.closed, self.ref_count)
     482        xshm_debug("XShmWrapper.free_image() ID=%s, closed=%s, new ref_count=%s", self.unique_id, self.closed, self.ref_count)
    461483        if self.closed and self.ref_count==0:
     484            assert not self.freed
    462485            self.free()
    463486
    464487    def free(self):                                     #@DuplicatedSignature
    465488        assert self.ref_count==0, "XShmWrapper %s cannot be freed: still has a ref count of %s" % (self, self.ref_count)
    466489        assert self.closed, "XShmWrapper %s cannot be freed: it is not closed yet" % self
     490        if self.thread!=threading.currentThread():
     491            log.warn("THREAD HAS CHANGED - OUCH!")
    467492        has_shm = self.shminfo.shmaddr!=<char *> -1
    468         xshm_debug("XShmWrapper.free() has_shm=%s, image=%s, shmid=%s", has_shm, hex(<unsigned long> self.image), self.shminfo.shmid)
     493        xshm_debug("%s.free() has_shm=%s, image=%s, shmid=%s", self, has_shm, hex(<unsigned long> self.image), self.shminfo.shmid)
    469494        if has_shm:
    470495            XShmDetach(self.display, &self.shminfo)
    471496        if self.image!=NULL:
     
    476501            shmdt(self.shminfo.shmaddr)
    477502            self.shminfo.shmaddr = <char *> -1
    478503            self.shminfo.shmid = -1
     504        self.freed = True
    479505
    480506
     507cdef long xshm_image_counter = 0
     508
    481509cdef class XShmImageWrapper(XImageWrapper):
    482510
    483511    cdef object free_callback
     512    cdef int unique_id                              #@DuplicatedSignature
    484513
    485514    def __init__(self, *args):                      #@DuplicatedSignature
    486515        self.free_callback = None
     516        #all calls run in UI thread, so we can just increment without locking
     517        global xshm_image_counter
     518        self.unique_id = xshm_image_counter       
     519        xshm_image_counter += 1
     520        xshm_debug("%s.init%s", self, args)
    487521
    488522    def __str__(self):                              #@DuplicatedSignature
    489         return "XShmImageWrapper(%s: %s, %s, %s, %s)" % (self.pixel_format, self.x, self.y, self.width, self.height)
     523        return "XShmImageWrapper(%s: %s, %s, %s, %s, ID=%s)" % (self.pixel_format, self.x, self.y, self.width, self.height, self.unique_id)
    490524
    491525    def get_image_pixels(self):                     #@DuplicatedSignature
    492526        cdef char *offset
    493         xshm_debug("XShmImageWrapper.get_image_pixels() self=%s", self)
     527        xshm_debug("XShmImageWrapper.get_image_pixels() ID=%s", self.unique_id)
    494528        assert self.image!=NULL
    495529        #calculate offset (assuming 4 bytes "pixelstride"):
    496530        offset = self.image.data + (self.y * self.rowstride) + (4 * self.x)
    497531        return PyBuffer_FromReadWriteMemory(offset, self.get_size())
    498532
    499533    def free(self):                                 #@DuplicatedSignature
    500         xshm_debug("XShmImageWrapper.free() free_callback=%s", self.free_callback)
     534        xshm_debug("XShmImageWrapper.free() ID=%s, free_callback=%s", self.unique_id, self.free_callback)
    501535        #ensure we never try to XDestroyImage:
    502536        self.image = NULL
    503537        self.free_pixels()
     
    505539            cb = self.free_callback
    506540            self.free_callback = None
    507541            cb()
    508         xshm_debug("XShmImageWrapper.free() done")
     542        xshm_debug("XShmImageWrapper.free() ID=%s, done", self.unique_id)
    509543
    510544    def set_free_callback(self, callback):
    511545        self.free_callback = callback