Preparatory changes for Proxy Execution v12
Subsystems (3)
v12 cover Preparatory changes for Proxy Execution v12
Hey All,
I wanted to re-send (again) v12 of the preparatory patches for
Proxy Execution - an approach for a generalized form of priority inheritance. Here again, I’m only submitting the early / preparatory changes for review, in the hope that we can move these more straightforward patches along and then iteratively move through the more interesting patches in the Proxy Execution series.
There have been a few changes to the preparatory patches in v12:
* Peter suggested I switch from using “selected” to denote the task chosen to be scheduled, and instead use “donor”
* K Prateek Nayak and Peter both pointed out issues in the “Remove wakeups from under mutex::wait_lock” patch that needed some work to solve.
Thank you for all the detailed review and feedback there!
I’ve also continued working on the rest of the series, which you can find here:
https://github.com/johnstultz-work/linux-dev/commits/proxy-exec-v12-6.11-rc5
https://github.com/johnstultz-work/linux-dev.git proxy-exec-v12-6.11-rc5
New changes in the full series include:
* Avoid donor migrations of SCHED_DEADLINE tasks
* Fix to avoid recently discovered race when bulk migrating the chain
* Propagating rename of rq_selected -> rq->donor
* Rework of ksched_football so it can be triggered repeatedly to run via sysfs
Issues still to address with the full series:
* K Prateek Nayak did some testing with an earlier version of the series and saw ~3-5% regressions in some cases. I’m hoping to look into this soon to see if we can reduce those further.
* The chain migration functionality needs further iterations and better validation to ensure it truly maintains the RT/DL load balancing invariants (despite this being broken in vanilla upstream with RT_PUSH_IPI currently)
* Juri Lelli proposed an alternative approach for handling issues with donor migration and SCHED_DEADLINE. I need to get some time to read over the paper he shared and understand it further.
* Also at OSPM, Thomas Gleixner mentioned we might consider including Proxy Exec in the PREEMPT_RT patch series, however for this to be useful I need to take a stab at deprecating rt_mutexes for proxy mutexes, as everything is an rt_mutex with PREEMPT_RT.
Credit/Disclaimer:
—--------------------
As mentioned previously, this Proxy Execution series has a long history:
First described in a paper[1] by Watkins, Straub, Niehaus, then from patches from Peter Zijlstra, extended with lots of work by Juri Lelli, Valentin Schneider, and Connor O'Brien. (and thank you to Steven Rostedt for providing additional details here!)
So again, many thanks to those above, as all the credit for this
series really is due to them - while the mistakes are likely mine.
Thanks so much!
-john
[1] https://static.lwn.net/images/conf/rtlws11/papers/proc/p38.pdf
Connor O'Brien (2):
sched: Add move_queued_task_locked helper
sched: Consolidate pick_*_task to task_is_pushable helper
John Stultz (1):
sched: Split out __schedule() deactivate task logic into a helper
Juri Lelli (2):
locking/mutex: Make mutex::wait_lock irq safe
locking/mutex: Expose __mutex_owner()
Peter Zijlstra (2):
locking/mutex: Remove wakeups from under mutex::wait_lock
sched: Split scheduler and execution contexts
kernel/futex/pi.c | 6 +- kernel/locking/mutex.c | 59 ++++++--------- kernel/locking/mutex.h | 27 +++++++ kernel/locking/rtmutex.c | 49 ++++++++---- kernel/locking/rtmutex_api.c | 11 ++- kernel/locking/rtmutex_common.h | 3 +- kernel/locking/rwbase_rt.c | 8 +- kernel/locking/rwsem.c | 4 +- kernel/locking/spinlock_rt.c | 3 +- kernel/locking/ww_mutex.h | 51 +++++++------ kernel/sched/core.c | 129 ++++++++++++++++++-------------- kernel/sched/deadline.c | 57 ++++++-------- kernel/sched/fair.c | 32 ++++---- kernel/sched/rt.c | 67 +++++++---------- kernel/sched/sched.h | 50 ++++++++++++- kernel/sched/syscalls.c | 4 +- 16 files changed, 328 insertions(+), 232 deletions(-)
Signature · 1 line
2.46.0.598.g6f2099f65c-goog
PATCH RESEND v12 1/7 locking/mutex: Remove wakeups from under mutex::wait_lock
From: Peter Zijlstra <[email protected]>
In preparation to nest mutex::wait_lock under rq::lock we need to remove wakeups from under it.
Do this by utilizing wake_qs to defer the wakeup until after the lock is dropped.
[Heavily changed after 55f036ca7e74 ("locking: WW mutex cleanup") and 08295b3b5bee ("locking: Implement an algorithm choice for Wound-Wait mutexes")]
[jstultz: rebased to mainline, added extra wake_up_q & init
to avoid hangs, similar to Connor's rework of this patch]
---
v5:
* Reverted back to an earlier version of this patch to undo the change that kept the wake_q in the ctx structure, as that broke the rule that the wake_q must always be on the stack, as its not safe for concurrency.
v6:
* Made tweaks suggested by Waiman Long
v7:
* Fixups to pass wake_qs down for PREEMPT_RT logic
v10:
* Switched preempt_enable to be lower close to the unlock as suggested by Valentin
* Added additional preempt_disable coverage around the wake_q calls as again noted by Valentin
v12:
* Fixes and simplifications from K Prateek Nayak and Peter Zijlstra
* Commit message tweak
--- kernel/futex/pi.c | 6 +++- kernel/locking/mutex.c | 16 ++++++++--- kernel/locking/rtmutex.c | 49 +++++++++++++++++++++++---------- kernel/locking/rtmutex_api.c | 11 ++++++-- kernel/locking/rtmutex_common.h | 3 +- kernel/locking/rwbase_rt.c | 8 +++++- kernel/locking/rwsem.c | 4 +-- kernel/locking/spinlock_rt.c | 3 +- kernel/locking/ww_mutex.h | 30 ++++++++++++-------- 9 files changed, 92 insertions(+), 38 deletions(-)
kernel/futex/pi.c +5 -1
@@ -922,6 +922,7 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int trylstruct rt_mutex_waiter rt_waiter;struct futex_hash_bucket *hb;struct futex_q q = futex_q_init; +DEFINE_WAKE_Q (wake_q);int res, ret;if (!IS_ENABLED (CONFIG_FUTEX_PI ))
@@ -1018,8 +1019,11 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl* such that futex_unlock_pi() is guaranteed to observe the waiter when * it sees the futex_q::pi_state. */ - ret =__rt_mutex_start_proxy_lock (&q.pi_state->pi_mutex, &rt_waiter, current); + ret =__rt_mutex_start_proxy_lock (&q.pi_state->pi_mutex, &rt_waiter, current, &wake_q); +preempt_disable ();raw_spin_unlock_irq (&q.pi_state->pi_mutex.wait_lock); +wake_up_q (&wake_q); +preempt_enable ();if (ret) {if (ret ==1 )
kernel/locking/mutex.c +12 -4
@@ -575,6 +575,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas struct lockdep_map *nest_lock, unsigned long ip, struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) { +DEFINE_WAKE_Q (wake_q );struct mutex_waiter waiter;struct ww_mutex *ww;int ret;
@@ -625,7 +626,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas*/ if (__mutex_trylock (lock)) {if (ww_ctx) -__ww_mutex_check_waiters (lock, ww_ctx); +__ww_mutex_check_waiters (lock, ww_ctx, &wake_q); goto skip_wait; }
@@ -645,7 +646,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas* Add in stamp order, waking up waiters that must kill * themselves. */ - ret =__ww_mutex_add_waiter (&waiter, lock, ww_ctx); + ret =__ww_mutex_add_waiter (&waiter, lock, ww_ctx, &wake_q);if (ret) goto err_early_kill; }
@@ -681,6 +682,10 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas }raw_spin_unlock (&lock->wait_lock); +/* Make sure we do wakeups before calling schedule */ +wake_up_q (&wake_q); +wake_q_init (&wake_q); +schedule_preempt_disabled (); first =__mutex_waiter_is_first (lock, &waiter);
@@ -714,7 +719,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas*/ if (!ww_ctx->is_wait_die && !__mutex_waiter_is_first (lock, &waiter)) -__ww_mutex_check_waiters (lock, ww_ctx); +__ww_mutex_check_waiters (lock, ww_ctx, &wake_q); }__mutex_remove_waiter (lock, &waiter);
@@ -730,6 +735,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclasww_mutex_lock_acquired (ww, ww_ctx);raw_spin_unlock (&lock->wait_lock); +wake_up_q (&wake_q);preempt_enable ();return 0 ;
@@ -741,6 +747,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclasraw_spin_unlock (&lock->wait_lock);debug_mutex_free_waiter (&waiter);mutex_release (&lock->dep_map, ip); +wake_up_q (&wake_q);preempt_enable ();return ret; }
@@ -951,9 +958,10 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigneif (owner &MUTEX_FLAG_HANDOFF )__mutex_handoff (lock, next); +preempt_disable ();raw_spin_unlock (&lock->wait_lock); -wake_up_q (&wake_q); +preempt_enable (); }#ifndef CONFIG_DEBUG_LOCK_ALLOC
kernel/locking/rtmutex.c +35 -14
149 lines not on this page · raw message
kernel/locking/rtmutex_api.c +8 -3
@@ -291,7 +291,8 @@ void __sched rt_mutex_proxy_unlock(struct rt_mutex_base *lock)*/ int __sched __rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,struct rt_mutex_waiter *waiter, -struct task_struct *task) +struct task_struct *task, +struct wake_q_head *wake_q) {int ret;
@@ -302,7 +303,7 @@ int __sched __rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,/* We enforce deadlock detection for futexes */ ret =task_blocks_on_rt_mutex (lock, waiter, task,NULL , -RT_MUTEX_FULL_CHAINWALK ); +RT_MUTEX_FULL_CHAINWALK , wake_q);if (ret && !rt_mutex_owner (lock)) {/*
@@ -341,12 +342,16 @@ int __sched rt_mutex_start_proxy_lock(struct rt_mutex_base *lock, struct task_struct *task) {int ret; +DEFINE_WAKE_Q (wake_q);raw_spin_lock_irq (&lock->wait_lock); - ret =__rt_mutex_start_proxy_lock (lock, waiter, task); + ret =__rt_mutex_start_proxy_lock (lock, waiter, task, &wake_q);if (unlikely (ret))remove_waiter (lock, waiter); +preempt_disable ();raw_spin_unlock_irq (&lock->wait_lock); +wake_up_q (&wake_q); +preempt_enable ();return ret; }
kernel/locking/rtmutex_common.h +2 -1
@@ -83,7 +83,8 @@ extern void rt_mutex_init_proxy_locked(struct rt_mutex_base *lock,extern void rt_mutex_proxy_unlock (struct rt_mutex_base *lock);extern int __rt_mutex_start_proxy_lock (struct rt_mutex_base *lock,struct rt_mutex_waiter *waiter, -struct task_struct *task); +struct task_struct *task, +struct wake_q_head *);extern int rt_mutex_start_proxy_lock (struct rt_mutex_base *lock,struct rt_mutex_waiter *waiter,struct task_struct *task);
kernel/locking/rwbase_rt.c +7 -1
@@ -69,6 +69,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb, unsigned int state) {struct rt_mutex_base *rtm = &rwb->rtmutex; +DEFINE_WAKE_Q (wake_q);int ret;rwbase_pre_schedule ();
@@ -110,7 +111,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,* For rwlocks this returns 0 unconditionally, so the below * !ret conditionals are optimized out. */ - ret =rwbase_rtmutex_slowlock_locked (rtm, state); + ret =rwbase_rtmutex_slowlock_locked (rtm, state, &wake_q);/* * On success the rtmutex is held, so there can't be a writer
@@ -121,7 +122,12 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,*/ if (!ret)atomic_inc (&rwb->readers); + +preempt_disable ();raw_spin_unlock_irq (&rtm->wait_lock); +wake_up_q (&wake_q); +preempt_enable (); +if (!ret)rwbase_rtmutex_unlock (rtm);
kernel/locking/rwsem.c +2 -2
@@ -1415,8 +1415,8 @@ static inline void __downgrade_write(struct rw_semaphore *sem)#define rwbase_rtmutex_lock_state (rtm, state) \ __rt_mutex_lock(rtm, state) -#define rwbase_rtmutex_slowlock_locked (rtm, state) \ - __rt_mutex_slowlock_locked(rtm, NULL, state) +#define rwbase_rtmutex_slowlock_locked (rtm, state, wq) \ + __rt_mutex_slowlock_locked(rtm, NULL, state, wq)#define rwbase_rtmutex_unlock (rtm) \ __rt_mutex_unlock(rtm)
kernel/locking/spinlock_rt.c +2 -1
@@ -162,7 +162,8 @@ rwbase_rtmutex_lock_state(struct rt_mutex_base *rtm, unsigned int state) } static __always_inline int -rwbase_rtmutex_slowlock_locked (struct rt_mutex_base *rtm,unsigned int state) +rwbase_rtmutex_slowlock_locked (struct rt_mutex_base *rtm,unsigned int state, +struct wake_q_head *wake_q) {rtlock_slowlock_locked (rtm);return 0 ;
kernel/locking/ww_mutex.h +19 -11
@@ -275,7 +275,7 @@ __ww_ctx_less(struct ww_acquire_ctx *a, struct ww_acquire_ctx *b)*/ static bool __ww_mutex_die (struct MUTEX *lock,struct MUTEX_WAITER *waiter, -struct ww_acquire_ctx *ww_ctx) +struct ww_acquire_ctx *ww_ctx,struct wake_q_head *wake_q) {if (!ww_ctx->is_wait_die)return false;
@@ -284,7 +284,7 @@ __ww_mutex_die(struct MUTEX *lock, struct MUTEX_WAITER *waiter,#ifndef WW_RT debug_mutex_wake_waiter (lock, waiter);#endif -wake_up_process (waiter->task); +wake_q_add (wake_q, waiter->task); }return true;
@@ -299,7 +299,8 @@ __ww_mutex_die(struct MUTEX *lock, struct MUTEX_WAITER *waiter,*/ static bool __ww_mutex_wound (struct MUTEX *lock,struct ww_acquire_ctx *ww_ctx, -struct ww_acquire_ctx *hold_ctx) +struct ww_acquire_ctx *hold_ctx, +struct wake_q_head *wake_q) {struct task_struct *owner =__ww_mutex_owner (lock);
@@ -331,7 +332,7 @@ static bool __ww_mutex_wound(struct MUTEX *lock,* wakeup pending to re-read the wounded state. */ if (owner != current) -wake_up_process (owner); +wake_q_add (wake_q, owner);return true; }
@@ -352,7 +353,8 @@ static bool __ww_mutex_wound(struct MUTEX *lock,* The current task must not be on the wait list. */ static void -__ww_mutex_check_waiters (struct MUTEX *lock,struct ww_acquire_ctx *ww_ctx) +__ww_mutex_check_waiters (struct MUTEX *lock,struct ww_acquire_ctx *ww_ctx, +struct wake_q_head *wake_q) {struct MUTEX_WAITER *cur;
@@ -364,8 +366,8 @@ __ww_mutex_check_waiters(struct MUTEX *lock, struct ww_acquire_ctx *ww_ctx)if (!cur->ww_ctx)continue ; -if (__ww_mutex_die (lock, cur, ww_ctx) || -__ww_mutex_wound (lock, cur->ww_ctx, ww_ctx)) +if (__ww_mutex_die (lock, cur, ww_ctx, wake_q) || +__ww_mutex_wound (lock, cur->ww_ctx, ww_ctx, wake_q))break ; } }
@@ -377,6 +379,8 @@ __ww_mutex_check_waiters(struct MUTEX *lock, struct ww_acquire_ctx *ww_ctx) static __always_inline voidww_mutex_set_context_fastpath (struct ww_mutex *lock,struct ww_acquire_ctx *ctx) { +DEFINE_WAKE_Q (wake_q); +ww_mutex_lock_acquired (lock, ctx);/*
@@ -405,8 +409,11 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)* die or wound us. */ lock_wait_lock (&lock->base); -__ww_mutex_check_waiters (&lock->base, ctx); +__ww_mutex_check_waiters (&lock->base, ctx, &wake_q); +preempt_disable ();unlock_wait_lock (&lock->base); +wake_up_q (&wake_q); +preempt_enable (); }static __always_inline int
@@ -488,7 +495,8 @@ __ww_mutex_check_kill(struct MUTEX *lock, struct MUTEX_WAITER *waiter,static inline int __ww_mutex_add_waiter (struct MUTEX_WAITER *waiter,struct MUTEX *lock, -struct ww_acquire_ctx *ww_ctx) +struct ww_acquire_ctx *ww_ctx, +struct wake_q_head *wake_q) {struct MUTEX_WAITER *cur, *pos =NULL ;bool is_wait_die;
@@ -532,7 +540,7 @@ __ww_mutex_add_waiter(struct MUTEX_WAITER *waiter, pos = cur;/* Wait-Die: ensure younger waiters die. */ -__ww_mutex_die (lock, cur, ww_ctx); +__ww_mutex_die (lock, cur, ww_ctx, wake_q); }__ww_waiter_add (lock, waiter, pos);
@@ -550,7 +558,7 @@ __ww_mutex_add_waiter(struct MUTEX_WAITER *waiter,* such that either we or the fastpath will wound @ww->ctx. */ smp_mb (); -__ww_mutex_wound (lock, ww_ctx, ww->ctx); +__ww_mutex_wound (lock, ww_ctx, ww->ctx, wake_q); }return 0 ;
Signature · 1 line
2.46.0.598.g6f2099f65c-goog
PATCH RESEND v12 2/7 locking/mutex: Make mutex::wait_lock irq safe
In reply to John StultzFrom: Juri Lelli <[email protected]>
mutex::wait_lock might be nested under rq->lock.
Make it irq safe then.
---
v3:
* Re-added this patch after it was dropped in v2 which caused lockdep warnings to trip.
v7:
* Fix function definition for PREEMPT_RT case, as pointed out by Metin Kaya.
* Fix incorrect flags handling in PREEMPT_RT case as found by Metin Kaya
--- kernel/locking/mutex.c | 18 ++++++++++-------- kernel/locking/ww_mutex.h | 21 +++++++++++---------- 2 files changed, 21 insertions(+), 18 deletions(-)
kernel/locking/mutex.c +10 -8
@@ -578,6 +578,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclasDEFINE_WAKE_Q (wake_q);struct mutex_waiter waiter;struct ww_mutex *ww; +unsigned long flags;int ret;if (!use_ww_ctx)
@@ -620,7 +621,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclasreturn 0 ; } -raw_spin_lock (&lock->wait_lock); +raw_spin_lock_irqsave (&lock->wait_lock, flags);/* * After waiting to acquire the wait_lock, try again. */
@@ -681,7 +682,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas goto err; } -raw_spin_unlock (&lock->wait_lock); +raw_spin_unlock_irqrestore (&lock->wait_lock, flags);/* Make sure we do wakeups before calling schedule */ wake_up_q (&wake_q);wake_q_init (&wake_q);
@@ -706,9 +707,9 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclastrace_contention_begin (lock,LCB_F_MUTEX ); } -raw_spin_lock (&lock->wait_lock); +raw_spin_lock_irqsave (&lock->wait_lock, flags); } -raw_spin_lock (&lock->wait_lock); +raw_spin_lock_irqsave (&lock->wait_lock, flags); acquired:__set_current_state (TASK_RUNNING );
@@ -734,7 +735,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclasif (ww_ctx)ww_mutex_lock_acquired (ww, ww_ctx); -raw_spin_unlock (&lock->wait_lock); +raw_spin_unlock_irqrestore (&lock->wait_lock, flags);wake_up_q (&wake_q);preempt_enable ();return 0 ;
@@ -744,7 +745,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas__mutex_remove_waiter (lock, &waiter); err_early_kill:trace_contention_end (lock, ret); -raw_spin_unlock (&lock->wait_lock); +raw_spin_unlock_irqrestore (&lock->wait_lock, flags);debug_mutex_free_waiter (&waiter);mutex_release (&lock->dep_map, ip);wake_up_q (&wake_q);
@@ -915,6 +916,7 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsignestruct task_struct *next =NULL ;DEFINE_WAKE_Q (wake_q);unsigned long owner; +unsigned long flags;mutex_release (&lock->dep_map, ip);
@@ -941,7 +943,7 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne } } -raw_spin_lock (&lock->wait_lock); +raw_spin_lock_irqsave (&lock->wait_lock, flags);debug_mutex_unlock (lock);if (!list_empty (&lock->wait_list)) {/* get the first entry from the wait-list: */
@@ -959,7 +961,7 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne__mutex_handoff (lock, next);preempt_disable (); -raw_spin_unlock (&lock->wait_lock); +raw_spin_unlock_irqrestore (&lock->wait_lock, flags);wake_up_q (&wake_q);preempt_enable (); }
kernel/locking/ww_mutex.h +11 -10
@@ -70,14 +70,14 @@ __ww_mutex_has_waiters(struct mutex *lock)return atomic_long_read (&lock->owner) &MUTEX_FLAG_WAITERS ; } -static inline void lock_wait_lock (struct mutex *lock) +static inline void lock_wait_lock (struct mutex *lock,unsigned long *flags) { -raw_spin_lock (&lock->wait_lock); +raw_spin_lock_irqsave (&lock->wait_lock, *flags); } -static inline void unlock_wait_lock (struct mutex *lock) +static inline void unlock_wait_lock (struct mutex *lock,unsigned long *flags) { -raw_spin_unlock (&lock->wait_lock); +raw_spin_unlock_irqrestore (&lock->wait_lock, *flags); }static inline void lockdep_assert_wait_lock_held (struct mutex *lock)
@@ -144,14 +144,14 @@ __ww_mutex_has_waiters(struct rt_mutex *lock)return rt_mutex_has_waiters (&lock->rtmutex); } -static inline void lock_wait_lock (struct rt_mutex *lock) +static inline void lock_wait_lock (struct rt_mutex *lock,unsigned long *flags) { -raw_spin_lock (&lock->rtmutex.wait_lock); +raw_spin_lock_irqsave (&lock->rtmutex.wait_lock, *flags); } -static inline void unlock_wait_lock (struct rt_mutex *lock) +static inline void unlock_wait_lock (struct rt_mutex *lock,unsigned long *flags) { -raw_spin_unlock (&lock->rtmutex.wait_lock); +raw_spin_unlock_irqrestore (&lock->rtmutex.wait_lock, *flags); }static inline void lockdep_assert_wait_lock_held (struct rt_mutex *lock)
@@ -380,6 +380,7 @@ static __always_inline void ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) {DEFINE_WAKE_Q (wake_q); +unsigned long flags;ww_mutex_lock_acquired (lock, ctx);
@@ -408,10 +409,10 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)* Uh oh, we raced in fastpath, check if any of the waiters need to * die or wound us. */ -lock_wait_lock (&lock->base); +lock_wait_lock (&lock->base, &flags);__ww_mutex_check_waiters (&lock->base, ctx, &wake_q);preempt_disable (); -unlock_wait_lock (&lock->base); +unlock_wait_lock (&lock->base, &flags);wake_up_q (&wake_q);preempt_enable (); }
Signature · 1 line
2.46.0.598.g6f2099f65c-goog
PATCH RESEND v12 3/7 locking/mutex: Expose __mutex_owner()
In reply to John StultzFrom: Juri Lelli <[email protected]>
Implementing proxy execution requires that scheduler code be able to identify the current owner of a mutex. Expose __mutex_owner() for this purpose (alone!). Includes a null mutex check, so that users of the function can be simplified.
---
v4:
* Move __mutex_owner() to kernel/locking/mutex.h instead of adding a new globally available accessor function to keep the exposure of this low, along with keeping it an inline function, as suggested by PeterZ
v10:
* Handle null lock ptr, to simplify later code, as suggested by Metin Kaya
v11:
* Tweak commit message suggested by Metin Kaya
--- kernel/locking/mutex.c | 25 ------------------------- kernel/locking/mutex.h | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 25 deletions(-)
kernel/locking/mutex.c +0 -25
@@ -56,31 +56,6 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) }EXPORT_SYMBOL (__mutex_init); -/* -* @owner: contains: 'struct task_struct *' to the current lock owner, -* NULL means not owned. Since task_struct pointers are aligned at -* at least L1_CACHE_BYTES, we have low bits to store extra state. -* -* Bit0 indicates a non-empty waiter list; unlock must issue a wakeup. -* Bit1 indicates unlock needs to hand the lock to the top-waiter -* Bit2 indicates handoff has been done and we're waiting for pickup. -*/ -#define MUTEX_FLAG_WAITERS 0x01 -#define MUTEX_FLAG_HANDOFF 0x02 -#define MUTEX_FLAG_PICKUP 0x04 - -#define MUTEX_FLAGS 0x07 - -/* -* Internal helper function; C doesn't allow us to hide it :/ -* -* DO NOT USE (outside of mutex code). -*/ -static inline struct task_struct *__mutex_owner (struct mutex *lock) -{ -return (struct task_struct *)(atomic_long_read (&lock->owner) & ~MUTEX_FLAGS ); -} -static inline struct task_struct *__owner_task (unsigned long owner) {return (struct task_struct *)(owner & ~MUTEX_FLAGS );
kernel/locking/mutex.h +27 -0
@@ -20,6 +20,33 @@ struct mutex_waiter {#endif }; +/* +* @owner: contains: 'struct task_struct *' to the current lock owner, +* NULL means not owned. Since task_struct pointers are aligned at +* at least L1_CACHE_BYTES, we have low bits to store extra state. +* +* Bit0 indicates a non-empty waiter list; unlock must issue a wakeup. +* Bit1 indicates unlock needs to hand the lock to the top-waiter +* Bit2 indicates handoff has been done and we're waiting for pickup. +*/ +#define MUTEX_FLAG_WAITERS 0x01 +#define MUTEX_FLAG_HANDOFF 0x02 +#define MUTEX_FLAG_PICKUP 0x04 + +#define MUTEX_FLAGS 0x07 + +/* +* Internal helper function; C doesn't allow us to hide it :/ +* +* DO NOT USE (outside of mutex & scheduler code). +*/ +static inline struct task_struct *__mutex_owner (struct mutex *lock) +{ +if (!lock) +return NULL ; +return (struct task_struct *)(atomic_long_read (&lock->owner) & ~MUTEX_FLAGS ); +} +#ifdef CONFIG_DEBUG_MUTEXES extern void debug_mutex_lock_common (struct mutex *lock,struct mutex_waiter *waiter);
Signature · 1 line
2.46.0.598.g6f2099f65c-goog
PATCH RESEND v12 4/7 sched: Add move_queued_task_locked helper
In reply to John StultzFrom: Connor O'Brien <[email protected]>
Switch logic that deactivates, sets the task cpu,
and reactivates a task on a different rq to use a
helper that will be later extended to push entire
blocked task chains.
This patch was broken out from a larger chain migration patch originally by Connor O'Brien.
---
v8:
* Renamed from push_task_chain to do_push_task so it makes more sense without proxy-execution
v10:
* Changed name to move_queued_task_locked as suggested by Valentin v11:
* Also use new helper in __migrate_swap_task() and try_steal_cookie() as suggested by Qais Yousef
* Nit cleanups suggested by Metin
--- kernel/sched/core.c | 13 +++---------- kernel/sched/deadline.c | 8 ++------ kernel/sched/rt.c | 8 ++------ kernel/sched/sched.h | 12 ++++++++++++ 4 files changed, 19 insertions(+), 22 deletions(-)
kernel/sched/core.c +3 -10
@@ -2526,9 +2526,7 @@ int push_cpu_stop(void *arg)// XXX validate p is still the highest prio task if (task_rq (p) == rq) { -deactivate_task (rq, p,0 ); -set_task_cpu (p, lowest_rq->cpu); -activate_task (lowest_rq, p,0 ); +move_queued_task_locked (rq, lowest_rq, p);resched_curr (lowest_rq); }
@@ -3214,9 +3212,7 @@ static void __migrate_swap_task(struct task_struct *p, int cpu)rq_pin_lock (src_rq, &srf);rq_pin_lock (dst_rq, &drf); -deactivate_task (src_rq, p,0 ); -set_task_cpu (p, cpu); -activate_task (dst_rq, p,0 ); +move_queued_task_locked (src_rq, dst_rq, p);wakeup_preempt (dst_rq, p,0 );rq_unpin_lock (dst_rq, &drf);
@@ -6152,10 +6148,7 @@ static bool try_steal_cookie(int this, int that)if (sched_task_is_throttled (p, this)) goto next; -deactivate_task (src, p,0 ); -set_task_cpu (p, this); -activate_task (dst, p,0 ); - +move_queued_task_locked (src, dst, p);resched_curr (dst); success = true;
kernel/sched/deadline.c +2 -6
@@ -2447,9 +2447,7 @@ static int push_dl_task(struct rq *rq) goto retry; } -deactivate_task (rq, next_task,0 ); -set_task_cpu (next_task, later_rq->cpu); -activate_task (later_rq, next_task,0 ); +move_queued_task_locked (rq, later_rq, next_task); ret =1 ;resched_curr (later_rq);
@@ -2535,9 +2533,7 @@ static void pull_dl_task(struct rq *this_rq)if (is_migration_disabled (p)) { push_task =get_push_task (src_rq); }else { -deactivate_task (src_rq, p,0 ); -set_task_cpu (p, this_cpu); -activate_task (this_rq, p,0 ); +move_queued_task_locked (src_rq, this_rq, p); dmin = p->dl.deadline; resched = true; }
kernel/sched/rt.c +2 -6
@@ -2105,9 +2105,7 @@ static int push_rt_task(struct rq *rq, bool pull) goto retry; } -deactivate_task (rq, next_task,0 ); -set_task_cpu (next_task, lowest_rq->cpu); -activate_task (lowest_rq, next_task,0 ); +move_queued_task_locked (rq, lowest_rq, next_task);resched_curr (lowest_rq); ret =1 ;
@@ -2378,9 +2376,7 @@ static void pull_rt_task(struct rq *this_rq)if (is_migration_disabled (p)) { push_task =get_push_task (src_rq); }else { -deactivate_task (src_rq, p,0 ); -set_task_cpu (p, this_cpu); -activate_task (this_rq, p,0 ); +move_queued_task_locked (src_rq, this_rq, p); resched = true; }/*
kernel/sched/sched.h +12 -0
@@ -3575,6 +3575,18 @@ static inline void init_sched_mm_cid(struct task_struct *t) { }extern u64 avg_vruntime (struct cfs_rq *cfs_rq);extern int entity_eligible (struct cfs_rq *cfs_rq,struct sched_entity *se); +#ifdef CONFIG_SMP +static inline +void move_queued_task_locked (struct rq *src_rq,struct rq *dst_rq,struct task_struct *task) +{ +lockdep_assert_rq_held (src_rq); +lockdep_assert_rq_held (dst_rq); + +deactivate_task (src_rq, task,0 ); +set_task_cpu (task, dst_rq->cpu); +activate_task (dst_rq, task,0 ); +} +#endif #ifdef CONFIG_RT_MUTEXES
Signature · 1 line
2.46.0.598.g6f2099f65c-goog
PATCH RESEND v12 5/7 sched: Consolidate pick_*_task to task_is_pushable helper
In reply to John StultzFrom: Connor O'Brien <[email protected]>
This patch consolidates rt and deadline pick_*_task functions to a task_is_pushable() helper
This patch was broken out from a larger chain migration patch originally by Connor O'Brien.
[jstultz: split out from larger chain migration patch,
renamed helper function]
---
v7:
* Split from chain migration patch
* Renamed function
v11:
* Switched to bool (though later in the series it goes to a tri-state return) for now to simplify review. Will add tri-state handling later in the series when its needed. Suggested by Metin and others.
--- kernel/sched/deadline.c | 10 +--------- kernel/sched/rt.c | 11 +---------- kernel/sched/sched.h | 10 ++++++++++ 3 files changed, 12 insertions(+), 19 deletions(-)
kernel/sched/deadline.c +1 -9
@@ -2183,14 +2183,6 @@ static void task_fork_dl(struct task_struct *p)/* Only try algorithms three times */ #define DL_MAX_TRIES 3 -static int pick_dl_task (struct rq *rq,struct task_struct *p,int cpu) -{ -if (!task_on_cpu (rq, p) && -cpumask_test_cpu (cpu, &p->cpus_mask)) -return 1 ; -return 0 ; -} -/* * Return the earliest pushable rq's task, which is suitable to be executed * on the CPU, NULL otherwise:
@@ -2209,7 +2201,7 @@ static struct task_struct *pick_earliest_pushable_dl_task(struct rq *rq, int cpuif (next_node) { p =__node_2_pdl (next_node); -if (pick_dl_task (rq, p, cpu)) +if (task_is_pushable (rq, p, cpu))return p; next_node =rb_next (next_node);
kernel/sched/rt.c +1 -10
@@ -1790,15 +1790,6 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)/* Only try algorithms three times */ #define RT_MAX_TRIES 3 -static int pick_rt_task (struct rq *rq,struct task_struct *p,int cpu) -{ -if (!task_on_cpu (rq, p) && -cpumask_test_cpu (cpu, &p->cpus_mask)) -return 1 ; - -return 0 ; -} -/* * Return the highest pushable rq's task, which is suitable to be executed * on the CPU, NULL otherwise
@@ -1812,7 +1803,7 @@ static struct task_struct *pick_highest_pushable_task(struct rq *rq, int cpu)return NULL ;plist_for_each_entry (p, head, pushable_tasks) { -if (pick_rt_task (rq, p, cpu)) +if (task_is_pushable (rq, p, cpu))return p; }
kernel/sched/sched.h +10 -0
@@ -3586,6 +3586,16 @@ void move_queued_task_locked(struct rq *src_rq, struct rq *dst_rq, struct task_sset_task_cpu (task, dst_rq->cpu); activate_task(dst_rq, task, 0); } + +static inline +bool task_is_pushable (struct rq *rq,struct task_struct *p,int cpu) +{ +if (!task_on_cpu (rq, p) && +cpumask_test_cpu (cpu, &p->cpus_mask)) +return true; + +return false; +}#endif #ifdef CONFIG_RT_MUTEXES
Signature · 1 line
2.46.0.598.g6f2099f65c-goog
Re: [RESEND x2][PATCH v12 5/7] sched: Consolidate pick_*_task to task_is_pushable helper
Quoted 118 lines · John Stultz
From: Connor O'Brien <[email protected]>
This patch consolidates rt and deadline pick_*_task functions to a
task_is_pushable()helperThis patch was broken out from a larger chain migration patch originally by Connor O'Brien.
Cc Joel Fernandes <[email protected]>Cc Qais Yousef <[email protected]>Cc Ingo Molnar <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Juri Lelli <[email protected]>Cc Vincent Guittot <[email protected]>Cc Dietmar Eggemann <[email protected]>Cc Valentin Schneider <[email protected]>Cc Steven Rostedt <[email protected]>Cc Ben Segall <[email protected]>Cc Zimuzo Ezeozue <[email protected]>Cc Mel Gorman <[email protected]>Cc Will Deacon <[email protected]>Cc Waiman Long <[email protected]>Cc Boqun Feng <[email protected]>Cc "Paul E. McKenney" <[email protected]>Cc Metin Kaya <[email protected]>Cc Xuewen Yan <[email protected]>Cc K Prateek Nayak <[email protected]>Cc Thomas Gleixner <[email protected]>Cc Daniel Lezcano <[email protected]>Tested-by K Prateek Nayak <[email protected]>Tested-by Metin Kaya <[email protected]>Reviewed-by Metin Kaya <[email protected]>Reviewed-by Valentin Schneider <[email protected]>Signed-off-by Connor O'Brien <[email protected]>[jstultz: split out from larger chain migration patch,
renamed helper function]Signed-off-by John Stultz <[email protected]>---
v7:
* Split from chain migration patch
* Renamed function
v11:
* Switched to bool (though later in the series it goes to a tri-state return) for now to simplify review. Will add tri-state handling later in the series when its needed. Suggested by Metin and others.--- kernel/sched/deadline.c | 10 +--------- kernel/sched/rt.c | 11 +---------- kernel/sched/sched.h | 10 ++++++++++ 3 files changed, 12 insertions(+), 19 deletions(-)kernel/sched/deadline.c +1
-9@@ -2183,14 +2183,6 @@ static void task_fork_dl(struct task_struct *p)/* Only try algorithms three times */ #define DL_MAX_TRIES 3 -static int pick_dl_task (struct rq *rq,struct task_struct *p,int cpu) -{ -if (!task_on_cpu (rq, p) && -cpumask_test_cpu (cpu, &p->cpus_mask)) -return 1 ; -return 0 ; -} -/* * Return the earliest pushable rq's task, which is suitable to be executed * on the CPU, NULL otherwise: @@ -2209,7 +2201,7 @@ static struct task_struct *pick_earliest_pushable_dl_task(struct rq *rq, int cpuif (next_node) { p =__node_2_pdl (next_node); -if (pick_dl_task (rq, p, cpu)) +if (task_is_pushable (rq, p, cpu))return p; next_node =rb_next (next_node);kernel/sched/rt.c +1
-10@@ -1790,15 +1790,6 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)/* Only try algorithms three times */ #define RT_MAX_TRIES 3 -static int pick_rt_task (struct rq *rq,struct task_struct *p,int cpu) -{ -if (!task_on_cpu (rq, p) && -cpumask_test_cpu (cpu, &p->cpus_mask)) -return 1 ; - -return 0 ; -} -/* * Return the highest pushable rq's task, which is suitable to be executed * on the CPU, NULL otherwise @@ -1812,7 +1803,7 @@ static struct task_struct *pick_highest_pushable_task(struct rq *rq, int cpu)return NULL ;plist_for_each_entry (p, head, pushable_tasks) { -if (pick_rt_task (rq, p, cpu)) +if (task_is_pushable (rq, p, cpu))return p; }kernel/sched/sched.h +0
-0@@ -3586,6 +3586,16 @@ void move_queued_task_locked(struct rq *src_rq, struct rq *dst_rq, struct task_sset_task_cpu (task, dst_rq->cpu);activate_task (dst_rq, task,0 ); }
kernel/sched/sched.h void move_queued_task_locked(struct rq *src_rq, struct rq *dst_rq, struct task_s · line 3598
Quoted 10 lines
kernel/sched/sched.h +10
-0+ +static inline +bool task_is_pushable (struct rq *rq,struct task_struct *p,int cpu) +{ +if (!task_on_cpu (rq, p) && +cpumask_test_cpu (cpu, &p->cpus_mask)) +return true; + +return false; +}
The slightly awkward
if (condition)
return true;
return false;
is more convenient for you for the tri-state later, I assume. Fine by me FWIW.
Re: [RESEND x2][PATCH v12 5/7] sched: Consolidate pick_*_task to task_is_pushable helper
Quoted 13 lines · Christian Loehle
kernel/sched/sched.h void move_queued_task_locked(struct rq *src_rq, struct rq *dst_rq, struct task_s · line 3598
Quoted 9 lines · John Stultz
kernel/sched/sched.h +9
-0+static inline +bool task_is_pushable (struct rq *rq,struct task_struct *p,int cpu) +{ +if (!task_on_cpu (rq, p) && +cpumask_test_cpu (cpu, &p->cpus_mask)) +return true; + +return false; +}The slightly awkward
if (condition)
Quoted 6 lines
return true;return false;
is more convenient for you for the tri-state later, I assume. Fine by me FWIW.
Reviewed-by Christian Loehle <[email protected]>
Thanks so much for the review! Very much appreciate it! -john
PATCH RESEND v12 6/7 sched: Split out __schedule() deactivate task logic into a helper
In reply to John StultzAs we're going to re-use the deactivation logic, split it into a helper.
---
v6:
* Define function as static to avoid "no previous prototype" warnings as Reported-by: kernel test robot <[email protected]>
v7:
* Rename state task_state to be more clear, as suggested by Metin Kaya
v11:
* Return early to simplify indentation, and drop unused bool return (will be introduced later when its needed) as sugggested by Qais.
--- kernel/sched/core.c | 71 +++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 29 deletions(-)
kernel/sched/core.c +42 -29
@@ -6349,6 +6349,47 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)# define SM_MASK_PREEMPT SM_PREEMPT#endif +/* +* Helper function for __schedule() +* +* If a task does not have signals pending, deactivate it +* Otherwise marks the task's __state as RUNNING +*/ +static void try_to_deactivate_task (struct rq *rq,struct task_struct *p, +unsigned long task_state) +{ +if (signal_pending_state (task_state, p)) { +WRITE_ONCE (p->__state,TASK_RUNNING ); +return ; + } + + p->sched_contributes_to_load = + (task_state &TASK_UNINTERRUPTIBLE ) && + !(task_state &TASK_NOLOAD ) && + !(task_state &TASK_FROZEN ); + +if (p->sched_contributes_to_load) + rq->nr_uninterruptible++; + +/* +* __schedule() ttwu() +* prev_state = prev->state; if (p->on_rq && ...) +* if (prev_state) goto out; +* p->on_rq = 0; smp_acquire__after_ctrl_dep(); +* p->state = TASK_WAKING +* +* Where __schedule() and ttwu() have matching control dependencies. +* +* After this, schedule() must not care about p->state any more. +*/ +deactivate_task (rq, p,DEQUEUE_SLEEP |DEQUEUE_NOCLOCK ); + +if (p->in_iowait) { +atomic_inc (&rq->nr_iowait); +delayacct_blkio_start (); + } +} +/* * __schedule() is the main scheduler function. *
@@ -6442,35 +6483,7 @@ static void __sched notrace __schedule(unsigned int sched_mode)*/ prev_state =READ_ONCE (prev->__state);if (!(sched_mode &SM_MASK_PREEMPT ) && prev_state) { -if (signal_pending_state (prev_state, prev)) { -WRITE_ONCE (prev->__state,TASK_RUNNING ); - }else { - prev->sched_contributes_to_load = - (prev_state &TASK_UNINTERRUPTIBLE ) && - !(prev_state &TASK_NOLOAD ) && - !(prev_state &TASK_FROZEN ); - -if (prev->sched_contributes_to_load) - rq->nr_uninterruptible++; - -/* -* __schedule() ttwu() -* prev_state = prev->state; if (p->on_rq && ...) -* if (prev_state) goto out; -* p->on_rq = 0; smp_acquire__after_ctrl_dep(); -* p->state = TASK_WAKING -* -* Where __schedule() and ttwu() have matching control dependencies. -* -* After this, schedule() must not care about p->state any more. -*/ -deactivate_task (rq, prev,DEQUEUE_SLEEP |DEQUEUE_NOCLOCK ); - -if (prev->in_iowait) { -atomic_inc (&rq->nr_iowait); -delayacct_blkio_start (); - } - } +try_to_deactivate_task (rq, prev, prev_state); switch_count = &prev->nvcsw; }
Signature · 1 line
2.46.0.598.g6f2099f65c-goog
PATCH RESEND v12 7/7 sched: Split scheduler and execution contexts
In reply to John StultzFrom: Peter Zijlstra <[email protected]>
Let's define the "scheduling context" as all the scheduler state in task_struct for the task chosen to run, which we'll call the donor task, and the "execution context" as all state required to actually run the task.
Currently both are intertwined in task_struct. We want to logically split these such that we can use the scheduling context of the donor task selected to be scheduled, but use the execution context of a different task to actually be run.
To this purpose, introduce rq->donor field to point to the task_struct chosen from the runqueue by the scheduler, and will be used for scheduler state, and preserve rq->curr to indicate the execution context of the task that will actually be run.
This patch introduces the donor field as a union with curr, so it doesn't cause the contexts to be split yet, but adds the logic to handle everything separately.
[add additional comments and update more sched_class code to use
rq::proxy]
[jstultz: Rebased and resolved minor collisions, reworked to use
accessors, tweaked update_curr_common to use rq_proxy fixing rt scheduling issues]
---
v2:
* Reworked to use accessors
* Fixed update_curr_common to use proxy instead of curr v3:
* Tweaked wrapper names
* Swapped proxy for selected for clarity
v4:
* Minor variable name tweaks for readability
* Use a macro instead of a inline function and drop
other helper functions as suggested by Peter.
* Remove verbose comments/questions to avoid review distractions, as suggested by Dietmar
v5:
* Add CONFIG_PROXY_EXEC option to this patch so the
new logic can be tested with this change
* Minor fix to grab rq_selected when holding the rq lock v7:
* Minor spelling fix and unused argument fixes suggested by Metin Kaya
* Switch to curr_selected for consistency, and minor rewording of commit message for clarity
* Rename variables selected instead of curr when we're using rq_selected()
* Reduce macros in CONFIG_SCHED_PROXY_EXEC ifdef sections, as suggested by Metin Kaya
v8:
* Use rq->curr, not rq_selected with task_tick, as suggested by Valentin
* Minor rework to reorder this with CONFIG_SCHED_PROXY_EXEC patch v10:
* Use rq_selected in push_rt_task & get_push_task
v11:
* Rework to use selected instead of curr in a few cases we were previously assigning curr = rq_selected() to minimize lines of change. Suggested by Metin.
v12:
* Big rename to use rq->donor instead of rq_selected(), as suggested by Peter.
--- kernel/sched/core.c | 45 +++++++++++++++++++++++--------------- kernel/sched/deadline.c | 39 +++++++++++++++++---------------- kernel/sched/fair.c | 32 +++++++++++++-------------- kernel/sched/rt.c | 48 ++++++++++++++++++++--------------------- kernel/sched/sched.h | 28 +++++++++++++++++++++--- kernel/sched/syscalls.c | 4 ++-- 6 files changed, 115 insertions(+), 81 deletions(-)
kernel/sched/core.c +28 -17
@@ -794,7 +794,7 @@ static enum hrtimer_restart hrtick(struct hrtimer *timer)rq_lock (rq, &rf);update_rq_clock (rq); - rq->curr->sched_class->task_tick (rq, rq->curr,1 ); + rq->donor->sched_class->task_tick (rq, rq->curr,1 );rq_unlock (rq, &rf);return HRTIMER_NORESTART ;
@@ -2053,16 +2053,18 @@ void check_class_changed(struct rq *rq, struct task_struct *p,void wakeup_preempt (struct rq *rq,struct task_struct *p,int flags) { -if (p->sched_class == rq->curr->sched_class) - rq->curr->sched_class->wakeup_preempt (rq, p, flags); -else if (sched_class_above (p->sched_class, rq->curr->sched_class)) +struct task_struct *donor = rq->donor; + +if (p->sched_class == donor->sched_class) + donor->sched_class->wakeup_preempt (rq, p, flags); +else if (sched_class_above (p->sched_class, donor->sched_class))resched_curr (rq);/* * A queue event has occurred, and we're going to schedule. In * this case, we can save a useless back to back clock update. */ -if (task_on_rq_queued (rq->curr) &&test_tsk_need_resched (rq->curr)) +if (task_on_rq_queued (donor) &&test_tsk_need_resched (rq->curr))rq_clock_skip_update (rq); }
@@ -2586,7 +2588,7 @@ __do_set_cpus_allowed(struct task_struct *p, struct affinity_context *ctx)lockdep_assert_held (&p->pi_lock); queued =task_on_rq_queued (p); - running =task_current (rq, p); + running =task_current_donor (rq, p);if (queued) {/*
@@ -5373,7 +5375,7 @@ unsigned long long task_sched_runtime(struct task_struct *p)* project cycles that may never be accounted to this * thread, breaking clock_gettime(). */ -if (task_current (rq, p) &&task_on_rq_queued (p)) { +if (task_current_donor (rq, p) &&task_on_rq_queued (p)) {prefetch_curr_exec_start (p);update_rq_clock (rq); p->sched_class->update_curr (rq);
@@ -5441,7 +5443,8 @@ void sched_tick(void) {int cpu =smp_processor_id ();struct rq *rq =cpu_rq (cpu); -struct task_struct *curr; +/* accounting goes to the donor task */ +struct task_struct *donor;struct rq_flags rf;unsigned long hw_pressure;u64 resched_latency;
@@ -5452,19 +5455,19 @@ void sched_tick(void)sched_clock_tick ();rq_lock (rq, &rf); + donor = rq->donor; - curr = rq->curr; -psi_account_irqtime (rq, curr,NULL ); +psi_account_irqtime (rq, donor,NULL );update_rq_clock (rq); hw_pressure =arch_scale_hw_pressure (cpu_of (rq));update_hw_load_avg (rq_clock_task (rq), rq, hw_pressure); - curr->sched_class->task_tick (rq, curr,0 ); + donor->sched_class->task_tick (rq, donor,0 );if (sched_feat (LATENCY_WARN )) resched_latency =cpu_resched_latency (rq);calc_global_load_tick (rq);sched_core_tick (rq); -task_tick_mm_cid (rq, curr); +task_tick_mm_cid (rq, donor);rq_unlock (rq, &rf);
@@ -5473,8 +5476,8 @@ void sched_tick(void)perf_event_task_tick (); -if (curr->flags &PF_WQ_WORKER ) -wq_worker_tick (curr); +if (donor->flags &PF_WQ_WORKER ) +wq_worker_tick (donor);#ifdef CONFIG_SMP rq->idle_balance =idle_cpu (cpu);
@@ -5539,6 +5542,12 @@ static void sched_tick_remote(struct work_struct *work)struct task_struct *curr = rq->curr;if (cpu_online (cpu)) { +/* +* Since this is a remote tick for full dynticks mode, +* we are always sure that there is no proxy (only a +* single task is running). +*/ +SCHED_WARN_ON (rq->curr != rq->donor);update_rq_clock (rq);if (!is_idle_task (curr)) {
@@ -6488,6 +6497,7 @@ static void __sched notrace __schedule(unsigned int sched_mode) } next =pick_next_task (rq, prev, &rf); +rq_set_donor (rq, next);clear_tsk_need_resched (prev);clear_preempt_need_resched ();#ifdef CONFIG_SCHED_DEBUG
@@ -6984,7 +6994,7 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task) prev_class = p->sched_class; queued =task_on_rq_queued (p); - running =task_current (rq, p); + running =task_current_donor (rq, p);if (queued)dequeue_task (rq, p, queue_flag);if (running)
@@ -7552,6 +7562,7 @@ void __init init_idle(struct task_struct *idle, int cpu)rcu_read_unlock (); rq->idle = idle; +rq_set_donor (rq, idle);rcu_assign_pointer (rq->curr, idle); idle->on_rq =TASK_ON_RQ_QUEUED ;#ifdef CONFIG_SMP
@@ -7641,7 +7652,7 @@ void sched_setnuma(struct task_struct *p, int nid) rq =task_rq_lock (p, &rf); queued =task_on_rq_queued (p); - running =task_current (rq, p); + running =task_current_donor (rq, p);if (queued)dequeue_task (rq, p,DEQUEUE_SAVE );
@@ -8772,7 +8783,7 @@ void sched_move_task(struct task_struct *tsk)update_rq_clock (rq); - running =task_current (rq, tsk); + running =task_current_donor (rq, tsk); queued =task_on_rq_queued (tsk);if (queued)
kernel/sched/deadline.c +20 -19
@@ -1217,7 +1217,7 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer)#endif enqueue_task_dl (rq, p,ENQUEUE_REPLENISH ); -if (dl_task (rq->curr)) +if (dl_task (rq->donor))wakeup_preempt_dl (rq, p,0 );else resched_curr (rq);
@@ -1441,11 +1441,11 @@ void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,*/ static void update_curr_dl (struct rq *rq) { -struct task_struct *curr = rq->curr; -struct sched_dl_entity *dl_se = &curr->dl; +struct task_struct *donor = rq->donor; +struct sched_dl_entity *dl_se = &donor->dl;s64 delta_exec; -if (!dl_task (curr) || !on_dl_rq (dl_se)) +if (!dl_task (donor) || !on_dl_rq (dl_se))return ;/*
@@ -1903,7 +1903,7 @@ static int find_later_rq(struct task_struct *task);static int select_task_rq_dl (struct task_struct *p,int cpu,int flags) { -struct task_struct *curr; +struct task_struct *curr, *donor;bool select_rq;struct rq *rq;
@@ -1914,6 +1914,7 @@ select_task_rq_dl(struct task_struct *p, int cpu, int flags)rcu_read_lock (); curr =READ_ONCE (rq->curr);/* unlocked access */ + donor =READ_ONCE (rq->donor);/* * If we are dealing with a -deadline task, we must
@@ -1924,9 +1925,9 @@ select_task_rq_dl(struct task_struct *p, int cpu, int flags)* other hand, if it has a shorter deadline, we * try to make it stay here, it might be important. */ - select_rq =unlikely (dl_task (curr)) && + select_rq =unlikely (dl_task (donor)) && (curr->nr_cpus_allowed <2 || - !dl_entity_preempt (&p->dl, &curr->dl)) && + !dl_entity_preempt (&p->dl, &donor->dl)) && p->nr_cpus_allowed >1 ;/*
@@ -1989,7 +1990,7 @@ static void check_preempt_equal_dl(struct rq *rq, struct task_struct *p)* let's hope p can move out. */ if (rq->curr->nr_cpus_allowed ==1 || - !cpudl_find (&rq->rd->cpudl, rq->curr,NULL )) + !cpudl_find (&rq->rd->cpudl, rq->donor,NULL ))return ;/*
@@ -2028,7 +2029,7 @@ static int balance_dl(struct rq *rq, struct task_struct *p, struct rq_flags *rf)static void wakeup_preempt_dl (struct rq *rq,struct task_struct *p,int flags) { -if (dl_entity_preempt (&p->dl, &rq->curr->dl)) { +if (dl_entity_preempt (&p->dl, &rq->donor->dl)) {resched_curr (rq);return ; }
@@ -2038,7 +2039,7 @@ static void wakeup_preempt_dl(struct rq *rq, struct task_struct *p,* In the unlikely case current and p have the same deadline * let us try to decide what's the best thing to do... */ -if ((p->dl.deadline == rq->curr->dl.deadline) && +if ((p->dl.deadline == rq->donor->dl.deadline) && !test_tsk_need_resched (rq->curr))check_preempt_equal_dl (rq, p);#endif /* CONFIG_SMP */
@@ -2070,7 +2071,7 @@ static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)if (!first)return ; -if (rq->curr->sched_class != &dl_sched_class) +if (rq->donor->sched_class != &dl_sched_class)update_dl_rq_load_avg (rq_clock_pelt (rq), rq,0 );deadline_queue_push_tasks (rq);
@@ -2395,8 +2396,8 @@ static int push_dl_task(struct rq *rq)* can move away, it makes sense to just reschedule * without going further in pushing next_task. */ -if (dl_task (rq->curr) && -dl_time_before (next_task->dl.deadline, rq->curr->dl.deadline) && +if (dl_task (rq->donor) && +dl_time_before (next_task->dl.deadline, rq->donor->dl.deadline) && rq->curr->nr_cpus_allowed >1 ) {resched_curr (rq);return 0 ;
@@ -2519,7 +2520,7 @@ static void pull_dl_task(struct rq *this_rq)* deadline than the current task of its runqueue. */ if (dl_time_before (p->dl.deadline, - src_rq->curr->dl.deadline)) + src_rq->donor->dl.deadline)) goto skip;if (is_migration_disabled (p)) {
@@ -2558,9 +2559,9 @@ static void task_woken_dl(struct rq *rq, struct task_struct *p)if (!task_on_cpu (rq, p) && !test_tsk_need_resched (rq->curr) && p->nr_cpus_allowed >1 && -dl_task (rq->curr) && +dl_task (rq->donor) && (rq->curr->nr_cpus_allowed <2 || - !dl_entity_preempt (&p->dl, &rq->curr->dl))) { + !dl_entity_preempt (&p->dl, &rq->donor->dl))) {push_dl_tasks (rq); } }
@@ -2735,12 +2736,12 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)return ; } -if (rq->curr != p) { +if (rq->donor != p) {#ifdef CONFIG_SMP if (p->nr_cpus_allowed >1 && rq->dl.overloaded)deadline_queue_push_tasks (rq);#endif -if (dl_task (rq->curr)) +if (dl_task (rq->donor))wakeup_preempt_dl (rq, p,0 );else resched_curr (rq);
@@ -2769,7 +2770,7 @@ static void prio_changed_dl(struct rq *rq, struct task_struct *p,if (!rq->dl.overloaded)deadline_queue_pull_task (rq); -if (task_current (rq, p)) { +if (task_current_donor (rq, p)) {/* * If we now have a earlier deadline task than p, * then reschedule, provided p is still on this
kernel/sched/fair.c +16 -16
@@ -1140,12 +1140,12 @@ static inline void update_curr_task(struct task_struct *p, s64 delta_exec)*/ s64 update_curr_common (struct rq *rq) { -struct task_struct *curr = rq->curr; +struct task_struct *donor = rq->donor;s64 delta_exec; - delta_exec =update_curr_se (rq, &curr->se); + delta_exec =update_curr_se (rq, &donor->se);if (likely (delta_exec >0 )) -update_curr_task (curr, delta_exec); +update_curr_task (donor, delta_exec);return delta_exec; }
@@ -1177,7 +1177,7 @@ static void update_curr(struct cfs_rq *cfs_rq)static void update_curr_fair (struct rq *rq) { -update_curr (cfs_rq_of (&rq->curr->se)); +update_curr (cfs_rq_of (&rq->donor->se)); } static inline void
@@ -6645,7 +6645,7 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p)s64 delta = slice - ran;if (delta <0 ) { -if (task_current (rq, p)) +if (task_current_donor (rq, p))resched_curr (rq);return ; }
@@ -6660,12 +6660,12 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p)*/ static void hrtick_update (struct rq *rq) { -struct task_struct *curr = rq->curr; +struct task_struct *donor = rq->donor; -if (!hrtick_enabled_fair (rq) || curr->sched_class != &fair_sched_class) +if (!hrtick_enabled_fair (rq) || donor->sched_class != &fair_sched_class)return ; -hrtick_start_fair (rq, curr); +hrtick_start_fair (rq, donor); }#else /* !CONFIG_SCHED_HRTICK */ static inline void
@@ -8347,9 +8347,9 @@ static void set_next_buddy(struct sched_entity *se)*/ static void check_preempt_wakeup_fair (struct rq *rq,struct task_struct *p,int wake_flags) { -struct task_struct *curr = rq->curr; -struct sched_entity *se = &curr->se, *pse = &p->se; -struct cfs_rq *cfs_rq =task_cfs_rq (curr); +struct task_struct *donor = rq->donor; +struct sched_entity *se = &donor->se, *pse = &p->se; +struct cfs_rq *cfs_rq =task_cfs_rq (donor);int cse_is_idle, pse_is_idle;if (unlikely (se == pse))
@@ -8378,11 +8378,11 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int* prevents us from potentially nominating it as a false LAST_BUDDY * below. */ -if (test_tsk_need_resched (curr)) +if (test_tsk_need_resched (rq->curr))return ;/* Idle tasks are by definition preempted by non-idle tasks. */ -if (unlikely (task_has_idle_policy (curr)) && +if (unlikely (task_has_idle_policy (donor)) &&likely (!task_has_idle_policy (p))) goto preempt;
@@ -9356,7 +9356,7 @@ static bool __update_blocked_others(struct rq *rq, bool *done)* update_load_avg() can call cpufreq_update_util(). Make sure that RT, * DL and IRQ signals have been updated before updating CFS. */ - curr_class = rq->curr->sched_class; + curr_class = rq->donor->sched_class; hw_pressure =arch_scale_hw_pressure (cpu_of (rq));
@@ -12738,7 +12738,7 @@ prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio)* our priority decreased, or if we are not currently running on * this runqueue and our priority is higher than the current's */ -if (task_current (rq, p)) { +if (task_current_donor (rq, p)) {if (p->prio > oldprio)resched_curr (rq); }else
@@ -12843,7 +12843,7 @@ static void switched_to_fair(struct rq *rq, struct task_struct *p)* kick off the schedule if running, otherwise just see * if we can still preempt the current task. */ -if (task_current (rq, p)) +if (task_current_donor (rq, p))resched_curr (rq);else wakeup_preempt (rq, p,0 );
kernel/sched/rt.c +24 -24
160 lines not on this page · raw message
kernel/sched/sched.h +25 -3
@@ -1058,7 +1058,10 @@ struct rq {*/ unsigned int nr_uninterruptible; -struct task_struct __rcu *curr; +union { +struct task_struct __rcu *donor;/* Scheduler context */ +struct task_struct __rcu *curr;/* Execution context */ + };struct task_struct *idle;struct task_struct *stop;unsigned long next_balance;
@@ -1254,6 +1257,11 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);#define cpu_curr (cpu) (cpu_rq(cpu)->curr)#define raw_rq () raw_cpu_ptr(&runqueues) +static inline void rq_set_donor (struct rq *rq,struct task_struct *t) +{ +/* Do nothing */ +} +#ifdef CONFIG_SCHED_CORE static inline struct cpumask *sched_group_span (struct sched_group *sg);
@@ -2170,11 +2178,25 @@ static inline u64 global_rt_runtime(void)return (u64 )sysctl_sched_rt_runtime *NSEC_PER_USEC ; } +/* +* Is p the current execution context? +*/ static inline int task_current (struct rq *rq,struct task_struct *p) {return rq->curr == p; } +/* +* Is p the current scheduling context? +* +* Note that it might be the current execution context at the same time if +* rq->curr == rq->donor == p. +*/ +static inline int task_current_donor (struct rq *rq,struct task_struct *p) +{ +return rq->donor == p; +} +static inline int task_on_cpu (struct rq *rq,struct task_struct *p) {#ifdef CONFIG_SMP
@@ -2344,7 +2366,7 @@ struct sched_class {static inline void put_prev_task (struct rq *rq,struct task_struct *prev) { -WARN_ON_ONCE (rq->curr != prev); +WARN_ON_ONCE (rq->donor != prev); prev->sched_class->put_prev_task (rq, prev); }
@@ -2436,7 +2458,7 @@ static inline cpumask_t *alloc_user_cpus_ptr(int node)static inline struct task_struct *get_push_task (struct rq *rq) { -struct task_struct *p = rq->curr; +struct task_struct *p = rq->donor;lockdep_assert_rq_held (rq);
kernel/sched/syscalls.c +2 -2
@@ -91,7 +91,7 @@ void set_user_nice(struct task_struct *p, long nice) } queued =task_on_rq_queued (p); - running =task_current (rq, p); + running =task_current_donor (rq, p);if (queued)dequeue_task (rq, p,DEQUEUE_SAVE |DEQUEUE_NOCLOCK );if (running)
@@ -784,7 +784,7 @@ int __sched_setscheduler(struct task_struct *p, } queued =task_on_rq_queued (p); - running =task_current (rq, p); + running =task_current_donor (rq, p);if (queued)dequeue_task (rq, p, queue_flags);if (running)
Signature · 1 line
2.46.0.598.g6f2099f65c-goog