Sat, 17 May 2008 11:59:19 +0200
2008/5/17, Grzegorz Nosek <grzegorz.nosek@gmail.com>:
> I've been experiencing some weird hangs (boom and it's dead, no panic,
> not even a softlockup or lockdep warning).
(...)
> I think that the solution would be to get some feedback from
> vx_try_unhold about whether any progress can be made at all (e.g. if the
> hold_queue is empty, vx_try_unhold will never change anything and
> vx_try_skip will just keep updating rq->idle_time).
And here's a preliminary patch (compile-tested only) - attached,
unless gmail screws something up.
BTW, any chance of reviving the idea of git.linux-vserver.org?
Best regards,
Grzegorz Nosek
commit b1c3a5c25d9b9301ab197a65247c3f495135fd60
Author: Grzegorz Nosek <root@localdomain.pl>
Date: Sat May 17 10:56:19 2008 +0200
Don't loop forever in scheduler
diff --git a/kernel/sched.c b/kernel/sched.c
index a111b42..218ccdf 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3627,6 +3627,7 @@ asmlinkage void __sched schedule(void)
int cpu, idx, new_prio;
long *switch_count;
struct rq *rq;
+ int can_progress;
/*
* Test if we are atomic. Since do_exit() needs to call into
@@ -3695,12 +3696,17 @@ need_resched_nonpreemptible:
cpu = smp_processor_id();
vx_set_rq_time(rq, jiffies);
try_unhold:
- vx_try_unhold(rq, cpu);
+ can_progress = vx_try_unhold(rq, cpu);
pick_next:
if (unlikely(!rq->nr_running)) {
- /* can we skip idle time? */
- if (vx_try_skip(rq, cpu))
+ /*
+ * can we skip idle time?
+ *
+ * if there are no held tasks, trying to unhold one
+ * will never succeed
+ */
+ if (can_progress && vx_try_skip(rq, cpu))
goto try_unhold;
idle_balance(cpu, rq);
diff --git a/kernel/sched_hard.h b/kernel/sched_hard.h
index 0e95990..0710af5 100644
--- a/kernel/sched_hard.h
+++ b/kernel/sched_hard.h
@@ -171,16 +171,17 @@ int vx_need_resched(struct task_struct *p, int slice, int cpu)
static inline
-void vx_try_unhold(struct rq *rq, int cpu)
+int vx_try_unhold(struct rq *rq, int cpu)
{
struct vx_info *vxi = NULL;
struct list_head *l, *n;
int maxidle = HZ;
int minskip = 0;
+ int can_progress = 0;
/* nothing to do? what about pause? */
if (list_empty(&rq->hold_queue))
- return;
+ return 0;
list_for_each_safe(l, n, &rq->hold_queue) {
int ret, delta_min[2];
@@ -205,6 +206,9 @@ void vx_try_unhold(struct rq *rq, int cpu)
&rq->norm_time, &rq->idle_time, delta_min);
vxm_tokens_recalc(sched_pc, rq, vxi, cpu);
+ /* a task will eventually be runnable, maybe even now */
+ can_progress = 1;
+
if (ret > 0) {
/* we found a runable context */
vx_unhold_task(p, rq);
@@ -216,6 +220,8 @@ void vx_try_unhold(struct rq *rq, int cpu)
vx_set_rq_max_idle(rq, maxidle);
vx_set_rq_min_skip(rq, minskip);
vxm_rq_max_min(rq, cpu);
+
+ return can_progress;
}