Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Jan 2010 15:28:35 +0900 (JST)
From:      Kohji Okuno <okuno.kohji@jp.panasonic.com>
To:        freebsd-current@freebsd.org
Cc:        okuno.kohji@jp.panasonic.com
Subject:   Re: Bug about sched_4bsd?
Message-ID:  <20100117.152835.119882392487126976.okuno.kohji@jp.panasonic.com>
In-Reply-To: <20100117.142200.321689433999177718.okuno.kohji@jp.panasonic.com>
References:  <20100117.142200.321689433999177718.okuno.kohji@jp.panasonic.com>

next in thread | previous in thread | raw e-mail | index | archive | help
----Next_Part(Sun_Jan_17_15_28_35_2010_654)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hello,

Could you check sched_4bsd.patch, please?

--
Best regards,
 Kohji Okuno.

> Hello, 
> 
> I think that sched_4bsd.c:sched_switch() has a problem.
> 
> 
> I encounterd the problem that a process could not exit. 
> That process has multi threads and p_flag was as below.
> 
>  p_flag : (P_INMEM|P_STOPPED_SINGLE|P_EXEC|P_SINGLE_EXIT|P_PPWAIT|P_CONTROLT)
> 
> 
> One thread (THREAD A) was suspended as below.
>  sched_switch()
>  mi_switch()
>  thread_suspend_switch()
>  thread_single()
>  exit1()
>  sys_exit()
> 
>  td_flags : TDF_NEEDSIGCHK|TDF_ASTPENDING|TDF_CANSWAP|TDF_INMEM
> 
> 
> Another thread (THREAD B) was sleeping as below.
>  sched_switch()
>  mi_switch()
>  sleepq_switch()
>  sleepq_catch_signals()
>  sleepq_wait_sig()
>  _cv_wait_sig()
>  seltdwait()
>  kern_select()
>  select()
> 
>  td_flags : TDF_CANSWAP|TDF_SINTR|TDF_INMEM
> 
> 
> That process could not exit, because THREAD B did not execute
> "thread_suspend_check()" and THREAD A had been suspended.
> 
> 
> I think that the race condition had occurred about td_flags as below.
> 
> In sched_switch(), when td->td_lock is not &sched_lock, td->td_lock
> will be unlocked as shown below. And then, td->td_flags will change
> without td->td_lock.
> 
> 
> <<THREAD A>>
>   kern_thread.c:
>   int
>   thread_single(int mode)
>   {
>           ...
> 
>           thread_lock(td2);
>           td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
>           
>    *** I think that td2 specified THREAD B in this time.
>       
> <<THREAD B>>
>   sched_4bsd.c:
>   void
>   sched_switch(struct thread *td, struct thread *newtd, int flags)
>   {
>           ...
> 
>           /*
>            * Switch to the sched lock to fix things up and pick
>            * a new thread.
>            */
>           if (td->td_lock != &sched_lock) {
>                   mtx_lock_spin(&sched_lock);
>                   thread_unlock(td);
>           }
> 
>    *** I think that td_lock was sleepqueue_chagin->sc_lock.
>           ...
> 
>           td->td_lastcpu = td->td_oncpu;
>           td->td_flags &= ~TDF_NEEDRESCHED;
>           td->td_owepreempt = 0;
>           td->td_oncpu = NOCPU;
> 
> --
> Thanks,
>  Kohji Okuno.
> 
> _______________________________________________
> freebsd-current@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-current
> To unsubscribe, send any mail to "freebsd-current-unsubscribe@freebsd.org"

----Next_Part(Sun_Jan_17_15_28_35_2010_654)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="sched_4bsd.patch"

diff --git a/kern/sched_4bsd.c b/kern/sched_4bsd.c
index 2a8c442..5602493 100644
--- a/kern/sched_4bsd.c
+++ b/kern/sched_4bsd.c
@@ -269,8 +269,18 @@ maybe_resched(struct thread *td)
 {
 
 	THREAD_LOCK_ASSERT(td, MA_OWNED);
+#if 1	/* Added */
+	if (td->td_lock != &sched_lock) {
+		mtx_lock_spin(&sched_lock);
+	}
+#endif
 	if (td->td_priority < curthread->td_priority)
 		curthread->td_flags |= TDF_NEEDRESCHED;
+#if 1	/* Added */
+	if (td->td_lock != &sched_lock) {
+		mtx_unlock_spin(&sched_lock);
+	}
+#endif
 }
 
 /*
@@ -928,6 +938,12 @@ sched_switch(struct thread *td, struct thread *newtd, int flags)
 
 	THREAD_LOCK_ASSERT(td, MA_OWNED);
 
+#if 1	/* Moved */
+	td->td_lastcpu = td->td_oncpu;
+	td->td_flags &= ~TDF_NEEDRESCHED;
+	td->td_owepreempt = 0;
+	td->td_oncpu = NOCPU;
+#endif
 	/* 
 	 * Switch to the sched lock to fix things up and pick
 	 * a new thread.
@@ -943,10 +959,12 @@ sched_switch(struct thread *td, struct thread *newtd, int flags)
 	if (newtd)
 		newtd->td_flags |= (td->td_flags & TDF_NEEDRESCHED);
 
+#if 0	/* Original */
 	td->td_lastcpu = td->td_oncpu;
 	td->td_flags &= ~TDF_NEEDRESCHED;
 	td->td_owepreempt = 0;
 	td->td_oncpu = NOCPU;
+#endif
 
 	/*
 	 * At the last moment, if this thread is still marked RUNNING,

----Next_Part(Sun_Jan_17_15_28_35_2010_654)----




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100117.152835.119882392487126976.okuno.kohji>