public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Peter Zijlstra <peterz@infradead.org>
To: mingo@kernel.org
Cc: linux-kernel@vger.kernel.org, torvalds@linux-foundation.org,
	fweisbec@gmail.com, oleg@redhat.com, umgwanakikbuti@gmail.com,
	tglx@linutronix.de, rostedt@goodmis.org,
	Peter Zijlstra <peterz@infradead.org>
Subject: [PATCH v2 03/12] sched: Create preempt_count invariant
Date: Wed, 30 Sep 2015 09:10:38 +0200	[thread overview]
Message-ID: <20150930072303.844400616@infradead.org> (raw)
In-Reply-To: 20150930071035.514587432@infradead.org

[-- Attachment #1: peterz-kill-preempt_active-2.patch --]
[-- Type: text/plain, Size: 3831 bytes --]

Assuming units of PREEMPT_DISABLE_OFFSET for preempt_count() numbers.

Now that TASK_DEAD no longer results in preempt_count() == 3 during
scheduling, we will always call context_switch() with preempt_count()
== 2.

However, we don't always end up with preempt_count() == 2 in
finish_task_switch() because new tasks get created with
preempt_count() == 1.

Create FORK_PREEMPT_COUNT and set it to 2 and use that in the right
places. Note that we cannot use INIT_PREEMPT_COUNT as that serves
another purpose (boot).

After this, preempt_count() is invariant across the context switch,
with exception of PREEMPT_ACTIVE.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
 arch/x86/include/asm/preempt.h |    2 +-
 include/asm-generic/preempt.h  |    2 +-
 include/linux/sched.h          |   17 ++++++++++++-----
 kernel/sched/core.c            |   23 +++++++++++++++++++++--
 4 files changed, 35 insertions(+), 9 deletions(-)

--- a/arch/x86/include/asm/preempt.h
+++ b/arch/x86/include/asm/preempt.h
@@ -31,7 +31,7 @@ static __always_inline void preempt_coun
  * must be macros to avoid header recursion hell
  */
 #define init_task_preempt_count(p) do { \
-	task_thread_info(p)->saved_preempt_count = PREEMPT_DISABLED; \
+	task_thread_info(p)->saved_preempt_count = FORK_PREEMPT_COUNT; \
 } while (0)
 
 #define init_idle_preempt_count(p, cpu) do { \
--- a/include/asm-generic/preempt.h
+++ b/include/asm-generic/preempt.h
@@ -24,7 +24,7 @@ static __always_inline void preempt_coun
  * must be macros to avoid header recursion hell
  */
 #define init_task_preempt_count(p) do { \
-	task_thread_info(p)->preempt_count = PREEMPT_DISABLED; \
+	task_thread_info(p)->preempt_count = FORK_PREEMPT_COUNT; \
 } while (0)
 
 #define init_idle_preempt_count(p, cpu) do { \
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -599,11 +599,7 @@ struct task_cputime_atomic {
 		.sum_exec_runtime = ATOMIC64_INIT(0),		\
 	}
 
-#ifdef CONFIG_PREEMPT_COUNT
-#define PREEMPT_DISABLED	(1 + PREEMPT_ENABLED)
-#else
-#define PREEMPT_DISABLED	PREEMPT_ENABLED
-#endif
+#define PREEMPT_DISABLED	(PREEMPT_DISABLE_OFFSET + PREEMPT_ENABLED)
 
 /*
  * Disable preemption until the scheduler is running -- use an unconditional
@@ -613,6 +609,17 @@ struct task_cputime_atomic {
  */
 #define INIT_PREEMPT_COUNT	PREEMPT_OFFSET
 
