Skip to content

Commit

Permalink
sched, nohz: Change rq->nr_running to always use wrappers
Browse files Browse the repository at this point in the history
Sometimes ->nr_running may cross 2 but interrupt is not being
sent to rq's cpu. In this case we don't reenable the timer.
Looks like this may be the reason for rare unexpected effects,
if nohz is enabled.

Patch replaces all places of direct changing of nr_running
and makes add_nr_running() caring about crossing border.

Signed-off-by: Kirill Tkhai <tkhai@yandex.ru>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140508225830.2469.97461.stgit@localhost
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Kirill Tkhai authored and Ingo Molnar committed May 22, 2014
1 parent 52a08ef commit 7246544
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 15 deletions.
4 changes: 2 additions & 2 deletions kernel/sched/deadline.c
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ void inc_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)

WARN_ON(!dl_prio(prio));
dl_rq->dl_nr_running++;
inc_nr_running(rq_of_dl_rq(dl_rq));
add_nr_running(rq_of_dl_rq(dl_rq), 1);

inc_dl_deadline(dl_rq, deadline);
inc_dl_migration(dl_se, dl_rq);
Expand All @@ -755,7 +755,7 @@ void dec_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
WARN_ON(!dl_prio(prio));
WARN_ON(!dl_rq->dl_nr_running);
dl_rq->dl_nr_running--;
dec_nr_running(rq_of_dl_rq(dl_rq));
sub_nr_running(rq_of_dl_rq(dl_rq), 1);

dec_dl_deadline(dl_rq, dl_se->deadline);
dec_dl_migration(dl_se, dl_rq);
Expand Down
8 changes: 4 additions & 4 deletions kernel/sched/fair.c
Original file line number Diff line number Diff line change
Expand Up @@ -3325,7 +3325,7 @@ static void throttle_cfs_rq(struct cfs_rq *cfs_rq)
}

if (!se)
rq->nr_running -= task_delta;
sub_nr_running(rq, task_delta);

cfs_rq->throttled = 1;
cfs_rq->throttled_clock = rq_clock(rq);
Expand Down Expand Up @@ -3376,7 +3376,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
}

if (!se)
rq->nr_running += task_delta;
add_nr_running(rq, task_delta);

/* determine whether we need to wake up potentially idle cpu */
if (rq->curr == rq->idle && rq->cfs.nr_running)
Expand Down Expand Up @@ -3908,7 +3908,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)

if (!se) {
update_rq_runnable_avg(rq, rq->nr_running);
inc_nr_running(rq);
add_nr_running(rq, 1);
}
hrtick_update(rq);
}
Expand Down Expand Up @@ -3968,7 +3968,7 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
}

if (!se) {
dec_nr_running(rq);
sub_nr_running(rq, 1);
update_rq_runnable_avg(rq, 1);
}
hrtick_update(rq);
Expand Down
4 changes: 2 additions & 2 deletions kernel/sched/rt.c
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ dequeue_top_rt_rq(struct rt_rq *rt_rq)

BUG_ON(!rq->nr_running);

rq->nr_running -= rt_rq->rt_nr_running;
sub_nr_running(rq, rt_rq->rt_nr_running);
rt_rq->rt_queued = 0;
}

Expand All @@ -989,7 +989,7 @@ enqueue_top_rt_rq(struct rt_rq *rt_rq)
if (rt_rq_throttled(rt_rq) || !rt_rq->rt_nr_running)
return;

rq->nr_running += rt_rq->rt_nr_running;
add_nr_running(rq, rt_rq->rt_nr_running);
rt_rq->rt_queued = 1;
}

Expand Down
12 changes: 7 additions & 5 deletions kernel/sched/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1206,12 +1206,14 @@ extern void update_idle_cpu_load(struct rq *this_rq);

extern void init_task_runnable_average(struct task_struct *p);

static inline void inc_nr_running(struct rq *rq)
static inline void add_nr_running(struct rq *rq, unsigned count)
{
rq->nr_running++;
unsigned prev_nr = rq->nr_running;

rq->nr_running = prev_nr + count;

#ifdef CONFIG_NO_HZ_FULL
if (rq->nr_running == 2) {
if (prev_nr < 2 && rq->nr_running >= 2) {
if (tick_nohz_full_cpu(rq->cpu)) {
/* Order rq->nr_running write against the IPI */
smp_wmb();
Expand All @@ -1221,9 +1223,9 @@ static inline void inc_nr_running(struct rq *rq)
#endif
}

static inline void dec_nr_running(struct rq *rq)
static inline void sub_nr_running(struct rq *rq, unsigned count)
{
rq->nr_running--;
rq->nr_running -= count;
}

static inline void rq_last_tick_reset(struct rq *rq)
Expand Down
4 changes: 2 additions & 2 deletions kernel/sched/stop_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ pick_next_task_stop(struct rq *rq, struct task_struct *prev)
static void
enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
{
inc_nr_running(rq);
add_nr_running(rq, 1);
}

static void
dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags)
{
dec_nr_running(rq);
sub_nr_running(rq, 1);
}

static void yield_task_stop(struct rq *rq)
Expand Down

0 comments on commit 7246544

Please sign in to comment.