From: guenther Date: Sun, 10 May 2015 18:33:15 +0000 (+0000) Subject: In the child after fork, the dl lock has to be forced as its inner spinlock X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=e0ad4b33be27625a6d90fe45e3344ce322784cf9;p=openbsd In the child after fork, the dl lock has to be forced as its inner spinlock may have been grabbed by another thread in the parent before the fork problem report from dcoppa@, ok kettenis@ --- diff --git a/lib/librthread/rthread.c b/lib/librthread/rthread.c index 72babbf5032..5f9ca87471c 100644 --- a/lib/librthread/rthread.c +++ b/lib/librthread/rthread.c @@ -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 * 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); } } diff --git a/lib/librthread/rthread_fork.c b/lib/librthread/rthread_fork.c index c9086daf595..7bca5b0595f 100644 --- a/lib/librthread/rthread_fork.c +++ b/lib/librthread/rthread_fork.c @@ -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 @@ -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; }