sched: fix the PREEMPT_ACTIVE check in __trace_sched_switch_state()
Subsystems (4)
cover sched: fix the PREEMPT_ACTIVE check in __trace_sched_switch_state()
And note that another caller of task_preempt_count(), set_cpu(), is fine but it doesn't really need this helper.
And afaics we do not need ->saved_preempt_count at all, the trivial patch below makes it unnecessary, we can kill it and all its users.
Not only this will simplify the code, this will make (well, almost) the per-cpu preempt counter arch-agnostic.
Or I missed something?
Do you think this makes sense? If yes, I'll try to make the patches.
Oleg.
---
OBVIOUSLY INCOMPLETE, BREAKS EVERYTHING EXCEPT x86. Just to explain what I mean.
(this depends on !__ARCH_WANT_UNLOCKED_CTXSW, but it was already removed
and x86 doesn't use it anyway).
kernel/sched/core.c +6 -1
@@ -2279,6 +2279,7 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev) {struct rq *rq =this_rq (); +preempt_count_set (PREEMPT_DISABLED );finish_task_switch (rq, prev);/*
@@ -2304,6 +2305,7 @@ context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) {struct mm_struct *mm, *oldmm; +int pc;prepare_task_switch (rq, prev, next);
@@ -2338,10 +2340,13 @@ context_switch(struct rq *rq, struct task_struct *prev,#endif context_tracking_task_switch (prev, next); +/* Here we just switch the register state and the stack. */ + pc =this_cpu_read (__preempt_count);switch_to (prev, next, prev); -barrier (); +preempt_count_set (pc); +/* * this_rq must be evaluated again because prev may have moved * CPUs since it called schedule(), thus the 'rq' on its stack
PATCH 1/1 sched: fix the PREEMPT_ACTIVE check in __trace_sched_switch_state()
task_preempt_count() has nothing to do with the actual preempt counter, thread_info->saved_preempt_count is only valid right after switch_to().
__trace_sched_switch_state() can use preempt_count(), prev is still the current task when trace_sched_switch() is called.
--- include/trace/events/sched.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
include/trace/events/sched.h +1 -1
@@ -100,7 +100,7 @@ static inline long __trace_sched_switch_state(struct task_struct *p)/* * For all intents and purposes a preempted task is a running task. */ -if (task_preempt_count (p) &PREEMPT_ACTIVE ) +if (preempt_count () &PREEMPT_ACTIVE ) state =TASK_RUNNING |TASK_STATE_MAX ;#endif
Signature · 1 line
1.5.5.1
Peter Zijlstra
maintainerQuoted 5 lines · Oleg Nesterov
task_preempt_count()has nothing to do with the actual preempt counter,thread_info->saved_preempt_countis only valid right afterswitch_to().
__trace_sched_switch_state()can usepreempt_count(), prev is still the current task whentrace_sched_switch()is called.
This is true, but the paranoid in me would like a BUG_ON(p != current) right along with that to make sure we don't accidentally change this.
But yes, its good to get rid of task_preempt_count(), its horrible.
Quoted 22 lines
Signed-off-by Oleg Nesterov <[email protected]>--- include/trace/events/sched.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)include/trace/events/sched.h +1
-1@@ -100,7 +100,7 @@ static inline long __trace_sched_switch_state(struct task_struct *p)/* * For all intents and purposes a preempted task is a running task. */ -if (task_preempt_count (p) &PREEMPT_ACTIVE ) +if (preempt_count () &PREEMPT_ACTIVE ) state =TASK_RUNNING |TASK_STATE_MAX ;#endif Signature · 1 line
1.5.5.1
Peter Zijlstra
maintainerQuoted 11 lines · Peter Zijlstra
Quoted 5 lines · Oleg Nesterov
task_preempt_count()has nothing to do with the actual preempt counter,thread_info->saved_preempt_countis only valid right afterswitch_to().
__trace_sched_switch_state()can usepreempt_count(), prev is still the current task whentrace_sched_switch()is called.This is true, but the paranoid in me would like a
BUG_ON(p != current)right along with that to make sure we don't accidentally change this.But yes, its good to get rid of
task_preempt_count(), its horrible.
Like so then?
---
include/trace/events/sched.h +6 -3
@@ -97,16 +97,19 @@ static inline long __trace_sched_switch_long state = p->state;#ifdef CONFIG_PREEMPT +#ifdef CONFIG_SCHED_DEBUG +BUG_ON (p != current); +#endif /* CONFIG_SCHED_DEBUG */ /* * For all intents and purposes a preempted task is a running task. */ -if (task_preempt_count (p) &PREEMPT_ACTIVE ) +if (preempt_count () &PREEMPT_ACTIVE ) state =TASK_RUNNING |TASK_STATE_MAX ; -#endif +#endif /* CONFIG_PREEMPT */ return state; } -#endif +#endif /* CREATE_TRACE_POINTS */ /* * Tracepoint for task switches, performed by the scheduler:
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] sched: Fix the PREEMPT_ACTIVE check in __trace_sched_switch_state()
In reply to Oleg Nesterovsched: Fix the PREEMPT_ACTIVE check in __trace_sched_switch_state()
Commit-ID: 8f9fbf092cd0ae31722b42c9abb427a87d55c18a Gitweb: http://git.kernel.org/tip/8f9fbf092cd0ae31722b42c9abb427a87d55c18a Author: Oleg Nesterov <[email protected]> AuthorDate: Tue, 7 Oct 2014 21:51:08 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 28 Oct 2014 10:47:53 +0100
sched: Fix the PREEMPT_ACTIVE check in __trace_sched_switch_state()
task_preempt_count() has nothing to do with the actual preempt counter, thread_info->saved_preempt_count is only valid right after switch_to().
__trace_sched_switch_state() can use preempt_count(), prev is still the current task when trace_sched_switch() is called.
--- include/trace/events/sched.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
include/trace/events/sched.h +6 -3
@@ -97,16 +97,19 @@ static inline long __trace_sched_switch_state(struct task_struct *p)long state = p->state;#ifdef CONFIG_PREEMPT +#ifdef CONFIG_SCHED_DEBUG +BUG_ON (p != current); +#endif /* CONFIG_SCHED_DEBUG */ /* * For all intents and purposes a preempted task is a running task. */ -if (task_preempt_count (p) &PREEMPT_ACTIVE ) +if (preempt_count () &PREEMPT_ACTIVE ) state =TASK_RUNNING |TASK_STATE_MAX ; -#endif +#endif /* CONFIG_PREEMPT */ return state; } -#endif +#endif /* CREATE_TRACE_POINTS */ /* * Tracepoint for task switches, performed by the scheduler:
Peter Zijlstra
maintainerQuoted 10 lines · Oleg Nesterov
And note that another caller of
task_preempt_count(),set_cpu(), is fine but it doesn't really need this helper.And afaics we do not need ->saved_preempt_count at all, the trivial patch below makes it unnecessary, we can kill it and all its users.
Not only this will simplify the code, this will make (well, almost) the per-cpu preempt counter arch-agnostic.
Or I missed something?
Two things, per-cpu isn't always faster on some archs, and load-store archs have problems with PREEMPT_NEED_RESCHED, although arguably you can do per-cpu preempt count without that.
Quoted 1 line
Do you think this makes sense? If yes, I'll try to make the patches.
It penalizes everything but x86 I think. There is no other arch that has per-cpu preempt count atm.
cover (Was: sched: fix the PREEMPT_ACTIVE check in __trace_sched_switch_state())
Quoted 8 lines · Peter Zijlstra
Quoted 6 lines · Oleg Nesterov
And note that another caller of
task_preempt_count(),set_cpu(), is fine but it doesn't really need this helper.And afaics we do not need ->saved_preempt_count at all, the trivial patch below makes it unnecessary, we can kill it and all its users.
Quoted 8 lines
Quoted 4 lines
Not only this will simplify the code, this will make (well, almost) the per-cpu preempt counter arch-agnostic.
Or I missed something?
Two things, per-cpu isn't always faster on some archs, and load-store archs have problems with
PREEMPT_NEED_RESCHED, although arguably you can do per-cpu preempt count without that.
Ah, but I didn't mean we should make it per-cpu on every arch.
I meant that (imo) this change can cleanup x86 code, and it can also help if we want to change another arch to use per-cpu preempt_count.
Quoted 3 lines
Quoted 1 line
Do you think this makes sense? If yes, I'll try to make the patches.
It penalizes everything but x86 I think.
I don't think so.
But please forget for the moment, lets discuss this later. Let me start with 2 simple preparations which imho make sense anyway. Then we will see.
1/2 looks like the obvious bugfix (iirc we already discussed this a bit), 2/2 depends on this patch.
Oleg.
PATCH 1/2 sched: schedule_tail() should disable preemption
finish_task_switch() enables preemption, so post_schedule(rq) can be called on the wrong (and even dead) CPU. Afaics, nothing really bad can happen, but in this case we can wrongly clear rq->post_schedule on that CPU. And this simply looks wrong in any case.
Another problem is that finish_task_switch() itself runs with preempt enabled after finish_lock_switch(). If nothing else this means that ->sched_in() notifier can't trust its "cpu" arg.
--- kernel/sched/core.c | 11 +++++------ 1 files changed, 5 insertions(+), 6 deletions(-)
kernel/sched/core.c +5 -6
@@ -2277,15 +2277,14 @@ static inline void post_schedule(struct rq *rq) asmlinkage __visible void schedule_tail(struct task_struct *prev) __releases(rq->lock) { -struct rq *rq =this_rq (); +struct rq *rq; +/* finish_task_switch() drops rq->lock and enables preemtion */ +preempt_disable (); + rq =this_rq ();finish_task_switch (rq, prev); - -/* -* FIXME: do we need to worry about rq being invalidated by the -* task_switch? -*/ post_schedule (rq); +preempt_enable ();if (current->set_child_tid)put_user (task_pid_vnr (current), current->set_child_tid);
Signature · 1 line
1.5.5.1
PATCH v2 1/2 sched: schedule_tail() should disable preemption
Quoted 4 lines · Oleg Nesterov
Another problem is that
finish_task_switch()itself runs with preempt enabled afterfinish_lock_switch(). If nothing else this means that ->sched_in() notifier can't trust its "cpu" arg.
OOPS, this obviously can't happen, ->preempt_notifiers must be empty. Remove this part from the changelog, please see v2.
I am not sure about finish_arch_post_lock_switch() ... but probably it should be fine without preempt_disable.
-------------------------------------------------------------------------------
Subject: [PATCH v2 1/2] sched: schedule_tail() should disable preemption
finish_task_switch() enables preemption, so post_schedule(rq) can be called on the wrong (and even dead) CPU. Afaics, nothing really bad can happen, but in this case we can wrongly clear rq->post_schedule on that CPU. And this simply looks wrong in any case.
--- kernel/sched/core.c | 11 +++++------ 1 files changed, 5 insertions(+), 6 deletions(-)
kernel/sched/core.c +5 -6
@@ -2277,15 +2277,14 @@ static inline void post_schedule(struct rq *rq) asmlinkage __visible void schedule_tail(struct task_struct *prev) __releases(rq->lock) { -struct rq *rq =this_rq (); +struct rq *rq; +/* finish_task_switch() drops rq->lock and enables preemtion */ +preempt_disable (); + rq =this_rq ();finish_task_switch (rq, prev); - -/* -* FIXME: do we need to worry about rq being invalidated by the -* task_switch? -*/ post_schedule (rq); +preempt_enable ();if (current->set_child_tid)put_user (task_pid_vnr (current), current->set_child_tid);
Signature · 1 line
1.5.5.1
Re: [PATCH v2 1/2] sched: schedule_tail() should disable preemption
В Ср, 08/10/2014 в 21:36 +0200, Oleg Nesterov пишет:
Quoted 30 lines · Oleg Nesterov
Quoted 4 lines
Another problem is that
finish_task_switch()itself runs with preempt enabled afterfinish_lock_switch(). If nothing else this means that ->sched_in() notifier can't trust its "cpu" arg.OOPS, this obviously can't happen, ->preempt_notifiers must be empty. Remove this part from the changelog, please see v2.
I am not sure about
finish_arch_post_lock_switch()... but probably it should be fine withoutpreempt_disable.-------------------------------------------------------------------------------
Subject: [PATCH v2 1/2] sched:schedule_tail()should disable preemption
finish_task_switch()enables preemption, sopost_schedule(rq)can be called on the wrong (and even dead) CPU. Afaics, nothing really bad can happen, but in this case we can wrongly clearrq->post_scheduleon that CPU. And this simply looks wrong in any case.Signed-off-by Oleg Nesterov <[email protected]>--- kernel/sched/core.c | 11 +++++------ 1 files changed, 5 insertions(+), 6 deletions(-)kernel/sched/core.c +0
-0
kernel/sched/core.c static inline void post_schedule(struct rq *rq) · line 2283
Quoted 8 lines
kernel/sched/core.c +3
-1@@ -2277,15 +2277,14 @@ static inline void post_schedule(struct rq *rq) asmlinkage __visible void schedule_tail(struct task_struct *prev) __releases(rq->lock) { -struct rq *rq =this_rq (); +struct rq *rq; +/* finish_task_switch() drops rq->lock and enables preemtion */ +preempt_disable ();
Maybe, the code would look simpler if we change init_task_preempt_count() and create new tasks with preempt_count() == 2, so this preempt_disable() won't be necessary. But it's more or less subjectively.
Quoted 12 lines
kernel/sched/core.c +2
-5+ rq =this_rq ();finish_task_switch (rq, prev); - -/* -* FIXME: do we need to worry about rq being invalidated by the -* task_switch? -*/ post_schedule (rq); +preempt_enable ();if (current->set_child_tid)put_user (task_pid_vnr (current), current->set_child_tid);
Re: [PATCH v2 1/2] sched: schedule_tail() should disable preemption
Quoted 9 lines · Kirill Tkhai
В Ср, 08/10/2014 в 21:36 +0200, Oleg Nesterov пишет:
Quoted 7 lines
kernel/sched/core.c +1
-1@@ -2277,15 +2277,14 @@ static inline void post_schedule(struct rq *rq) asmlinkage __visible void schedule_tail(struct task_struct *prev) __releases(rq->lock) { -struct rq *rq =this_rq (); +struct rq *rq;
Quoted 7 lines
kernel/sched/core.c static inline void post_schedule(struct rq *rq) · line 2283
Quoted 2 lines
kernel/sched/core.c +2
-0+/* finish_task_switch() drops rq->lock and enables preemtion */ +preempt_disable ();Maybe, the code would look simpler if we change
init_task_preempt_count()and create new tasks withpreempt_count()== 2, so thispreempt_disable()won't be necessary. But it's more or less subjectively.
Yes, yes, I thought about the same.
Except I think we should kill init_task_preempt_count() and change schedule_tail()
- preempt_disable(); + preempt_count_set(PREEMPT_DISABLED + 1);
but first we need to remove ->saved_preempt_count.
Quoted 1 line
Reviewed-by Kirill Tkhai <[email protected]>
Thanks!
Oleg.
Peter Zijlstra
maintainerRe: [PATCH v2 1/2] sched: schedule_tail() should disable preemption
Quoted 1 line · Oleg Nesterov
but first we need to remove ->saved_preempt_count.
Why do you want to kill that? Your earlier proposal would penalize every !x86 arch by adding extra code to the scheduler core while they already automagically preserve their thread_info::preempt_count.
Re: [PATCH v2 1/2] sched: schedule_tail() should disable preemption
Peter,
let me first say that I understand that cleanups are always subjective. So if you do not like it - I won't argue at all.
Quoted 6 lines · Peter Zijlstra
Quoted 1 line · Oleg Nesterov
but first we need to remove ->saved_preempt_count.
Why do you want to kill that?
Because imo this makes the code a bit simpler. But (perhaps) mostly because personally I dislike any "special" member in task_struct/thread_info, and it seems to me that ->saved_preempt_count buys nothing. We only need it to record/restore the counter before/after switch_to(), a local variably looks better to me.
But again, see above. If the maintainer doesn't like the cleanup - then it should be counted as uglification ;)
Quoted 3 lines
Your earlier proposal would penalize every
!x86 arch by adding extra code to the scheduler core while they already automagically preserve theirthread_info::preempt_count.
Sure, and it can't be even compiled on !x86.
But this is simple, just we need a new helper, preempt_count_restore(), defined as nop in asm-generic/preempt.h. Well, perhaps another helper makes sense, preempt_count_raw() which simply reads the counter, but this is minor.
After the patch below we can remove ->saved_preempt_count. Including init_task_preempt_count(), it is no longer needed after the change in schedule_tail().
No?
Oleg.
arch/x86/include/asm/preempt.h +5 -0
@@ -27,6 +27,11 @@ static __always_inline void preempt_count_set(int pc)raw_cpu_write_4 (__preempt_count, pc); } +static __always_inline void preempt_count_restore(int pc) +{ +preempt_count_set (pc); +} +/* * must be macros to avoid header recursion hell */
include/asm-generic/preempt.h +4 -0
@@ -20,6 +20,10 @@ static __always_inline void preempt_count_set(int pc) *preempt_count_ptr () = pc; } +static __always_inline void preempt_count_restore(int pc) +{ +} +/* * must be macros to avoid header recursion hell */
kernel/sched/core.c +6 -1
@@ -2279,6 +2279,8 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev) {struct rq *rq; +preempt_count_set (PREEMPT_DISABLED ); +/* finish_task_switch() drops rq->lock and enables preemtion */ preempt_disable (); rq =this_rq ();
@@ -2299,6 +2301,7 @@ context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) {struct mm_struct *mm, *oldmm; +int pc;prepare_task_switch (rq, prev, next);
@@ -2333,10 +2336,12 @@ context_switch(struct rq *rq, struct task_struct *prev,#endif context_tracking_task_switch (prev, next); + + pc =preempt_count ();/* Here we just switch the register state and the stack. */ switch_to (prev, next, prev); -barrier (); +preempt_count_restore (pc);/* * this_rq must be evaluated again because prev may have moved * CPUs since it called schedule(), thus the 'rq' on its stack
Peter Zijlstra
maintainerRe: [PATCH v2 1/2] sched: schedule_tail() should disable preemption
Quoted 6 lines · Oleg Nesterov
Quoted 3 lines
Your earlier proposal would penalize every
!x86 arch by adding extra code to the scheduler core while they already automagically preserve theirthread_info::preempt_count.Sure, and it can't be even compiled on !x86.
Quoted 8 lines
But this is simple, just we need a new helper,
preempt_count_restore(), defined as nop inasm-generic/preempt.h. Well, perhaps another helper makes sense,preempt_count_raw()which simply reads the counter, but this is minor.After the patch below we can remove ->saved_preempt_count. Including
init_task_preempt_count(), it is no longer needed after the change inschedule_tail().
Ah, right, this makes more sense.
kernel/sched/core.c context_switch(struct rq *rq, struct task_struct *prev, · line 2340
Quoted 6 lines
kernel/sched/core.c +2
-0@@ -2333,10 +2336,12 @@ context_switch(struct rq *rq, struct task_struct *prev,#endif context_tracking_task_switch (prev, next); + + pc =preempt_count ();
The only problem here is that you can loose PREEMPT_NEED_RESCHED, I haven't thought about whether that is a problem here or not.
Quoted 9 lines
kernel/sched/core.c +1
-1/* Here we just switch the register state and the stack. */ switch_to (prev, next, prev); -barrier (); +preempt_count_restore (pc);/* * this_rq must be evaluated again because prev may have moved * CPUs since it called schedule(), thus the 'rq' on its stack
Peter Zijlstra
maintainerRe: [PATCH v2 1/2] sched: schedule_tail() should disable preemption
Quoted 21 lines · Peter Zijlstra
Quoted 6 lines · Oleg Nesterov
Quoted 3 lines
Your earlier proposal would penalize every
!x86 arch by adding extra code to the scheduler core while they already automagically preserve theirthread_info::preempt_count.Sure, and it can't be even compiled on !x86.
Quoted 8 lines
But this is simple, just we need a new helper,
preempt_count_restore(), defined as nop inasm-generic/preempt.h. Well, perhaps another helper makes sense,preempt_count_raw()which simply reads the counter, but this is minor.After the patch below we can remove ->saved_preempt_count. Including
init_task_preempt_count(), it is no longer needed after the change inschedule_tail().Ah, right, this makes more sense.
Quoted 3 lines
(quoted diff) +0
-0@@ -2333,10 +2336,12 @@ context_switch(struct rq *rq, struct task_struct *prev, #endif
Quoted 6 lines
kernel/sched/core.c context_switch(struct rq *rq, struct task_struct *prev, · line 2340
Quoted 3 lines
kernel/sched/core.c +2
-0context_tracking_task_switch (prev, next); + + pc =preempt_count ();The only problem here is that you can loose
PREEMPT_NEED_RESCHED, I haven't thought about whether that is a problem here or not.
Also, if you make that preempt_count_save(), to mirror the restore, you can both preserve PREEMPT_NEED_RESCHED and avoid emitting code on !x86.
Re: [PATCH v2 1/2] sched: schedule_tail() should disable preemption
Quoted 6 lines · Peter Zijlstra
Quoted 4 lines · Peter Zijlstra
Quoted 3 lines · Oleg Nesterov
(quoted diff) +0
-0@@ -2333,10 +2336,12 @@ context_switch(struct rq *rq, struct task_struct *prev, #endif
Quoted 6 lines
Quoted 6 lines
kernel/sched/core.c context_switch(struct rq *rq, struct task_struct *prev, · line 2340
Quoted 3 lines
kernel/sched/core.c +2
-0context_tracking_task_switch (prev, next); + + pc =preempt_count ();The only problem here is that you can loose
PREEMPT_NEED_RESCHED, I haven't thought about whether that is a problem here or not.
No, it must not be set. It was cleared by clear_preempt_need_resched() in __schedule(), and nobody can set it.
(schedule_tail() also relies on fact it runs with irqs disabled).
But,
Quoted 1 line
Also, if you make that
preempt_count_save(), to mirror the restore,
Yes, agreed. That is why I said we probably want preempt_count_raw() (or _save). This way we avoid the unnecessary "&= ~PREEMPT_NEED_RESCHED" on x86.
Quoted 1 line
can both preserve
PREEMPT_NEED_RESCHEDand avoid emitting code on !x86.
This too, although gcc should optimize this code out anyway. At least it seems to do on x86 if I make preempt_count_restore() empty.
Oleg.
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] sched: Fix schedule_tail() to disable preemption
In reply to Oleg Nesterovsched: Fix schedule_tail() to disable preemption
Commit-ID: 1a43a14a5bd9c32dbd7af35e35a5afa703944bcb Gitweb: http://git.kernel.org/tip/1a43a14a5bd9c32dbd7af35e35a5afa703944bcb Author: Oleg Nesterov <[email protected]> AuthorDate: Wed, 8 Oct 2014 21:36:44 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 28 Oct 2014 10:47:54 +0100
sched: Fix schedule_tail() to disable preemption
finish_task_switch() enables preemption, so post_schedule(rq) can be called on the wrong (and even dead) CPU. Afaics, nothing really bad can happen, but in this case we can wrongly clear rq->post_schedule on that CPU. And this simply looks wrong in any case.
--- kernel/sched/core.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
kernel/sched/core.c +5 -6
@@ -2309,15 +2309,14 @@ static inline void post_schedule(struct rq *rq) asmlinkage __visible void schedule_tail(struct task_struct *prev) __releases(rq->lock) { -struct rq *rq =this_rq (); +struct rq *rq; +/* finish_task_switch() drops rq->lock and enables preemtion */ +preempt_disable (); + rq =this_rq ();finish_task_switch (rq, prev); - -/* -* FIXME: do we need to worry about rq being invalidated by the -* task_switch? -*/ post_schedule (rq); +preempt_enable ();if (current->set_child_tid)put_user (task_pid_vnr (current), current->set_child_tid);
PATCH 2/2 sched: kill task_preempt_count()
In reply to Oleg Nesterovtask_preempt_count() is pointless if preemption counter is per-cpu, currently this is x86 only. It is only valid if the task is not running, and even in this case the only info it can provide is the state of PREEMPT_ACTIVE bit.
Change its single caller to check p->on_rq instead, this should be the same if p->state != TASK_RUNNING, and kill this helper.
--- arch/x86/include/asm/preempt.h | 3 --- include/asm-generic/preempt.h | 3 --- kernel/sched/core.c | 2 +- 3 files changed, 1 insertions(+), 7 deletions(-)
arch/x86/include/asm/preempt.h +0 -3
@@ -30,9 +30,6 @@ static __always_inline void preempt_count_set(int pc)/* * must be macros to avoid header recursion hell */ -#define task_preempt_count (p) \ - (task_thread_info(p)->saved_preempt_count & ~PREEMPT_NEED_RESCHED) -#define init_task_preempt_count (p) do { \ task_thread_info(p)->saved_preempt_count = PREEMPT_DISABLED; \ } while (0)
include/asm-generic/preempt.h +0 -3
@@ -23,9 +23,6 @@ static __always_inline void preempt_count_set(int pc)/* * must be macros to avoid header recursion hell */ -#define task_preempt_count (p) \ - (task_thread_info(p)->preempt_count & ~PREEMPT_NEED_RESCHED) -#define init_task_preempt_count (p) do { \ task_thread_info(p)->preempt_count = PREEMPT_DISABLED; \ } while (0)
kernel/sched/core.c +1 -1
@@ -1056,7 +1056,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)* ttwu() will sort out the placement. */ WARN_ON_ONCE (p->state !=TASK_RUNNING && p->state !=TASK_WAKING && - !(task_preempt_count (p) &PREEMPT_ACTIVE )); + !p->on_rq);#ifdef CONFIG_LOCKDEP /*
Signature · 1 line
1.5.5.1
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] sched: Kill task_preempt_count()
sched: Kill task_preempt_count()
Commit-ID: e2336f6e51edda875a49770b616ed5b02a74665b Gitweb: http://git.kernel.org/tip/e2336f6e51edda875a49770b616ed5b02a74665b Author: Oleg Nesterov <[email protected]> AuthorDate: Wed, 8 Oct 2014 20:33:48 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 28 Oct 2014 10:47:56 +0100
sched: Kill task_preempt_count()
task_preempt_count() is pointless if preemption counter is per-cpu, currently this is x86 only. It is only valid if the task is not running, and even in this case the only info it can provide is the state of PREEMPT_ACTIVE bit.
Change its single caller to check p->on_rq instead, this should be the same if p->state != TASK_RUNNING, and kill this helper.
--- arch/x86/include/asm/preempt.h | 3 --- include/asm-generic/preempt.h | 3 --- kernel/sched/core.c | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-)
arch/x86/include/asm/preempt.h +0 -3
@@ -30,9 +30,6 @@ static __always_inline void preempt_count_set(int pc)/* * must be macros to avoid header recursion hell */ -#define task_preempt_count (p) \ - (task_thread_info(p)->saved_preempt_count & ~PREEMPT_NEED_RESCHED) -#define init_task_preempt_count (p) do { \ task_thread_info(p)->saved_preempt_count = PREEMPT_DISABLED; \ } while (0)
include/asm-generic/preempt.h +0 -3
@@ -23,9 +23,6 @@ static __always_inline void preempt_count_set(int pc)/* * must be macros to avoid header recursion hell */ -#define task_preempt_count (p) \ - (task_thread_info(p)->preempt_count & ~PREEMPT_NEED_RESCHED) -#define init_task_preempt_count (p) do { \ task_thread_info(p)->preempt_count = PREEMPT_DISABLED; \ } while (0)
kernel/sched/core.c +1 -1
@@ -1054,7 +1054,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)* ttwu() will sort out the placement. */ WARN_ON_ONCE (p->state !=TASK_RUNNING && p->state !=TASK_WAKING && - !(task_preempt_count (p) &PREEMPT_ACTIVE )); + !p->on_rq);#ifdef CONFIG_LOCKDEP /*
cover sched: make finish_task_switch() return struct rq *
In reply to Oleg Nesterovspeaking of minor cleanups...
Let me send another once before ->saved_preempt_count removal, it looks simple and less subjective.
Again, this is just minor cleanup so please feel free to ignore, but somehow to me this duplicated this_rq() (and the comment!) looks a bit annoying. Plus it saves a few insns, but this is minor.
Depends on "sched: schedule_tail() should disable preemption".
Oleg.
PATCH 1/1 sched: make finish_task_switch() return struct rq *
Both callers of finish_task_switch() need to recalculate this_rq() and pass it as an argument, plus __schedule() does this again after context_switch().
It would be simpler to call this_rq() once in finish_task_switch() and return the this rq to the callers.
Note: probably "int cpu" in __schedule() should die; it is not used and both rcu_note_context_switch() and wq_worker_sleeping() do not really need this argument.
--- kernel/sched/core.c | 37 +++++++++++++++---------------------- 1 files changed, 15 insertions(+), 22 deletions(-)
kernel/sched/core.c +15 -22
@@ -2200,10 +2200,16 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,* so, we finish that here outside of the runqueue lock. (Doing it * with the lock held can cause deadlocks; see schedule() for * details.) +* +* The context switch have flipped the stack from under us and restored the +* local variables which were saved when this task called schedule() in the +* past. prev == current is still correct but we need to recalculate this_rq +* because prev may have moved to another CPU. */ -static void finish_task_switch (struct rq *rq,struct task_struct *prev) +static struct rq *finish_task_switch (struct task_struct *prev) __releases(rq->lock) { +struct rq *rq =this_rq ();struct mm_struct *mm = rq->prev_mm;long prev_state;
@@ -2243,6 +2249,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) }tick_nohz_task_switch (current); +return rq; }#ifdef CONFIG_SMP
@@ -2281,8 +2288,7 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev)/* finish_task_switch() drops rq->lock and enables preemtion */ preempt_disable (); - rq =this_rq (); -finish_task_switch (rq, prev); + rq =finish_task_switch (prev);post_schedule (rq);preempt_enable ();
@@ -2291,10 +2297,9 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev) }/* -* context_switch - switch to the new MM and the new -* thread's register state. +* context_switch - switch to the new MM and the new thread's register state. */ -static inline void +static inline struct rq *context_switch (struct rq *rq,struct task_struct *prev,struct task_struct *next) {
@@ -2335,14 +2340,9 @@ context_switch(struct rq *rq, struct task_struct *prev,context_tracking_task_switch (prev, next);/* Here we just switch the register state and the stack. */ switch_to (prev, next, prev); -barrier (); -/* -* this_rq must be evaluated again because prev may have moved -* CPUs since it called schedule(), thus the 'rq' on its stack -* frame will be invalid. -*/ -finish_task_switch (this_rq (), prev); + +return finish_task_switch (prev); }/*
@@ -2802,15 +2802,8 @@ need_resched: rq->curr = next; ++*switch_count; -context_switch (rq, prev, next);/* unlocks the rq */ -/* -* The context switch have flipped the stack from under us -* and restored the local variables which were saved when -* this task called schedule() in the past. prev == current -* is still correct, but it can be moved to another cpu/rq. -*/ - cpu =smp_processor_id (); - rq =cpu_rq (cpu); + rq =context_switch (rq, prev, next);/* unlocks the rq */ + cpu = rq->cpu; }else raw_spin_unlock_irq (&rq->lock);
Signature · 1 line
1.5.5.1
Peter Zijlstra
maintainerRe: [PATCH 1/1] sched: make finish_task_switch() return struct rq *
Quoted 5 lines · Oleg Nesterov
kernel/sched/core.c +0
-1@@ -2802,15 +2802,8 @@ need_resched: rq->curr = next; ++*switch_count; -context_switch (rq, prev, next);/* unlocks the rq */
kernel/sched/core.c need_resched: · line 2806
Quoted 10 lines
kernel/sched/core.c +2
-8-/* -* The context switch have flipped the stack from under us -* and restored the local variables which were saved when -* this task called schedule() in the past. prev == current -* is still correct, but it can be moved to another cpu/rq. -*/ - cpu =smp_processor_id (); - rq =cpu_rq (cpu); + rq =context_switch (rq, prev, next);/* unlocks the rq */ + cpu = rq->cpu;
This won't compile on UP, cpu_of(rq) works though.
Re: [PATCH 1/1] sched: make finish_task_switch() return struct rq *
Quoted 6 lines · Peter Zijlstra
Quoted 4 lines · Oleg Nesterov
kernel/sched/core.c +0
-0@@ -2802,15 +2802,8 @@ need_resched: rq->curr = next; ++*switch_count;
Quoted 13 lines
kernel/sched/core.c need_resched: · line 2806
Quoted 11 lines
kernel/sched/core.c +2
-9-context_switch (rq, prev, next);/* unlocks the rq */ -/* -* The context switch have flipped the stack from under us -* and restored the local variables which were saved when -* this task called schedule() in the past. prev == current -* is still correct, but it can be moved to another cpu/rq. -*/ - cpu =smp_processor_id (); - rq =cpu_rq (cpu); + rq =context_switch (rq, prev, next);/* unlocks the rq */ + cpu = rq->cpu;This won't compile on UP,
cpu_of(rq)works though.
Heh ;) and I swear I was going to write cpu_of().
and I agree with BUG_ON() in __trace_sched_switch() if CONFIG_SCHED_DEBUG.
I am travelling till next Wednesday, will resend everything once I return.
Thanks a lot!
Oleg.
Peter Zijlstra
maintainerRe: [PATCH 1/1] sched: make finish_task_switch() return struct rq *
Quoted 21 lines · Oleg Nesterov
Quoted 6 lines · Peter Zijlstra
Quoted 4 lines · Oleg Nesterov
kernel/sched/core.c +0
-0@@ -2802,15 +2802,8 @@ need_resched: rq->curr = next; ++*switch_count;Quoted 13 lines
kernel/sched/core.c need_resched: · line 2806
Quoted 11 lines
kernel/sched/core.c +2
-9-context_switch (rq, prev, next);/* unlocks the rq */ -/* -* The context switch have flipped the stack from under us -* and restored the local variables which were saved when -* this task called schedule() in the past. prev == current -* is still correct, but it can be moved to another cpu/rq. -*/ - cpu =smp_processor_id (); - rq =cpu_rq (cpu); + rq =context_switch (rq, prev, next);/* unlocks the rq */ + cpu = rq->cpu;This won't compile on UP,
cpu_of(rq)works though.
Quoted 5 lines
Heh ;) and I swear I was going to write
cpu_of().and I agree with
BUG_ON()in__trace_sched_switch()ifCONFIG_SCHED_DEBUG.I am travelling till next Wednesday, will resend everything once I return.
Not towards DUS by any chance? I fixed up the patches, they should be in here:
https://git.kernel.org/cgit/linux/kernel/git/peterz/queue.git/log/?h=sched/core
If I missed some, please do resend (or ping me on) those.
Re: [PATCH 1/1] sched: make finish_task_switch() return struct rq *
Quoted 6 lines · Peter Zijlstra
Quoted 2 lines · Oleg Nesterov
I am travelling till next Wednesday, will resend everything once I return.
Not towards DUS by any chance?
No, Moscow ;)
Quoted 3 lines
I fixed up the patches, they should be in
here:
https://git.kernel.org/cgit/linux/kernel/git/peterz/queue.git/log/?h=sched/core
Thanks! In particular thanks for taking the preempt_schedule_context() fix.
Oleg.
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] sched: Make finish_task_switch() return ' struct rq *'
In reply to Oleg Nesterovsched: Make finish_task_switch() return 'struct rq *'
Commit-ID: dfa50b605c2a933b7bb1c1d575a0da4e897e3c7d Gitweb: http://git.kernel.org/tip/dfa50b605c2a933b7bb1c1d575a0da4e897e3c7d Author: Oleg Nesterov <[email protected]> AuthorDate: Thu, 9 Oct 2014 21:32:32 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 28 Oct 2014 10:47:55 +0100
sched: Make finish_task_switch() return 'struct rq *'
Both callers of finish_task_switch() need to recalculate this_rq() and pass it as an argument, plus __schedule() does this again after context_switch().
It would be simpler to call this_rq() once in finish_task_switch() and return the this rq to the callers.
Note: probably "int cpu" in __schedule() should die; it is not used and both rcu_note_context_switch() and wq_worker_sleeping() do not really need this argument.
--- kernel/sched/core.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-)
kernel/sched/core.c +15 -23
@@ -2220,7 +2220,6 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,/** * finish_task_switch - clean up after a task-switch -* @rq: runqueue associated with task-switch * @prev: the thread we just switched away from. * * finish_task_switch must be called after the context switch, paired
@@ -2232,10 +2231,16 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,* so, we finish that here outside of the runqueue lock. (Doing it * with the lock held can cause deadlocks; see schedule() for * details.) +* +* The context switch have flipped the stack from under us and restored the +* local variables which were saved when this task called schedule() in the +* past. prev == current is still correct but we need to recalculate this_rq +* because prev may have moved to another CPU. */ -static void finish_task_switch (struct rq *rq,struct task_struct *prev) +static struct rq *finish_task_switch (struct task_struct *prev) __releases(rq->lock) { +struct rq *rq =this_rq ();struct mm_struct *mm = rq->prev_mm;long prev_state;
@@ -2275,6 +2280,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) }tick_nohz_task_switch (current); +return rq; }#ifdef CONFIG_SMP
@@ -2313,8 +2319,7 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev)/* finish_task_switch() drops rq->lock and enables preemtion */ preempt_disable (); - rq =this_rq (); -finish_task_switch (rq, prev); + rq =finish_task_switch (prev);post_schedule (rq);preempt_enable ();
@@ -2323,10 +2328,9 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev) }/* -* context_switch - switch to the new MM and the new -* thread's register state. +* context_switch - switch to the new MM and the new thread's register state. */ -static inline void +static inline struct rq *context_switch (struct rq *rq,struct task_struct *prev,struct task_struct *next) {
@@ -2365,14 +2369,9 @@ context_switch(struct rq *rq, struct task_struct *prev,context_tracking_task_switch (prev, next);/* Here we just switch the register state and the stack. */ switch_to (prev, next, prev); -barrier (); -/* -* this_rq must be evaluated again because prev may have moved -* CPUs since it called schedule(), thus the 'rq' on its stack -* frame will be invalid. -*/ -finish_task_switch (this_rq (), prev); + +return finish_task_switch (prev); }/*
@@ -2854,15 +2853,8 @@ need_resched: rq->curr = next; ++*switch_count; -context_switch (rq, prev, next);/* unlocks the rq */ -/* -* The context switch have flipped the stack from under us -* and restored the local variables which were saved when -* this task called schedule() in the past. prev == current -* is still correct, but it can be moved to another cpu/rq. -*/ - cpu =smp_processor_id (); - rq =cpu_rq (cpu); + rq =context_switch (rq, prev, next);/* unlocks the rq */ + cpu =cpu_of (rq); }else raw_spin_unlock_irq (&rq->lock);