In the child after fork, the dl lock has to be forced as its inner spinlock
authorguenther <guenther@openbsd.org>
Sun, 10 May 2015 18:33:15 +0000 (18:33 +0000)
committerguenther <guenther@openbsd.org>
Sun, 10 May 2015 18:33:15 +0000 (18:33 +0000)
may have been grabbed by another thread in the parent before the fork

problem report from dcoppa@, ok kettenis@

lib/librthread/rthread.c
lib/librthread/rthread_fork.c

index 72babbf..5f9ca87 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rthread.c,v 1.81 2015/04/29 06:01:37 guenther Exp $ */
+/*     $OpenBSD: rthread.c,v 1.82 2015/05/10 18:33:15 guenther Exp $ */
 /*
  * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
  * All Rights Reserved.
@@ -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 c9086da..7bca5b0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rthread_fork.c,v 1.11 2015/04/07 01:27:07 guenther Exp $ */
+/*     $OpenBSD: rthread_fork.c,v 1.12 2015/05/10 18:33:15 guenther Exp $ */
 
 /*
  * Copyright (c) 2008 Kurt Miller <kurt@openbsd.org>
@@ -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;
 }