On Sat, 09 May 2015, Philip Guenther wrote:

> Looks like the problem is that while one thread is calling vfork(), 
> another thread does something that acquires the spinlock inside 
> rthread_dl_lock() (probably another vfork).  The child of the vfork tries 
> to acquire the spinlock so that it can release the recursive lock itself 
> and spins forever.  The solution is to have the child reset that lock.  
> I'm unable to reproduce after applying the diff below.
> 
> oks?
> 

With your diff applied, the test suite from latest libinotify-kqueue's
git snapshot (which was even more prone to hangs than libinotify-20141104
currently in our ports tree) also runs w/o problems.

Thanks a lot Philip!
David

> Index: rthread.c
> ===================================================================
> RCS file: /data/src/openbsd/src/lib/librthread/rthread.c,v
> retrieving revision 1.81
> diff -u -p -r1.81 rthread.c
> --- rthread.c 29 Apr 2015 06:01:37 -0000      1.81
> +++ rthread.c 9 May 2015 23:22:25 -0000
> @@ -671,8 +671,7 @@ _rthread_dl_lock(int what)
>       static struct pthread_queue lockers = TAILQ_HEAD_INITIALIZER(lockers);
>       static int count = 0;
>  
> -     if (what == 0)
> -     {
> +     if (what == 0) {
>               pthread_t self = pthread_self();
>  
>               /* lock, possibly recursive */
> @@ -689,9 +688,7 @@ _rthread_dl_lock(int what)
>               }
>               count++;
>               _spinunlock(&lock);
> -     }
> -     else
> -     {
> +     } else if (what == 1) {
>               /* unlock, possibly recursive */
>               if (--count == 0) {
>                       pthread_t next;
> @@ -704,6 +701,12 @@ _rthread_dl_lock(int what)
>                       if (next != NULL)
>                               __thrwakeup(next, 1);
>               }
> +     } else {
> +             /* reinit: used in child after fork to clear the queue */
> +             lock = _SPINLOCK_UNLOCKED_ASSIGN;
> +             if (--count == 0)
> +                     owner = NULL;
> +             TAILQ_INIT(&lockers);
>       }
>  }
>  
> Index: rthread_fork.c
> ===================================================================
> RCS file: /data/src/openbsd/src/lib/librthread/rthread_fork.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 rthread_fork.c
> --- rthread_fork.c    7 Apr 2015 01:27:07 -0000       1.11
> +++ rthread_fork.c    9 May 2015 23:12:01 -0000
> @@ -105,12 +105,12 @@ _dofork(int is_vfork)
>       _thread_malloc_unlock();
>       _thread_atexit_unlock();
>  
> +     if (newid == 0) {
>  #if defined(__ELF__)
> -     if (_DYNAMIC)
> -             _rthread_dl_lock(1);
> +             /* reinitialize the lock in the child */
> +             if (_DYNAMIC)
> +                     _rthread_dl_lock(2);
>  #endif
> -
> -     if (newid == 0) {
>               /* update this thread's structure */
>               me->tid = getthrid();
>               me->donesem.lock = _SPINLOCK_UNLOCKED_ASSIGN;
> @@ -128,6 +128,10 @@ _dofork(int is_vfork)
>               /* single threaded now */
>               __isthreaded = 0;
>       }
> +#if defined(__ELF__)
> +     else if (_DYNAMIC)
> +             _rthread_dl_lock(1);
> +#endif
>       return newid;
>  }
>  

Reply via email to