On Thu, 7 May 2015, David Coppa wrote:
> Can somebody with the necessary skills help me with this?
> 
> $ cd /usr/ports/devel/libinotify/ && make clean fake && make test 
> 
> I remember this used to work... Now, most of the times, the
> 'check_libinotify' process brings the CPU to 100% and it's stuck
> in a sched_yield() loop:

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?

Philip


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