mysterious hang in pthread_create

David Xu davidxu at freebsd.org
Mon Sep 1 08:08:35 UTC 2008


Kostik Belousov wrote:
> Ok, let me to tell the whole story. I am sure that in fact you know
> it better then me.
> 
> Assuming libthr is the only threading library, there are two locking
> implementations for the rtld: 'default' and the one supplied by libthr.
> On the first call to pthread_create(), libthr calls _rtld_thread_init()
> to substitute the default by the implementation from libthr.
> 
> In fact, default implementation is broken from my point of view. For
> instance, thread_flag update is not atomic. Moreover, it does not
> correctly handles sequential acquision of several locks, due
> to thread_flag.
> 
> The dl_iterate_phdr() function, called by gcc exception handling support
> code, does exactly this. It acquires rtld_phdr_lock, then rtld_bind_lock.
> [I shall admit it does this after my change]. In particular, this would
> leave the bit for the bind lock set in the thread_flag.
> 
> Andriy' example throw the exception and calls dl_iterate_phdr() before
> first thread is created. On thread creation, _rtld_thread_init() is
> called, that tries to move the locks according to thread_flag. This is
> the cause for the reported wlock acquisition.
> 
> I do not want to change anything in the default rtld locking. It is
> disfunctional from the time libc_r is gone, and I think it would be
> better to make it nop. My change makes the image that is linked with
> libthr, to consistently use libthr locks.

The ancient bug is in rtld, rlock_acquire() and wlock_acquire() test
thread_flag as a boolean value, because pt_iterate_phdr() tries to
lock two locks at same time, this test will always fail once it
acquired first lock.

The following silly patch fixes the problem Andriy encountered:

Index: rtld_lock.c
===================================================================
--- rtld_lock.c	(版本 182594)
+++ rtld_lock.c	(工作副本)
@@ -184,7 +184,7 @@
  int
  rlock_acquire(rtld_lock_t lock)
  {
-	if (thread_mask_set(lock->mask)) {
+	if (thread_mask_set(lock->mask) & lock->mask) {
  	    dbg("rlock_acquire: recursed");
  	    return (0);
  	}
@@ -195,7 +195,7 @@
  int
  wlock_acquire(rtld_lock_t lock)
  {
-	if (thread_mask_set(lock->mask)) {
+	if (thread_mask_set(lock->mask) & lock->mask) {
  	    dbg("wlock_acquire: recursed");
  	    return (0);
  	}


Regards,
David Xu



More information about the freebsd-threads mailing list