summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc
diff options
context:
space:
mode:
authorRoger A. Faulkner <Roger.Faulkner@Sun.COM>2009-09-24 05:17:17 -0700
committerRoger A. Faulkner <Roger.Faulkner@Sun.COM>2009-09-24 05:17:17 -0700
commite54ab87fbe2dfd9466e91d29075aa6d56c36f6ff (patch)
treeddab61e0784052a502d0c17efff5612d70a1a86a /usr/src/lib/libc
parent2cd7c447890e4fe78b7beb498903440e9122ee80 (diff)
downloadillumos-joyent-e54ab87fbe2dfd9466e91d29075aa6d56c36f6ff.tar.gz
6881066 sporadic hang of thr_suspend
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r--usr/src/lib/libc/inc/thr_uberdata.h7
-rw-r--r--usr/src/lib/libc/port/threads/rwlock.c8
-rw-r--r--usr/src/lib/libc/port/threads/synch.c13
-rw-r--r--usr/src/lib/libc/port/threads/thr.c37
4 files changed, 38 insertions, 27 deletions
diff --git a/usr/src/lib/libc/inc/thr_uberdata.h b/usr/src/lib/libc/inc/thr_uberdata.h
index d6ae1b603e..981a41ef8d 100644
--- a/usr/src/lib/libc/inc/thr_uberdata.h
+++ b/usr/src/lib/libc/inc/thr_uberdata.h
@@ -609,6 +609,7 @@ typedef struct ulwp {
char ul_sync_obj_reg; /* tdb_sync_obj_register() */
char ul_qtype; /* MX or CV */
char ul_cv_wake; /* != 0: just wake up, don't requeue */
+ int ul_rtld; /* thread is running inside ld.so.1 */
int ul_usropts; /* flags given to thr_create() */
void *(*ul_startpc)(void *); /* start func (thr_create()) */
void *ul_startarg; /* argument for start function */
@@ -1021,6 +1022,7 @@ typedef struct ulwp32 {
char ul_sync_obj_reg; /* tdb_sync_obj_register() */
char ul_qtype; /* MX or CV */
char ul_cv_wake; /* != 0: just wake up, don't requeue */
+ int ul_rtld; /* thread is running inside ld.so.1 */
int ul_usropts; /* flags given to thr_create() */
caddr32_t ul_startpc; /* start func (thr_create()) */
caddr32_t ul_startarg; /* argument for start function */
@@ -1254,7 +1256,10 @@ extern void do_exit_critical(void);
* of the signal mask must also be deferred.
*/
#define sigoff(self) (self->ul_sigdefer++)
-extern void sigon(ulwp_t *);
+#define sigon(self) \
+ (void) ((--self->ul_sigdefer == 0 && \
+ self->ul_curplease && self->ul_critical == 0)? \
+ (do_exit_critical(), 0) : 0)
/* these are exported functions */
extern void _sigoff(void);
diff --git a/usr/src/lib/libc/port/threads/rwlock.c b/usr/src/lib/libc/port/threads/rwlock.c
index 9698eab7f8..80b6c29f0f 100644
--- a/usr/src/lib/libc/port/threads/rwlock.c
+++ b/usr/src/lib/libc/port/threads/rwlock.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -239,13 +239,15 @@ rwlock_init(rwlock_t *rwlp, int type, void *arg)
int
rwlock_destroy(rwlock_t *rwlp)
{
+ ulwp_t *self = curthread;
+
/*
* Once destroyed, we can no longer be holding a read or write lock.
* We can do nothing about other threads that are holding read locks.
*/
- sigoff(curthread);
+ sigoff(self);
rwl_entry(rwlp)->rd_count = 0;
- sigon(curthread);
+ sigon(self);
rwlp->rwlock_magic = 0;
tdb_sync_obj_deregister(rwlp);
return (0);
diff --git a/usr/src/lib/libc/port/threads/synch.c b/usr/src/lib/libc/port/threads/synch.c
index 91b4e960f8..9fac80b0f8 100644
--- a/usr/src/lib/libc/port/threads/synch.c
+++ b/usr/src/lib/libc/port/threads/synch.c
@@ -2670,25 +2670,30 @@ lmutex_unlock(mutex_t *mp)
void
sig_mutex_lock(mutex_t *mp)
{
- sigoff(curthread);
+ ulwp_t *self = curthread;
+
+ sigoff(self);
(void) mutex_lock(mp);
}
void
sig_mutex_unlock(mutex_t *mp)
{
+ ulwp_t *self = curthread;
+
(void) mutex_unlock(mp);
- sigon(curthread);
+ sigon(self);
}
int
sig_mutex_trylock(mutex_t *mp)
{
+ ulwp_t *self = curthread;
int error;
- sigoff(curthread);
+ sigoff(self);
if ((error = mutex_trylock(mp)) != 0)
- sigon(curthread);
+ sigon(self);
return (error);
}
diff --git a/usr/src/lib/libc/port/threads/thr.c b/usr/src/lib/libc/port/threads/thr.c
index 5cfcb2daef..31c28233f2 100644
--- a/usr/src/lib/libc/port/threads/thr.c
+++ b/usr/src/lib/libc/port/threads/thr.c
@@ -1785,8 +1785,8 @@ force_continue(ulwp_t *ulwp)
}
/*
- * Suspend an lwp with lwp_suspend(), then move it to a safe
- * point, that is, to a point where ul_critical is zero.
+ * Suspend an lwp with lwp_suspend(), then move it to a safe point,
+ * that is, to a point where ul_critical and ul_rtld are both zero.
* On return, the ulwp_lock() is dropped as with ulwp_unlock().
* If 'link_dropped' is non-NULL, then 'link_lock' is held on entry.
* If we have to drop link_lock, we store 1 through link_dropped.
@@ -1823,7 +1823,8 @@ safe_suspend(ulwp_t *ulwp, uchar_t whystopped, int *link_dropped)
spin_lock_clear(&ulwp->ul_spinlock);
top:
- if (ulwp->ul_critical == 0 || ulwp->ul_stopping) {
+ if ((ulwp->ul_critical == 0 && ulwp->ul_rtld == 0) ||
+ ulwp->ul_stopping) {
/* thread is already safe */
ulwp->ul_stop |= whystopped;
} else {
@@ -2147,6 +2148,7 @@ thr_kill(thread_t tid, int sig)
/*
* Exit a critical section, take deferred actions if necessary.
+ * Called from exit_critical() and from sigon().
*/
void
do_exit_critical()
@@ -2155,7 +2157,12 @@ do_exit_critical()
int sig;
ASSERT(self->ul_critical == 0);
- if (self->ul_dead)
+
+ /*
+ * Don't suspend ourself or take a deferred signal while dying
+ * or while executing inside the dynamic linker (ld.so.1).
+ */
+ if (self->ul_dead || self->ul_rtld)
return;
while (self->ul_pleasestop ||
@@ -2214,6 +2221,7 @@ _ti_bind_guard(int flags)
self->ul_bindflags |= bindflag;
if ((flags & (THR_FLG_NOLOCK | THR_FLG_REENTER)) == THR_FLG_NOLOCK) {
sigoff(self); /* see no signals while holding ld_lock */
+ self->ul_rtld++; /* don't suspend while in ld.so.1 */
(void) mutex_lock(&udp->ld_lock);
}
enter_critical(self);
@@ -2239,6 +2247,7 @@ _ti_bind_clear(int flags)
if ((flags & (THR_FLG_NOLOCK | THR_FLG_REENTER)) == THR_FLG_NOLOCK) {
if (MUTEX_OWNED(&udp->ld_lock, self)) {
(void) mutex_unlock(&udp->ld_lock);
+ self->ul_rtld--;
sigon(self); /* reenable signals */
}
}
@@ -2275,28 +2284,18 @@ _ti_critical(void)
void
_sigoff(void)
{
- sigoff(curthread);
-}
+ ulwp_t *self = curthread;
-void
-_sigon(void)
-{
- sigon(curthread);
+ sigoff(self);
}
void
-sigon(ulwp_t *self)
+_sigon(void)
{
- int sig;
+ ulwp_t *self = curthread;
ASSERT(self->ul_sigdefer > 0);
- if (--self->ul_sigdefer == 0) {
- if ((sig = self->ul_cursig) != 0 && self->ul_critical == 0) {
- self->ul_cursig = 0;
- take_deferred_signal(sig);
- ASSERT(self->ul_cursig == 0);
- }
- }
+ sigon(self);
}
int