6881066 sporadic hang of thr_suspend
authorRoger A. Faulkner <Roger.Faulkner@Sun.COM>
Thu, 24 Sep 2009 05:17:17 -0700
changeset 10637 f6eac4af74a8
parent 10636 4068d6e64f8c
child 10638 5d19a597329d
6881066 sporadic hang of thr_suspend
usr/src/cmd/mdb/common/modules/libc/libc.c
usr/src/lib/libc/inc/thr_uberdata.h
usr/src/lib/libc/port/threads/rwlock.c
usr/src/lib/libc/port/threads/synch.c
usr/src/lib/libc/port/threads/thr.c
--- a/usr/src/cmd/mdb/common/modules/libc/libc.c	Thu Sep 24 07:49:36 2009 -0400
+++ b/usr/src/cmd/mdb/common/modules/libc/libc.c	Thu Sep 24 05:17:17 2009 -0700
@@ -583,13 +583,14 @@
 	    ulwp.ul_td_evbuf.eventnum,
 	    prt_addr(ulwp.ul_td_evbuf.eventdata, 0));
 
-	HD("td'enable  sync'reg   qtype      cv_wake    usropts");
-	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d ",
+	HD("td'enable  sync'reg   qtype      cv_wake    rtld       usropts");
+	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d ",
 	    OFFSET(ul_td_events_enable),
 	    ulwp.ul_td_events_enable,
 	    ulwp.ul_sync_obj_reg,
 	    ulwp.ul_qtype,
-	    ulwp.ul_cv_wake);
+	    ulwp.ul_cv_wake,
+	    ulwp.ul_rtld);
 	mdb_printf(ulwp.ul_usropts? "0x%x\n" : "%d\n",
 	    ulwp.ul_usropts);
 
--- a/usr/src/lib/libc/inc/thr_uberdata.h	Thu Sep 24 07:49:36 2009 -0400
+++ b/usr/src/lib/libc/inc/thr_uberdata.h	Thu Sep 24 05:17:17 2009 -0700
@@ -609,6 +609,7 @@
 	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 @@
 	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 @@
  * 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);
--- a/usr/src/lib/libc/port/threads/rwlock.c	Thu Sep 24 07:49:36 2009 -0400
+++ b/usr/src/lib/libc/port/threads/rwlock.c	Thu Sep 24 05:17:17 2009 -0700
@@ -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 @@
 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);
--- a/usr/src/lib/libc/port/threads/synch.c	Thu Sep 24 07:49:36 2009 -0400
+++ b/usr/src/lib/libc/port/threads/synch.c	Thu Sep 24 05:17:17 2009 -0700
@@ -2670,25 +2670,30 @@
 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);
 }
 
--- a/usr/src/lib/libc/port/threads/thr.c	Thu Sep 24 07:49:36 2009 -0400
+++ b/usr/src/lib/libc/port/threads/thr.c	Thu Sep 24 05:17:17 2009 -0700
@@ -1785,8 +1785,8 @@
 }
 
 /*
- * 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 @@
 	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 @@
 
 /*
  * Exit a critical section, take deferred actions if necessary.
+ * Called from exit_critical() and from sigon().
  */
 void
 do_exit_critical()
@@ -2155,7 +2157,12 @@
 	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 @@
 	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 @@
 	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 @@
 void
 _sigoff(void)
 {
-	sigoff(curthread);
+	ulwp_t *self = curthread;
+
+	sigoff(self);
 }
 
 void
 _sigon(void)
 {
-	sigon(curthread);
-}
-
-void
-sigon(ulwp_t *self)
-{
-	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