kernel/sched: Fix preemption logic

The should_preempt() code was catching some of the "unrunnable" cases
but not all of them, opening the possibility of failing to preempt a
just-pended thread and thus waking it up synchronously.  There are
reports of this causing spin loops over k_poll() in the network stack
work queues (see #8049).

Note that the previous _is_dummy() call is folded into (the somewhat
verbosely named) _is_thread_prevented_from_running(), and that the
order of tests has been changed/optimized to hopefully catch common
cases earlier.

Suggested-by: Michael Scott <michael@opensourcefoundries.com>
Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2018-05-31 11:13:49 -07:00 committed by Anas Nashif
parent e76ef30aca
commit 43553da9b2

View file

@ -114,10 +114,22 @@ int _is_t1_higher_prio_than_t2(struct k_thread *t1, struct k_thread *t2)
static int should_preempt(struct k_thread *th, int preempt_ok)
{
/* System initialization states can have dummy threads, never
* refuse to swap those
/* Preemption is OK if it's being explicitly allowed by
* software state (e.g. the thread called k_yield())
*/
if (!_current || _is_thread_dummy(_current)) {
if (preempt_ok) {
return 1;
}
/* Or if we're pended/suspended/dummy (duh) */
if (!_current || _is_thread_prevented_from_running(_current)) {
return 1;
}
/* Otherwise we have to be running a preemptible thread or
* switching to a metairq
*/
if (_is_preempt(_current) || is_metairq(th)) {
return 1;
}
@ -129,18 +141,6 @@ static int should_preempt(struct k_thread *th, int preempt_ok)
return 1;
}
/* Preemption is OK if it's being explicitly allowed */
if (preempt_ok) {
return 1;
}
/* Otherwise we have to be running a preemptible thread or
* switching to a metairq
*/
if (_is_preempt(_current) || is_metairq(th)) {
return 1;
}
return 0;
}