[xml] threading and xmlReadFile



I am relatively new to libxml2, and I've stumbled across an issue around xmlReadFile and threading.  I am running on x86_64-linux, and I built and installed libxml2 myself, ensuring that the build was configured with --with-threads.  I am coding in C++11, using the C++11 thread package, which is itself implemented in terms of pthreads in g++4.6, which I'm currently using.  I've examined the bug database, and I've seen nothing to imply this general of a problem with threads and libxml2 exists.

I am seeing very occasional deadlock in an application with four threads—one main thread, which spawns three child threads, each of which attempts to parse a remote RSS document, as with:

void RSSFeed::parse() {
    xmlDocPtr doc = xmlReadFile(url.c_str(), /* encoding = */ NULL, XML_PARSE_NOBLANKS);
    // more code that's never reached

I know we're in deadlock, because I can load the process in gdb and generate the following:

(gdb) info threads
  Id   Target Id         Frame 
  4    Thread 0x7f0afb155700 (LWP 25901) "news-aggregator" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  3    Thread 0x7f0afa954700 (LWP 25902) "news-aggregator" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  2    Thread 0x7f0afa153700 (LWP 25903) "news-aggregator" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
* 1    Thread 0x7f0afc8aa740 (LWP 25900) "news-aggregator" 0x00007f0afc4a2148 in pthread_join (threadid=139685138880256, thread_return=0x0) at pthread_join.c:89

I did full backtraces of threads 2, 3, and 4 to confirm that each is attempting to pull a different XML file, each of which looks like this:

(gdb) thread 2
[Switching to thread 2 (Thread 0x7f0afa153700 (LWP 25903))]
#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
162     ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: No such file or directory.
(gdb) bt
#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
#1  0x00007f0afc1e5d23 in xmlRMutexLock () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#2  0x00007f0afc1e20b9 in ?? () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#3  0x00007f0afc1e2648 in ?? () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#4  0x00007f0afc1e35ff in xmlACatalogResolve () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#5  0x00007f0afc19d7e3 in ?? () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#6  0x00007f0afc1a0354 in ?? () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#7  0x00007f0afc1a01df in xmlLoadExternalEntity () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#8  0x00007f0afc186b36 in xmlCreateURLParserCtxt () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#9  0x00007f0afc18cdaa in xmlReadFile () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
#10 0x000000000040b222 in ?? ()
#11 0x00000000004031d9 in ?? ()
#12 0x000000000040389a in ?? ()
#13 0x0000000000405e93 in ?? ()
#14 0x0000000000405e1d in ?? ()
#15 0x0000000000405cac in ?? ()
#16 0x00007f0afbeaac78 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#17 0x00007f0afc4a0e9a in start_thread (arg=0x7f0afa153700) at pthread_create.c:308
#18 0x00007f0afb95d4bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#19 0x0000000000000000 in ?? ()
 
Frame 7's rbx register can be used to confirm the URL strings are different for each thread, so no two threads are unintentionally racing to parse the same remote RSS feed.

(gdb) frame 7
#7  0x00007f0afc1a01df in xmlLoadExternalEntity () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
(gdb) print (char *)$rbx
(gdb) thread 3
[Switching to thread 3 (Thread 0x7f0afa954700 (LWP 25902))]
#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
162     in ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
(gdb) frame 7
#7  0x00007f0afc1a01df in xmlLoadExternalEntity () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
(gdb) print (char *)$rbx
(gdb) thread 4
[Switching to thread 4 (Thread 0x7f0afb155700 (LWP 25901))]
#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
162     in ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
(gdb) frame 7
#7  0x00007f0afc1a01df in xmlLoadExternalEntity () from /usr/lib/x86_64-linux-gnu/libxml2.so.2
(gdb) print (char *)$rbx

Of course, xmlRMutexLock and pthread_cond_wait are each at the bottom of the three thread stacks, so my (hopefully not incorrect) assumption is that they are all waiting to acquire the same mutex.

This happens very rarely, but I'm assuming it's happening because of a race I'm not protecting against.

I'd be grateful if someone sees an obvious omission or error in my thinking.

Thanks,
Jerry






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]