rtprio_thread trouble

John Baldwin jhb at freebsd.org
Wed Mar 6 15:38:08 UTC 2013


On Thursday, February 28, 2013 2:59:16 pm Ian Lepore wrote:
> On Tue, 2013-02-26 at 15:29 -0500, John Baldwin wrote:
> > On Friday, February 22, 2013 2:06:00 pm Ian Lepore wrote:
> > > I ran into some trouble with rtprio_thread() today.  I have a worker
> > > thread that I want to run at idle priority most of the time, but if it
> > > falls too far behind I'd like to bump it back up to regular timeshare
> > > priority until it catches up.  In a worst case, the system is
> > > continuously busy and something scheduled at idle priority is never
> > > going to run (for some definition of 'never').  
> > > 
> > > What I found is that in this worst case, even after my main thread has
> > > used rtprio_thread() to change the worker thread back to
> > > RTP_PRIO_NORMAL, the worker thread never gets scheduled.  This is with
> > > the 4BSD scheduler but it appears that the same would be the case with
> > > ULE, based on code inspection.  I find that this fixes it for 4BSD, and
> > > I think the same would be true for ULE...
> > > 
> > > --- a/sys/kern/sched_4bsd.c	Wed Feb 13 12:54:36 2013 -0700
> > > +++ b/sys/kern/sched_4bsd.c	Fri Feb 22 11:55:35 2013 -0700
> > > @@ -881,6 +881,9 @@ sched_user_prio(struct thread *td, u_cha
> > >  		return;
> > >  	oldprio = td->td_user_pri;
> > >  	td->td_user_pri = prio;
> > > +	if (td->td_flags & TDF_BORROWING && td->td_priority <= prio)
> > > +		return;
> > > +	sched_priority(td, prio);
> > >  }
> > >  
> > >  void
> > > 
> > > But I'm not sure if this would have any negative side effects,
> > > especially since in the ULE case there's a comment on this function that
> > > specifically notes that it changes the the user priority without
> > > changing the current priority (but it doesn't say why that matters).
> > > 
> > > Is this a reasonable way to fix this problem, or is there a better way?
> > 
> > This will lose the "priority boost" afforded to interactive threads when they 
> > sleep in the kernel in the 4BSD scheduler.  You aren't supposed to drop the
> > user priority to loose this boost until userret().  You could perhaps try
> > only altering the priority if the new user pri is lower than your current
> > priority (and then you don't have to check TDF_BORROWING I believe):
> > 
> > 	if (prio < td->td_priority)
> > 		sched_priority(td, prio);
> > 
> 
> That's just the sort of insight I was looking for, thanks.  That made me
> look at the code more and think harder about the problem I'm trying to
> solve, and I concluded that doing it within the scheduler is all wrong.
> 
> That led me to look elsewhere, and I discovered the change you made in
> r228207, which does almost what I want, but your change does it only for
> realtime priorities, and I need a similar effect for idle priorities.
> What I came up with is a bit different than yours (attached below) and
> I'd like your thoughts on it.
> 
> I start with the same test as yours: if sched_user_prio() didn't
> actually change the user priority (due to borrowing), do nothing.  Then
> mine differs:  call sched_prio() to effect the change only if either the
> old or the new priority class is not timeshare.
> 
> My reasoning for the second half of the test is that if it's a change in
> timeshare priority then the scheduler is going to adjust that priority
> in a way that completely wipes out the requested change anyway, so
> what's the point?  (If that's not true, then allowing a thread to change
> its own timeshare priority would subvert the scheduler's adjustments and
> let a cpu-bound thread monopolize the cpu; if allowed at all, that
> should require priveleges.)
> 
> On the other hand, if either the old or new priority class is not
> timeshare, then the scheduler doesn't make automatic adjustments, so we
> should honor the request and make the priority change right away.  The
> reason the old class gets caught up in this is the very reason I'm
> wanting to make a change:  when thread A changes the priority of its
> child thread B from idle back to timeshare, thread B never actually gets
> moved to a timeshare-range run queue unless there are some idle cycles
> available to allow it to first get scheduled again as an idle thread.
> 
> Finally, my change doesn't consider the td == curthread situation at
> all, because I don't see how that's germane.  This is the thing I'm
> least sure of -- I don't at all understand why the old code (even before
> your changes) had that test.  The old code had that flagged as "XXX
> dubious" (a comment a bit too cryptic to be useful).

I think your change is correct.  One style nit: please sort the order of
variables (oldclass comes before oldpri).

-- 
John Baldwin


More information about the freebsd-hackers mailing list