diff options
author | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-03-20 00:47:24 +0000 |
---|---|---|
committer | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-03-20 00:47:24 +0000 |
commit | f20d2e0042fa909488b83bbb2a0f664c2d1a7299 (patch) | |
tree | 027d26c619f500e7fb6ba32b875fc769cb0e11ea | |
parent | 3878465307b8010631b215296da1e11a958e1b5a (diff) |
Permit recursive locking in _rthread_dl_lock(), as an so's destructor
may need to call dlclose().
problem observed by Antti Harri (iku at openbsd.fi), ok kurt@
-rw-r--r-- | lib/librthread/rthread.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/lib/librthread/rthread.c b/lib/librthread/rthread.c index 110c8bab268..72224990978 100644 --- a/lib/librthread/rthread.c +++ b/lib/librthread/rthread.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread.c,v 1.58 2012/03/14 21:23:37 guenther Exp $ */ +/* $OpenBSD: rthread.c,v 1.59 2012/03/20 00:47:23 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -580,15 +580,55 @@ _thread_dump_info(void) } #if defined(__ELF__) && defined(PIC) +/* + * _rthread_dl_lock() provides the locking for dlopen(), dlclose(), and + * the function called via atexit() to invoke all destructors. The latter + * two call shared-object destructors, which may need to call dlclose(), + * so this lock needs to permit recursive locking. + * The specific code here was extracted from _rthread_mutex_lock() and + * pthread_mutex_unlock() and simplified to use the static variables. + */ void _rthread_dl_lock(int what) { static _spinlock_lock_t lock = _SPINLOCK_UNLOCKED; + static pthread_t owner = NULL; + static struct pthread_queue lockers = TAILQ_HEAD_INITIALIZER(lockers); + static int count = 0; if (what == 0) + { + pthread_t self = pthread_self(); + + /* lock, possibly recursive */ _spinlock(&lock); - else + if (owner == NULL) { + owner = self; + } else if (owner != self) { + TAILQ_INSERT_TAIL(&lockers, self, waiting); + while (owner != self) { + __thrsleep(self, 0, NULL, &lock, NULL); + _spinlock(&lock); + } + } + count++; _spinunlock(&lock); + } + else + { + /* unlock, possibly recursive */ + if (--count == 0) { + pthread_t next; + + _spinlock(&lock); + owner = next = TAILQ_FIRST(&lockers); + if (next != NULL) + TAILQ_REMOVE(&lockers, next, waiting); + _spinunlock(&lock); + if (next != NULL) + __thrwakeup(next, 1); + } + } } void |