Thomas Hellstrom wrote:
Keith Whitwell wrote:
On Tue, 2009-03-17 at 03:56 -0700, José Fonseca wrote:
On Tue, 2009-03-17 at 03:39 -0700, Thomas Hellstrom wrote:
Thomas Hellström wrote:
Hi!

I'm currently looking into the thread-safety of the dri drivers. In particular the calls to libX11.

It appears that many of the applications I've tried have issues with deadlocks in the XCB code. It looks like this might be an issue with the locking order of XLockDisplay() and driver mutexes.

In particular, if the application protects all glx calls with XLockDisplay() the driver might deadlock in a normal GL call:

Thread A:
XLockDisplay() -> glxXXX -> driver mutex -> Xlib call -> Xcb XLockdisplay().
Thread B
Normal GL call -> driver mutex -> Xlib call -> Xcb XLockDisplay().

So we have a locking order reversal between the driver mutex and XLockDisplay which causes a deadlock.

Now, it seems like a simple away around this would be to omit the application XLockDisplays() completely. However, that seems to cause issues with XPending and XNextEvent eating the reply data meant for XSync(), leaving XSync waiting locked in a select().

I guess the remedy is to have the DRI utility routines and drivers protect _all_ X calls with XLockDisplay().

Does anyone have thoughts / insights about this?

Thanks,
Thomas


Hmm,
I installed a non-XCB Xlib and all problems just vanished...
Don't mind the above.
So is this a XCB problem?
XCB is pretty much the default now & given that it was supposed to
resolve the threading issues with old Xlib, I don't think that this
means the issue goes away...
Keith

Yes, as far as I can tell, this is an xcb problem, and it should pretty much affect all our drivers.

I guess this needs to be fixed asap. I'll see if I can come up with a non-GL X app that reproduces the problem. Basically it should show up if the main thread is running a loop that calls XNextEvent(), while other threads are calling XSync / XGetGeometry() on windows.

/Thomas


Attached is a program that should be linked with -lpthread -lX11.
For me it deadlocks immediately with an XCB-enabled Xlib, but works fine without XCB.

/Thomas

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>


struct thread_init_arg {
   int id;
};

struct window {
   pthread_mutex_t drawMutex;
   char DisplayName[1000];
   Display *Dpy;
   Window Win;
   int Id;
   XVisualInfo *visInfo;
};


#define MAX_WINDOWS 20
static struct window Windows[MAX_WINDOWS];
static int NumWindows = 0;
static int terminate = 0;
Display *gDpy;



static void
Error(const char *display, const char *msg)
{
   fprintf(stderr, "Error on display %s - %s\n", display, msg);
   exit(1);
}


static int
initMainthread(Display *dpy, const char *displayName)
{
   int scrnum;

   scrnum = DefaultScreen(dpy);
   return 0;
}

static struct window *
AddWindow(Display *dpy, const char *displayName, int xpos, int ypos)
{
   Window win;
   int scrnum;
   XSetWindowAttributes attr;
   unsigned long mask;
   Window root;
   XWindowAttributes root_attr;
   int width = 300, height = 300;

   if (NumWindows >= MAX_WINDOWS)
      return NULL;

   scrnum = DefaultScreen(dpy);
   root = RootWindow(dpy, scrnum);
   XGetWindowAttributes(dpy, root, &root_attr);

   /* window attributes */
   attr.background_pixel = 0;
   attr.border_pixel = 0;
   attr.colormap = XCreateColormap(dpy, root, XDefaultVisual(dpy, scrnum), 
				    AllocNone);
   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
   mask = CWBorderPixel | CWColormap | CWEventMask;

   win = XCreateWindow(dpy, root, xpos, ypos, width, height,
		       0, root_attr.depth, InputOutput,
		       XDefaultVisual(dpy, scrnum), mask, &attr);
   if (!win) {
      Error(displayName, "Couldn't create window");
      return NULL;
   }

   {
      XSizeHints sizehints;
      sizehints.x = xpos;
      sizehints.y = ypos;
      sizehints.width  = width;
      sizehints.height = height;
      sizehints.flags = USSize | USPosition;
      XSetNormalHints(dpy, win, &sizehints);
      XSetStandardProperties(dpy, win, displayName, displayName,
			     None, (char **)NULL, 0, &sizehints);
   }

   XMapWindow(dpy, win);

   /* save the info for this window */
   {
      static int id = 0;
      struct window *h = &Windows[NumWindows];
      strcpy(h->DisplayName, displayName);
      h->Dpy = dpy;
      h->Win = win;
      h->Id = id++;
      pthread_mutex_init(&h->drawMutex, NULL);
      NumWindows++;
      return &Windows[NumWindows-1];
   }
}


static void
Redraw(struct window *h)
{
   XWindowAttributes attr;

   pthread_mutex_lock(&h->drawMutex);
   XSync(h->Dpy, 0);
   XGetWindowAttributes(h->Dpy, h->Win, &attr);
   printf("Redraw %d\n", h->Id);
   pthread_mutex_unlock(&h->drawMutex);
}

static void *threadRunner (void *arg)
{
   struct thread_init_arg *tia = (struct thread_init_arg *) arg;
   struct window *win;

   win = &Windows[tia->id];

   while(!terminate) {
      usleep(1000);
      Redraw(win);
   }

   return NULL;
}

static void
Resize(struct window *h, unsigned int width, unsigned int height)
{
   XWindowAttributes attr;

   pthread_mutex_lock(&h->drawMutex);
   XSync(h->Dpy, 0);
   XGetWindowAttributes(h->Dpy, h->Win, &attr);
   printf("Resize %d\n", h->Id);
   pthread_mutex_unlock(&h->drawMutex);
}


static void
EventLoop(void)
{
   while (1) {
      int i;
      XEvent event;
      XNextEvent(gDpy, &event);
      for (i = 0; i < NumWindows; i++) {
	 struct window *h = &Windows[i];
	 if (event.xany.window == h->Win) {
	    switch (event.type) {
	    case Expose:
	       Redraw(h);
	       break;
	    case ConfigureNotify:
	       Resize(h, event.xconfigure.width, event.xconfigure.height);
	       break;
	    case KeyPress:
	       terminate = 1;
	       return;
	    default:
	       /*no-op*/ ;
	    }
	 }
      }
   }
}

int
main(int argc, char *argv[])
{
   const char *dpyName = XDisplayName(NULL);
   pthread_t t0, t1, t2, t3;
   struct thread_init_arg tia0, tia1, tia2, tia3;
   struct window *h0, *h1, *h2, *h3;

   XInitThreads();
   gDpy = XOpenDisplay(dpyName);
   if (!gDpy) {
      Error(dpyName, "Unable to open display");
      return -1;
   }

   if (initMainthread(gDpy, dpyName))
      return -1;

   /* four windows and contexts sharing display lists and texture objects */
   h0 = AddWindow(gDpy, dpyName,  10,  10);
   h1 = AddWindow(gDpy, dpyName, 330,  10);
   h2 = AddWindow(gDpy, dpyName,  10, 350);
   h3 = AddWindow(gDpy, dpyName, 330, 350);

   tia0.id = 0;
   pthread_create(&t0, NULL, threadRunner, &tia0);
   tia1.id = 1;
   pthread_create(&t1, NULL, threadRunner, &tia1);
   tia2.id = 2;
   pthread_create(&t2, NULL, threadRunner, &tia2);
   tia3.id = 3;
   pthread_create(&t3, NULL, threadRunner, &tia3);
   EventLoop();
   return 0;
}
------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Mesa3d-dev mailing list
Mesa3d-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to