Testing xbmc pvr; libGL threading issues...

Juergen Lock nox at jelal.kn-bremen.de
Fri Oct 14 21:56:56 UTC 2011


Hi!

 I had been playing with opdenkamp's xbmc pvr branch and pipelka's
xvdr xbmc addon and vdr plugin for a little while now, and finally
have something that more or less runs.  One issue that took me a
while to figure out were crashes in libGL when switching live
channels:

(gdb) bt
#0  0x00000008041abca7 in glIsTexture () from /usr/local/lib/libGL.so.1
#1  0x0000000000b2a995 in CLinuxRendererGL::DeleteYV12Texture (
    this=0x8340b8800, index=0) at LinuxRendererGL.cpp:1690
#2  0x0000000000b2eae2 in CLinuxRendererGL::UnInit (this=0x8340b8800)
    at LinuxRendererGL.cpp:1059
#3  0x0000000000b2ed9e in CLinuxRendererGL::PreInit (this=0x8340b8800)
    at LinuxRendererGL.cpp:719
#4  0x0000000000b29049 in CXBMCRenderManager::PreInit (this=0x1546920)
    at RenderManager.cpp:324
#5  0x0000000000b8bf4f in CDVDPlayerVideo::OpenStream (this=0x835400590, 
    hint=@0x7ffffdfcee20) at DVDPlayerVideo.cpp:183
#6  0x0000000000b6d88e in CDVDPlayer::OpenVideoStream (this=0x835400000, 
    iStream=0, source=256) at DVDPlayer.cpp:2891
#7  0x0000000000b79734 in CDVDPlayer::Process (this=0x835400000)
    at DVDPlayer.cpp:1207
#8  0x0000000000f4a74d in CThread::staticThread (data=0x835400010)
    at Thread.cpp:177

turns out libGL keeps thread-local pointers and xbmc called into
libGL (glIsTexture()) from (apparently) a new thread where then
_x86_64_get_dispatch in:

	work/Mesa-7.6.1/src/mesa/x86-64/glapi_x86-64.S

returned NULL and thus the glIsTexture wrapper in the same .S
got a segfault referencing that NULL pointer here:

[...]
        .p2align        4,,15
        .globl  GL_PREFIX(IsTexture)
        .type   GL_PREFIX(IsTexture), @function
GL_PREFIX(IsTexture):
#if defined(GLX_USE_TLS)
        call    _x86_64_get_dispatch at PLT
        movq    2640(%rax), %r11
        jmp     *%r11
#elif defined(PTHREADS)
        pushq   %rdi
        call    _x86_64_get_dispatch at PLT
        popq    %rdi
        movq    2640(%rax), %r11
	^^^^^^^^^^^^^^^^^^^^^^^^ segfault
        jmp     *%r11
#else
[...]

_x86_64_get_dispatch uses pthread_getspecific() and looks like this:

[...]
#elif defined(PTHREADS)

        .extern _glapi_Dispatch
        .extern _gl_DispatchTSD
        .extern pthread_getspecific

        .p2align        4,,15
_x86_64_get_dispatch:
        movq    _gl_DispatchTSD at GOTPCREL(%rip), %rax
        movl    (%rax), %edi
        jmp     pthread_getspecific at PLT

#elif defined(THREADS)
[...]

and some documentation about these thread-local pointers is here:

	work/Mesa-7.6.1/docs/dispatch.html

 After some googling I stumbled across this debian ticket that has a patch:

	http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=536106

so I changed the libGL port's files/patch-src__mesa__x86-64__glapi_x86-64.S
into this:

--------snip------
--- ./src/mesa/x86-64/glapi_x86-64.S.orig	2009-03-13 04:28:49.000000000 +0100
+++ ./src/mesa/x86-64/glapi_x86-64.S	2011-01-28 18:12:18.000000000 +0100
@@ -73,7 +73,12 @@ _x86_64_get_dispatch:
 
 	.p2align	4,,15
 _x86_64_get_dispatch:
-	movq	_gl_DispatchTSD(%rip), %rdi
+	movq	_glapi_Dispatch(%rip), %rax
+	testq	%rax,%rax
+	je	1f
+	ret
+1:	movq	_gl_DispatchTSD at GOTPCREL(%rip), %rax
+	movl	(%rax), %edi
 	jmp	pthread_getspecific at PLT
 
 #elif defined(THREADS)
--------snip------

 That fixed these crashes but now I got other crashes that seem to be
related to messages like:

	Recursive call into r300FlushCmdBufLocked!

(this is using the xorg radeon drivers, the nvidia libGL blob on
the other box crashed in glIsTexture() too but obviously I cannot
easily debug that) - so I looked for another workaround.  What I
finally ended up doing was this patch:
(files/patch-xbmc-cores-VideoRenderers-LinuxRendererGL.cpp)

--- xbmc/cores/VideoRenderers/LinuxRendererGL.cpp.orig
+++ xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -159,6 +159,10 @@ CLinuxRendererGL::CLinuxRendererGL()
   m_rgbPbo = 0;
 
   m_dllSwScale = new DllSwScale;
+
+#ifdef __FreeBSD__
+  m_tid = NULL;
+#endif
 }
 
 CLinuxRendererGL::~CLinuxRendererGL()
@@ -247,6 +251,9 @@ bool CLinuxRendererGL::ValidateRenderTar
       (this->*m_textureCreate)(i);
 
     m_bValidated = true;
+#ifdef __FreeBSD__
+    m_tid = pthread_self();
+#endif
     return true;
   }
   return false;
@@ -716,6 +723,9 @@ unsigned int CLinuxRendererGL::PreInit()
   CSingleLock lock(g_graphicsContext);
   m_bConfigured = false;
   m_bValidated = false;
+#ifdef __FreeBSD__ // XXX Will this leak?  It's needed to avoid crashes... :(
+  if (pthread_self() == m_tid)
+#endif
   UnInit();
   m_resolution = g_guiSettings.m_LookAndFeelResolution;
   if ( m_resolution == RES_WINDOW )

 i.e. I only called into CLinuxRendererGL::UnInit() (where the original
crashes happened) if this was the same thread that created the textures
that CLinuxRendererGL::UnInit() tried to delete.  I don't know if this
will leak memory, textures, or something else so I'd prefer libGL
to be fixed properly...  (And as you might have guessed, this code runs
just fine unpatched on Linux...)

 Anyway, here are the preliminary ports:

	http://people.freebsd.org/~nox/tmp/xbmcpvr-opdenkamp.patch
	(to be applied on top of the current xbmc port)

	http://people.freebsd.org/~nox/tmp/vdr-plugin-xvdr.shar
	vdr plugin to connect to:

	http://people.freebsd.org/~nox/tmp/xbmc-addon-xvdr.shar
	xbmc pvr addon to connect to vdr

 All are git snapshots so likely contain bugs; xbmc pvr has support
for mythtv (and tvheadend) too so you _might_ be able to test that too,
I only tested with vdr.  (The xbmc pvr port at _least_ still needs
the commented out REINPLACE_CMD 's|/usr/local|${LOCALBASE}|g' fixed,
and I also would like to know where the remaining
libXBMC_addon-x86_64-linux.so etc references come from; I had to
symlink e.g. libXBMC_addon-x86_64-freebsd.so to the linux name.)

 Oh and I just saw the vdr-plugin-xvdr port's COMMENT still mentions
vnsi (the old name of the plugin) - will fix that later.

 Thanx,
	Juergen


More information about the freebsd-multimedia mailing list