[POWERPC] spufs: remove woken threads from the runqueue early
authorChristoph Hellwig <hch@lst.de>
Mon, 23 Apr 2007 19:08:11 +0000 (21:08 +0200)
committerArnd Bergmann <arnd@klappe.arndb.de>
Mon, 23 Apr 2007 19:18:54 +0000 (21:18 +0200)
A single context should only be woken once, and we should not have
more wakeups for a given priority than the number of contexts on
that runqueue position.

Also add some asserts to trap future problems in this area more
easily.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/sched.c

index b3954aba424e2abc5365cd2c65c2b4f3448f9957..065147fb1cc2d3fead081acb9e23c759d4280d43 100644 (file)
@@ -52,6 +52,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
        ctx->state = SPU_STATE_SAVED;
        ctx->ops = &spu_backing_ops;
        ctx->owner = get_task_mm(current);
+       INIT_LIST_HEAD(&ctx->rq);
        if (gang)
                spu_gang_add_ctx(gang, ctx);
        ctx->rt_priority = current->rt_priority;
@@ -76,6 +77,7 @@ void destroy_spu_context(struct kref *kref)
        spu_fini_csa(&ctx->csa);
        if (ctx->gang)
                spu_gang_remove_ctx(ctx->gang, ctx);
+       BUG_ON(!list_empty(&ctx->rq));
        kfree(ctx);
 }
 
index 1582d7645237de6f8a130ee6b7081333dbf5ed40..876828cc95a260175caf9a6d0e6ddf03341da852 100644 (file)
@@ -245,6 +245,14 @@ static void spu_add_to_rq(struct spu_context *ctx)
        spin_unlock(&spu_prio->runq_lock);
 }
 
+static void __spu_del_from_rq(struct spu_context *ctx, int prio)
+{
+       if (!list_empty(&ctx->rq))
+               list_del_init(&ctx->rq);
+       if (list_empty(&spu_prio->runq[prio]))
+               clear_bit(ctx->prio, spu_prio->bitmap);
+}
+
 /**
  * spu_del_from_rq - remove a context from the runqueue
  * @ctx:       context to remove
@@ -252,33 +260,10 @@ static void spu_add_to_rq(struct spu_context *ctx)
 static void spu_del_from_rq(struct spu_context *ctx)
 {
        spin_lock(&spu_prio->runq_lock);
-       list_del_init(&ctx->rq);
-       if (list_empty(&spu_prio->runq[ctx->prio]))
-               clear_bit(ctx->prio, spu_prio->bitmap);
+       __spu_del_from_rq(ctx, ctx->prio);
        spin_unlock(&spu_prio->runq_lock);
 }
 
-/**
- * spu_grab_context - remove one context from the runqueue
- * @prio:      priority of the context to be removed
- *
- * This function removes one context from the runqueue for priority @prio.
- * If there is more than one context with the given priority the first
- * task on the runqueue will be taken.
- *
- * Returns the spu_context it just removed.
- *
- * Must be called with spu_prio->runq_lock held.
- */
-static struct spu_context *spu_grab_context(int prio)
-{
-       struct list_head *rq = &spu_prio->runq[prio];
-
-       if (list_empty(rq))
-               return NULL;
-       return list_entry(rq->next, struct spu_context, rq);
-}
-
 static void spu_prio_wait(struct spu_context *ctx)
 {
        DEFINE_WAIT(wait);
@@ -309,9 +294,14 @@ static void spu_reschedule(struct spu *spu)
        spin_lock(&spu_prio->runq_lock);
        best = sched_find_first_bit(spu_prio->bitmap);
        if (best < MAX_PRIO) {
-               struct spu_context *ctx = spu_grab_context(best);
-               if (ctx)
-                       wake_up(&ctx->stop_wq);
+               struct list_head *rq = &spu_prio->runq[best];
+               struct spu_context *ctx;
+
+               BUG_ON(list_empty(rq));
+
+               ctx = list_entry(rq->next, struct spu_context, rq);
+               __spu_del_from_rq(ctx, best);
+               wake_up(&ctx->stop_wq);
        }
        spin_unlock(&spu_prio->runq_lock);
 }