From: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
PREEMPT_RT needs to hand a special state into __schedule() when a task
blocks on a 'sleeping' spin/rwlock. This is required to handle
rcu_note_context_switch() correctly without having special casing in the
RCU code. From an RCU point of view the blocking on the sleeping spinlock
is equivalent to preemption because the task might be in a read side
critical section.
schedule_debug() also has a check which would trigger with the !preempt
case, but that could be handled differently.
To avoid adding another argument and extra checks which cannot be optimized
out by the compiler the following solution has been chosen:
- Replace the boolean 'preempt' argument with an unsigned integer
'sched_mode' argument and define constants to hand in:
(0 == No preemption, 1 = preemption).
- Add two masks to apply on that mode one for the debug/rcu invocations
and one for the actual scheduling decision.
For a non RT kernel these masks are UINT_MAX, i.e. all bits are set
which allows the compiler to optimze the AND operation out because it is
not masking out anything. IOW, it's not different from the boolean.
RT enabled kernels will define these masks seperately.
No functional change.
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
---
kernel/sched/core.c | 36 +++++++++++++++++++++++++-----------
1 file changed, 25 insertions(+), 11 deletions(-)
---
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5822,6 +5822,20 @@ pick_next_task(struct rq *rq, struct tas
#endif /* CONFIG_SCHED_CORE */
/*
+ * Constants for the sched_mode argument of __schedule().
+ *
+ * The mode argument allows RT enabled kernels to differentiate a
+ * preemption from blocking on an 'sleeping' spin/rwlock by having seperate
+ * mask values for SM_MASK_PREEMPT and SM_MASK_STATE while on a non RT
+ * enabled kernel the masks have all bits set which allows the compiler to
+ * optimize the AND operation out.
+ */
+#define SM_NONE 0x0
+#define SM_PREEMPT 0x1
+#define SM_MASK_PREEMPT UINT_MAX
+#define SM_MASK_STATE SM_MASK_PREEMPT