Dear lists,
I have attached a slightly modified glthreads.c: I have modified it so that
selecting one of its windows and pressing any key will destroy the
associated glx context and subsequently that X window.
This destruction yields, in a very random fashion, one of the three
following symptoms on my Radeon M7 (7500 Mobility) laptop running
4.2.99.902:
1. The longstanding "radeon_vtxfmt.c:1057: radeonVtxfmtUnbindContext:
Assertion vb.context == ctx' failed." assertion error.
2. The infamous drmRadeonCmdBuffer: -22 and then program exit. I am more
concerned about this symptom, because I'm seeing it with a real application
that I'm developing when destroying one of its multiple glx contexts. This
is why I modified glthreads.c in the first place.
3. A good old segfault:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1026 (LWP 712)]
0x404dd042 in _swrast_InvalidateState ()
from /usr/X11R6/lib/modules/dri/radeon_dri.so
(gdb) bt
#0 0x404dd042 in _swrast_InvalidateState ()
from /usr/X11R6/lib/modules/dri/radeon_dri.so
#1 0x4058b6ac in radeonInvalidateState ()
from /usr/X11R6/lib/modules/dri/radeon_dri.so
#2 0x404a6edd in _mesa_update_state ()
from /usr/X11R6/lib/modules/dri/radeon_dri.so
#3 0x4045e0e0 in _mesa_Clear () from /usr/X11R6/lib/modules/dri/radeon_dri.so
#4 0x401132f5 in _ts_Clear () from /usr/X11R6/lib/libGL.so.1
#5 0x08049275 in draw_loop ()
#6 0x0804995a in thread_function ()
#7 0x40337fa5 in pthread_start_thread () from /lib/libpthread.so.0
#8 0x40337fed in pthread_start_thread_event () from /lib/libpthread.so.0
4. X lockup: the mouse moves but can't interact with anything onscreen. The
keyboard is dead.
If you keep on running glthreads with e.g. glthreads -n 3 and destroying a
single context, you should see each of these 4 symptoms at some or other
stage. It would be wonderful if someone with deeper knowledge of the dark
Radeon driver interior could have a look at this.
Compile the attached code with:
gcc -I../include -O3 -ansi -pedantic -fPIC -ffast-math -D_SVID_SOURCE \
-D_BSD_SOURCE -DUSE_XSHM -DPTHREADS -I/usr/X11R6/include glthreads.c \
-L/usr/X11R6/lib -lglut -lGLU -lGL -lm -o glthreads
Thanks,
Charl
--
charl p. botha http://cpbotha.net/ http://visualisation.tudelft.nl/
/* $Id: glthreads.c,v 1.1 2000/07/20 20:12:17 brianp Exp $ */
/* modified by [EMAIL PROTECTED] to destroy current window and context when
* key pressed...
*/
/*
* Copyright (C) 2000 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* This program tests GLX thread safety.
* Command line options:
* -n <num threads> Number of threads to create (default is 2)
* -display <display name> Specify X display (default is :0.0)
*
* Brian Paul 20 July 2000
*/
#if defined(PTHREADS) /* defined by Mesa on Linux and other platforms */
#include <GL/gl.h>
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
/*
* Each window/thread/context:
*/
struct winthread {
Display *Dpy;
int Index;
pthread_t Thread;
Window Win;
GLXContext Context;
float Angle;
int WinWidth, WinHeight;
GLboolean NewSize;
};
#define MAX_WINTHREADS 100
static struct winthread WinThreads[MAX_WINTHREADS];
static int NumWinThreads = 0;
static GLboolean ExitFlag = GL_FALSE;
static void
Error(const char *msg)
{
fprintf(stderr, "Error: %s\n", msg);
exit(1);
}
/* draw a colored cube */
static void
draw_object(void)
{
glPushMatrix();
glScalef(0.75, 0.75, 0.75);
glColor3f(1, 0, 0);
glBegin(GL_POLYGON);
glVertex3f(1, -1, -1);
glVertex3f(1, 1, -1);
glVertex3f(1, 1, 1);
glVertex3f(1, -1, 1);
glEnd();
glColor3f(0, 1, 1);
glBegin(GL_POLYGON);
glVertex3f(-1, -1, -1);
glVertex3f(-1, 1, -1);
glVertex3f(-1, 1, 1);
glVertex3f(-1, -1, 1);
glEnd();
glColor3f(0, 1, 0);
glBegin(GL_POLYGON);
glVertex3f(-1, 1, -1);
glVertex3f( 1, 1, -1);
glVertex3f( 1, 1, 1);
glVertex3f(-1, 1, 1);
glEnd();
glColor3f(1, 0, 1);
glBegin(GL_POLYGON);
glVertex3f(-1, -1, -1);
glVertex3f( 1, -1, -1);
glVertex3f( 1, -1, 1);
glVertex3f(-1, -1, 1);
glEnd();
glColor3f(0, 0, 1);
glBegin(GL_POLYGON);
glVertex3f(-1, -1, 1);
glVertex3f( 1, -1, 1);
glVertex3f( 1, 1, 1);
glVertex3f(-1, 1, 1);
glEnd();
glColor3f(1, 1, 0);
glBegin(GL_POLYGON);
glVertex3f(-1, -1, -1);
glVertex3f( 1, -1, -1);
glVertex3f( 1, 1, -1);
glVertex3f(-1, 1, -1);
glEnd();
glPopMatrix();
}
/* signal resize of given window */
static void
resize(struct winthread *wt, int w, int h)
{
wt->NewSize = GL_TRUE;
wt->WinWidth = w;
wt->WinHeight = h;
}
/*
* We have an instance of this for each thread.
*/
static void
draw_loop(struct winthread *wt)
{
while (!ExitFlag) {
glXMakeCurrent(wt->Dpy, wt->Win, wt->Context);
glEnable(GL_DEPTH_TEST);
if (wt->NewSize) {
GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
glViewport(0, 0, wt->WinWidth, wt->WinHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -2.5);
wt->NewSize = GL_FALSE;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(wt->Angle, 0, 0, 1);
glRotatef(wt->Angle, 1, 0, 0);
glScalef(0.7, 0.7, 0.7);
draw_object();
glPopMatrix();
glXSwapBuffers(wt->Dpy, wt->Win);
wt->Angle += 1.0;
}
}
/*
* The main process thread runs this loop.
*/
static void
event_loop(Display *dpy)
{
while (!ExitFlag) {
static long mask = StructureNotifyMask | ExposureMask | KeyPressMask;
XEvent event;
int i;
for (i = 0; i < NumWinThreads; i++) {
struct winthread *wt = &WinThreads[i];
while (wt->Index >= 0 && XCheckWindowEvent(dpy, wt->Win, mask, &event)) {
if (event.xany.window == wt->Win) {
switch (event.type) {
case ConfigureNotify:
resize(wt, event.xconfigure.width,
event.xconfigure.height);
break;
case KeyPress:
glXDestroyContext(dpy, wt->Context);
XDestroyWindow(dpy, wt->Win);
XSync(dpy, 0);
/* hack so we know not to play with this */
wt->Index = -1;
break;
default:
/*no-op*/ ;
}
}
else {
printf("window mismatch\n");
}
}
}
}
}
/*
* we'll call this once for each thread, before the threads are created.
*/
static void
create_window(struct winthread *wt)
{
Window win;
GLXContext ctx;
int attrib[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None };
int scrnum;
XSetWindowAttributes attr;
unsigned long mask;
Window root;
XVisualInfo *visinfo;
int width = 80, height = 80;
int xpos = (wt->Index % 10) * 90;
int ypos = (wt->Index / 10) * 100;
scrnum = DefaultScreen(wt->Dpy);
root = RootWindow(wt->Dpy, scrnum);
visinfo = glXChooseVisual(wt->Dpy, scrnum, attrib);
if (!visinfo) {
Error("Unable to find RGB, Z, double-buffered visual");
}
/* window attributes */
attr.background_pixel = 0;
attr.border_pixel = 0;
attr.colormap = XCreateColormap(wt->Dpy, root, visinfo->visual, AllocNone);
attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
win = XCreateWindow(wt->Dpy, root, xpos, ypos, width, height,
0, visinfo->depth, InputOutput,
visinfo->visual, mask, &attr);
if (!win) {
Error("Couldn't create window");
}
{
XSizeHints sizehints;
sizehints.x = xpos;
sizehints.y = ypos;
sizehints.width = width;
sizehints.height = height;
sizehints.flags = USSize | USPosition;
XSetNormalHints(wt->Dpy, win, &sizehints);
XSetStandardProperties(wt->Dpy, win, "glthreads", "glthreads",
None, (char **)NULL, 0, &sizehints);
}
ctx = glXCreateContext(wt->Dpy, visinfo, NULL, True);
if (!ctx) {
Error("Couldn't create GLX context");
}
XMapWindow(wt->Dpy, win);
XSync(wt->Dpy, 0);
/* save the info for this window/context */
wt->Win = win;
wt->Context = ctx;
wt->Angle = 0.0;
wt->WinWidth = width;
wt->WinHeight = height;
wt->NewSize = GL_TRUE;
}
/*
* Called by pthread_create()
*/
static void *
thread_function(void *p)
{
struct winthread *wt = (struct winthread *) p;
draw_loop(wt);
return NULL;
}
/*
* called before exit to wait for all threads to finish
*/
static void
clean_up(void)
{
int i;
/* wait for threads to finish */
for (i = 0; i < NumWinThreads; i++) {
pthread_join(WinThreads[i].Thread, NULL);
}
for (i = 0; i < NumWinThreads; i++) {
glXDestroyContext(WinThreads[i].Dpy, WinThreads[i].Context);
XDestroyWindow(WinThreads[i].Dpy, WinThreads[i].Win);
}
}
int
main(int argc, char *argv[])
{
char *displayName = ":0.0";
int numThreads = 2;
Display *dpy;
int i;
Status threadStat;
if (argc == 1) {
printf("threadgl: test of GL thread safety (any key = exit)\n");
printf("Usage:\n");
printf(" threadgl [-display dpyName] [-n numthreads]\n");
}
else {
int i;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
displayName = argv[i + 1];
i++;
}
else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
numThreads = atoi(argv[i + 1]);
if (numThreads < 1)
numThreads = 1;
else if (numThreads > MAX_WINTHREADS)
numThreads = MAX_WINTHREADS;
i++;
}
}
}
/*
* VERY IMPORTANT: call XInitThreads() before any other Xlib functions.
*/
threadStat = XInitThreads();
if (threadStat) {
printf("XInitThreads() returned %d (success)\n", (int) threadStat);
}
else {
printf("XInitThreads() returned 0 (failure- this program may fail)\n");
}
dpy = XOpenDisplay(displayName);
if (!dpy) {
fprintf(stderr, "Unable to open display %s\n", displayName);
return -1;
}
NumWinThreads = numThreads;
/* Create the GLX windows and contexts */
for (i = 0; i < numThreads; i++) {
WinThreads[i].Dpy = dpy;
WinThreads[i].Index = i;
create_window(&WinThreads[i]);
}
/* Create the threads */
for (i = 0; i < numThreads; i++) {
pthread_create(&WinThreads[i].Thread, NULL, thread_function,
(void*) &WinThreads[i]);
printf("Created Thread %p\n", WinThreads[i].Thread);
}
event_loop(dpy);
clean_up();
XCloseDisplay(dpy);
return 0;
}
#else /* PTHREADS */
#include <stdio.h>
int
main(int argc, char *argv[])
{
printf("Sorry, this program wasn't compiled with PTHREADS defined.\n");
return 0;
}
#endif /* PTHREADS */