Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Sep 2004 18:14:17 -0400
From:      Stephan Uphoff <ups@tree.com>
To:        John Baldwin <jhb@FreeBSD.org>
Cc:        "freebsd-arch@freebsd.org" <freebsd-arch@FreeBSD.org>
Subject:   Re: scheduler (sched_4bsd) questions
Message-ID:  <1096496057.3733.2163.camel@palm.tree.com>
In-Reply-To: <200409291652.29990.jhb@FreeBSD.org>
References:  <1095468747.31297.241.camel@palm.tree.com> <1096477932.3733.1471.camel@palm.tree.com> <1096489576.3733.1868.camel@palm.tree.com> <200409291652.29990.jhb@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 2004-09-29 at 16:52, John Baldwin wrote:
> > > OK - here is a crude patch to fix some problems with mutex priority
> > > inheritance. My theory is that the clock thread gets stuck waiting on
> > > GIANT.
> > >
> > > During release/acquisition of a contested sleep mutex there are a few
> > > windows where a task can be preempted when actions (waking up blocked
> > > threads, ownership of the mutex, ..) need to be atomic as far as
> > > scheduling is concerned. Otherwise priority inheritance may fail. The
> > > patch uses critical_enter/critical_exit to protect these regions against
> > > preemption.
> > >
> > > It would be great if could run this in addition to the other patches.
> 
> turnstile_claim() doesn't make any threads runnable and thus can't preempt.
> The other place is supposed to preempt, and it should be ok to do so.  Note 
> that since the turnstile chain lock is held, that includes a nested critical 
> section and any preemption will be deferred until the turnstile lock is 
> released via turnstile_release which happens in the middle of 
> turnstile_unpend() after it has finished building a list of all the threads 
> to be made runnable so that the turnstile object can be re-used safely.  I 
> don't think this patch will make much of a difference (if any).  Can you 
> provide a description of a case where you think the priority inheritance can 
> fail if turnstile_unpend() doesn't run in a nested critical section?

This is a bit of a mind bender.
I hope you have some aspirins close by ;-)

Thread A holds a mutex x contested by Thread B and has priority pri(A).
Thread B holds a mutex y.
There is a thread C with priority pri(C) with pri(C) < pri(A).

Thread A is in the process of releasing x.
It removes thread B from the turnstile and holds a pointer to B in a
private list.
Thread A sets the owner of the turnstile to NULL and releases all spin
locks. ( mtx_unlock_spin(&tc->tc_lock); line 148)
This means interrupts are now enabled.

An interrupt occurs (or is already pending) and the interrupt handler
puts the associated interrupt thread I on the run queue.
This causes a preemption from A to I.
The interrupt thread I tries to acquire mutex y owned by B and blocks.
I donates its priority to B - but inheritance stops at B.
The next thread with the best priority is C and the cpu switches to C.
However B needs A to run to make it to the run-queue.

If y is GIANT and I is the clock thread C could run forever in userspace
without being interrupted.

There is another scenario that does not require an interrupt (preemption
in setrunqueue(td, SRQ_BORING), two blocked threads ...).

I was looking at the MUTEX_WAKE_ALL undefined case when I used the
critical section for turnstile_claim().
However there are bigger problems with MUTEX_WAKE_ALL undefined
so you are right - the critical section for turnstile_claim is pretty
useless.

	Stephan



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