Subject: bug in libGL? was Re: pthreads, Xlib and me ...
To: None <port-macppc@netbsd.org, tech-x11@NetBSD.org>
From: leon zadorin <leonleon77@gmail.com>
List: tech-x11
Date: 04/16/2007 00:02:31
Hi all,

firstly, sorry if this is a false alarm caused by my stupidity - it is
rather very late and my brain is not functioning as it should be...

just a short note/update on the issues of Xlib, XInitThreads, libGL,
pthreads and "unlocking unlocked mutex" error...

It appears that there may be a bug in libGL (in NetBSD's xsrc source
tree - which may affect other ports, not just the macppc)... well, at
least the line in question looks strange to me and taking it out
solves the problem (presented at the end of this message)... I could
be very wrong, however, so here it goes:

in /usr/xsrc/xfree/xc/lib/GL/glx/glxext.c (or
/usr/xsrc/dist/Mesa/src/glx/x11/glxext.c)

one of the code snippets in AllocAndFetchScreenConfigs, (lines 1004)  reads:

	UnlockDisplay(dpy);
	if (!reply.numVisuals) {
	    /* This screen does not support GL rendering */
	    UnlockDisplay(dpy);
	    continue;
	}

Is it possible that it is doing double unlocking and if so - is it a
bug? It is caught by libpthread on macppc port and process is
aborted... the doco for pthread_mutex_unlock says that if mutex is
recursive then unlocking an unlocked mutex will return an error, and
if mutex is not recursive then undefined behaviour will take place...
so is it a bug in terms of line 1004 which should not be present there
or should Xlib be using a different kind of a mutex (I think that the
more likely solution is for 1004 to be taken out or moved... but I
don't know much about X...)?

The aforementioned "unlocking of the unlocked mutex" is also evident
in all other code blocks that follow line 1004 (e.g. line 1007 as per
above sample but also in line 1019, 1029 ... 1074)

It seems to lock only once in that method (line 970):

	LockDisplay(dpy);
	switch( supported_request ) {
	    case 1:
	    GetReq(GLXGetFBConfigs,fb_req);
	    fb_req->reqType = priv->majorOpcode;
	    fb_req->glxCode = X_GLXGetFBConfigs;
	    fb_req->screen = i;
	    break;
	
	    case 2:
	    GetReqExtra(GLXVendorPrivateWithReply,
			sz_xGLXGetFBConfigsSGIXReq-sz_xGLXVendorPrivateWithReplyReq,vpreq);
	    sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq;
	    sgi_req->reqType = priv->majorOpcode;
	    sgi_req->glxCode = X_GLXVendorPrivateWithReply;
	    sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX;
	    sgi_req->screen = i;
	    break;

	    case 3:
	    GetReq(GLXGetVisualConfigs,req);
	    req->reqType = priv->majorOpcode;
	    req->glxCode = X_GLXGetVisualConfigs;
	    req->screen = i;
	    break;
 	}

	if (!_XReply(dpy, (xReply*) &reply, 0, False)) {
	    /* Something is busted. Punt. */
	    UnlockDisplay(dpy);
	    FreeScreenConfigs(priv);
	    return GL_FALSE;
	}

	UnlockDisplay(dpy);
	if (!reply.numVisuals) {
	    /* This screen does not support GL rendering */
	    UnlockDisplay(dpy);
	    continue;
	}


Taking out line 1004 ("UnlockDisplay(dpy);") seems to solve my
problem... Otherwise, in my case the double unlocking was taking place
at line 1074 (i think). As a reminder, the following test code now
compiles and runs without geneating "unlocking unlocked mutex" runtime
error:

#include <unistd.h>
#include <pthread.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/extensions/Xext.h>

#include <GL/glx.h>
#include <GL/gl.h>

#include <iostream>
using namespace std;

pthread_mutex_t mutex;

void * blockingThread (void *opaque)
{
	Display *dpy (XOpenDisplay (NULL));
	if (dpy != NULL)
	{
		if (glXQueryExtension(dpy, NULL, NULL))
		{
			cout << "done query extension call" << endl;
			int majorVersionNumber, minorVersionNumber;
			glXQueryVersion (dpy, &majorVersionNumber, &minorVersionNumber);
			cout << "done query version call" << endl;
		}
		sleep (5);
	}
	return NULL;
}

int main ()
{
	XInitThreads ();
	pthread_t blockingThreadId;
	pthread_create (&blockingThreadId, NULL, blockingThread, NULL);
	sleep (10);
	return 0;
}

before, the glXQueryVersion would generate "unlocking unlocked mutex" error.

Kind regards
Leon Zadorin.

On 3/23/07, leon zadorin <leonleon77@gmail.com> wrote:
> Hi all,
>
> well, another "i must be doing something wrong" issue...
>
> here is the quick sample program:
>
> #include <unistd.h>
> #include <pthread.h>
> #include <X11/Xlib.h>
> #include <X11/Xutil.h>
> #include <X11/Xatom.h>
>
> #include <GL/glx.h>
> #include <GL/gl.h>
>
> void * blockingThread (void *opaque)
> {
>         Display *dpy (XOpenDisplay (NULL));
>         if (dpy != NULL)
>         {
>                 if (glXQueryExtension(dpy, NULL, NULL))
>                 {
>                         int majorVersionNumber, minorVersionNumber;
>                         glXQueryVersion (dpy, &majorVersionNumber, &minorVersionNumber);
>                 }
>         }
>         return NULL;
> }
>
> int main ()
> {
>         XInitThreads ();
>         pthread_t blockingThreadId;
>         pthread_create (&blockingThreadId, NULL, blockingThread, NULL);
>         sleep (10);
>
>         return 0;
> }
>
> Here is a rough build description
>
> gcc -I/usr/X11R6/include main.cc -L/usr/X11R6/lib -lGL -lX11 -lstdc++
> -lm -lpthread
>