+/*
+ * Initial preempt_count value; reflects the preempt_count schedule invariant
+ * which states that during context switches:
+ *
+ *    preempt_count() == 2*PREEMPT_DISABLE_OFFSET
+ *
+ * Note: PREEMPT_DISABLE_OFFSET is 0 for !PREEMPT_COUNT kernels.
+ * Note: See finish_task_switch().
+ */
+#define FORK_PREEMPT_COUNT	(2*PREEMPT_DISABLE_OFFSET + PREEMPT_ENABLED)
+
 /**
  * struct thread_group_cputimer - thread group interval timer counts
  * @cputime_atomic:	atomic thread group interval timers.
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2504,6 +2504,18 @@ static struct rq *finish_task_switch(str
 	struct mm_struct *mm = rq->prev_mm;
 	long prev_state;
 
+	/*
+	 * The previous task will have left us with a preempt_count of 2
+	 * because it left us after:
+	 *
+	 *	schedule()
+	 *	  preempt_disable();			// 1
+	 *	  __schedule()
+	 *	    raw_spin_lock_irq(&rq->lock)	// 2
+	 *
+	 * Also, see FORK_PREEMPT_COUNT.
+	 */
+
 	rq->prev_mm = NULL;
 
 	/*
@@ -2588,8 +2600,15 @@ asmlinkage __visible void schedule_tail(
 {
 	struct rq *rq;
 
-	/* finish_task_switch() drops rq->lock and enables preemtion */
-	preempt_disable();
+	/*
+	 * New tasks start with FORK_PREEMPT_COUNT, see there and
+	 * finish_task_switch() for details.
+	 *
+	 * finish_task_switch() will drop rq->lock() and lower preempt_count
+	 * and the preempt_enable() will end up enabling preemption (on
+	 * PREEMPT_COUNT kernels).
+	 */
+
 	rq = finish_task_switch(prev);
 	balance_callback(rq);
 	preempt_enable();



  parent reply	other threads:[~2015-09-30  7:31 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-30  7:10 [PATCH v2 00/12] sched: Killing PREEMPT_ACTIVE Peter Zijlstra
2015-09-30  7:10 ` [PATCH v2 01/12] sched: Simplify INIT_PREEMPT_COUNT Peter Zijlstra
2015-09-30  9:04   ` Steven Rostedt
2015-09-30 20:39     ` Thomas Gleixner
2015-10-01 13:25   ` Frederic Weisbecker
2015-09-30  7:10 ` [PATCH v2 02/12] sched: Rework TASK_DEAD preemption exception Peter Zijlstra
2015-09-30  7:10 ` Peter Zijlstra [this message]
2015-09-30  9:32   ` [PATCH v2 03/12] sched: Create preempt_count invariant Steven Rostedt
2015-09-30 11:13     ` Peter Zijlstra
2015-09-30 13:36       ` Steven Rostedt
2015-09-30  7:10 ` [PATCH v2 04/12] sched: Add preempt argument to __schedule() Peter Zijlstra
2015-09-30  7:10 ` [PATCH v2 05/12] sched: Fix trace_sched_switch() Peter Zijlstra
2015-09-30  7:10 ` [PATCH v2 06/12] sched: Stop setting PREEMPT_ACTIVE Peter Zijlstra
2015-10-01 15:27   ` Frederic Weisbecker
2015-09-30  7:10 ` [PATCH v2 07/12] sched: Robustify preemption leak checks Peter Zijlstra
2015-09-30  9:35   ` Steven Rostedt
2015-09-30  7:10 ` [PATCH v2 08/12] sched: Simplify preempt_count tests Peter Zijlstra
2015-10-01 15:31   ` Frederic Weisbecker
2015-09-30  7:10 ` [PATCH v2 09/12] sched, x86: Kill saved_preempt_count Peter Zijlstra
2015-10-01 15:40   ` Frederic Weisbecker
2015-09-30  7:10 ` [PATCH v2 10/12] sched: Kill PREEMPT_ACTIVE Peter Zijlstra
2015-10-01 15:41   ` Frederic Weisbecker
2015-09-30  7:10 ` [PATCH v2 11/12] sched: More notrace Peter Zijlstra
2015-09-30  7:10 ` [PATCH v2 12/12] sched: Add preempt_count invariant check Peter Zijlstra
2015-09-30  9:38   ` Steven Rostedt
2015-09-30 11:15     ` Peter Zijlstra

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150930072303.844400616@infradead.org \
    --to=peterz@infradead.org \
    --cc=fweisbec@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=oleg@redhat.com \
    --cc=rostedt@goodmis.org \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    --cc=umgwanakikbuti@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox