Skip to content

Commit 1c06918

Browse files
author
Peter Zijlstra
committed
sched: Consider task_struct::saved_state in wait_task_inactive()
With the introduction of task_struct::saved_state in commit 5f220be ("sched/wakeup: Prepare for RT sleeping spin/rwlocks") matching the task state has gotten more complicated. That same commit changed try_to_wake_up() to consider both states, but wait_task_inactive() has been neglected. Sebastian noted that the wait_task_inactive() usage in ptrace_check_attach() can misbehave when ptrace_stop() is blocked on the tasklist_lock after it sets TASK_TRACED. Therefore extract a common helper from ttwu_state_match() and use that to teach wait_task_inactive() about the PREEMPT_RT locks. Originally-by: Sebastian Andrzej Siewior <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Tested-by: Sebastian Andrzej Siewior <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent d5e1586 commit 1c06918

File tree

1 file changed

+48
-11
lines changed

1 file changed

+48
-11
lines changed

kernel/sched/core.c

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,6 +2213,39 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
22132213
rq_clock_skip_update(rq);
22142214
}
22152215

2216+
static __always_inline
2217+
int __task_state_match(struct task_struct *p, unsigned int state)
2218+
{
2219+
if (READ_ONCE(p->__state) & state)
2220+
return 1;
2221+
2222+
#ifdef CONFIG_PREEMPT_RT
2223+
if (READ_ONCE(p->saved_state) & state)
2224+
return -1;
2225+
#endif
2226+
return 0;
2227+
}
2228+
2229+
static __always_inline
2230+
int task_state_match(struct task_struct *p, unsigned int state)
2231+
{
2232+
#ifdef CONFIG_PREEMPT_RT
2233+
int match;
2234+
2235+
/*
2236+
* Serialize against current_save_and_set_rtlock_wait_state() and
2237+
* current_restore_rtlock_saved_state().
2238+
*/
2239+
raw_spin_lock_irq(&p->pi_lock);
2240+
match = __task_state_match(p, state);
2241+
raw_spin_unlock_irq(&p->pi_lock);
2242+
2243+
return match;
2244+
#else
2245+
return __task_state_match(p, state);
2246+
#endif
2247+
}
2248+
22162249
/*
22172250
* wait_task_inactive - wait for a thread to unschedule.
22182251
*
@@ -2231,7 +2264,7 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
22312264
*/
22322265
unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state)
22332266
{
2234-
int running, queued;
2267+
int running, queued, match;
22352268
struct rq_flags rf;
22362269
unsigned long ncsw;
22372270
struct rq *rq;
@@ -2257,7 +2290,7 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state
22572290
* is actually now running somewhere else!
22582291
*/
22592292
while (task_on_cpu(rq, p)) {
2260-
if (!(READ_ONCE(p->__state) & match_state))
2293+
if (!task_state_match(p, match_state))
22612294
return 0;
22622295
cpu_relax();
22632296
}
@@ -2272,8 +2305,15 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state
22722305
running = task_on_cpu(rq, p);
22732306
queued = task_on_rq_queued(p);
22742307
ncsw = 0;
2275-
if (READ_ONCE(p->__state) & match_state)
2308+
if ((match = __task_state_match(p, match_state))) {
2309+
/*
2310+
* When matching on p->saved_state, consider this task
2311+
* still queued so it will wait.
2312+
*/
2313+
if (match < 0)
2314+
queued = 1;
22762315
ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
2316+
}
22772317
task_rq_unlock(rq, p, &rf);
22782318

22792319
/*
@@ -4003,15 +4043,14 @@ static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags)
40034043
static __always_inline
40044044
bool ttwu_state_match(struct task_struct *p, unsigned int state, int *success)
40054045
{
4046+
int match;
4047+
40064048
if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)) {
40074049
WARN_ON_ONCE((state & TASK_RTLOCK_WAIT) &&
40084050
state != TASK_RTLOCK_WAIT);
40094051
}
40104052

4011-
if (READ_ONCE(p->__state) & state) {
4012-
*success = 1;
4013-
return true;
4014-
}
4053+
*success = !!(match = __task_state_match(p, state));
40154054

40164055
#ifdef CONFIG_PREEMPT_RT
40174056
/*
@@ -4027,12 +4066,10 @@ bool ttwu_state_match(struct task_struct *p, unsigned int state, int *success)
40274066
* p::saved_state to TASK_RUNNING so any further tests will
40284067
* not result in false positives vs. @success
40294068
*/
4030-
if (p->saved_state & state) {
4069+
if (match < 0)
40314070
p->saved_state = TASK_RUNNING;
4032-
*success = 1;
4033-
}
40344071
#endif
4035-
return false;
4072+
return match > 0;
40364073
}
40374074

40384075
/*

0 commit comments

Comments
 (0)