Commit a475c2f4 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Arnd Bergmann

[POWERPC] spufs: remove woken threads from the runqueue early

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: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarArnd Bergmann <arnd.bergmann@de.ibm.com>
parent 390c5343
...@@ -52,6 +52,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) ...@@ -52,6 +52,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
ctx->state = SPU_STATE_SAVED; ctx->state = SPU_STATE_SAVED;
ctx->ops = &spu_backing_ops; ctx->ops = &spu_backing_ops;
ctx->owner = get_task_mm(current); ctx->owner = get_task_mm(current);
INIT_LIST_HEAD(&ctx->rq);
if (gang) if (gang)
spu_gang_add_ctx(gang, ctx); spu_gang_add_ctx(gang, ctx);
ctx->rt_priority = current->rt_priority; ctx->rt_priority = current->rt_priority;
...@@ -76,6 +77,7 @@ void destroy_spu_context(struct kref *kref) ...@@ -76,6 +77,7 @@ void destroy_spu_context(struct kref *kref)
spu_fini_csa(&ctx->csa); spu_fini_csa(&ctx->csa);
if (ctx->gang) if (ctx->gang)
spu_gang_remove_ctx(ctx->gang, ctx); spu_gang_remove_ctx(ctx->gang, ctx);
BUG_ON(!list_empty(&ctx->rq));
kfree(ctx); kfree(ctx);
} }
......
...@@ -245,38 +245,23 @@ static void spu_add_to_rq(struct spu_context *ctx) ...@@ -245,38 +245,23 @@ static void spu_add_to_rq(struct spu_context *ctx)
spin_unlock(&spu_prio->runq_lock); spin_unlock(&spu_prio->runq_lock);
} }
/** static void __spu_del_from_rq(struct spu_context *ctx, int prio)
* spu_del_from_rq - remove a context from the runqueue
* @ctx: context to remove
*/
static void spu_del_from_rq(struct spu_context *ctx)
{ {
spin_lock(&spu_prio->runq_lock); if (!list_empty(&ctx->rq))
list_del_init(&ctx->rq); list_del_init(&ctx->rq);
if (list_empty(&spu_prio->runq[ctx->prio])) if (list_empty(&spu_prio->runq[prio]))
clear_bit(ctx->prio, spu_prio->bitmap); clear_bit(ctx->prio, spu_prio->bitmap);
spin_unlock(&spu_prio->runq_lock);
} }
/** /**
* spu_grab_context - remove one context from the runqueue * spu_del_from_rq - remove a context from the runqueue
* @prio: priority of the context to be removed * @ctx: context to remove
*
* 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) static void spu_del_from_rq(struct spu_context *ctx)
{ {
struct list_head *rq = &spu_prio->runq[prio]; spin_lock(&spu_prio->runq_lock);
__spu_del_from_rq(ctx, ctx->prio);
if (list_empty(rq)) spin_unlock(&spu_prio->runq_lock);
return NULL;
return list_entry(rq->next, struct spu_context, rq);
} }
static void spu_prio_wait(struct spu_context *ctx) static void spu_prio_wait(struct spu_context *ctx)
...@@ -309,8 +294,13 @@ static void spu_reschedule(struct spu *spu) ...@@ -309,8 +294,13 @@ static void spu_reschedule(struct spu *spu)
spin_lock(&spu_prio->runq_lock); spin_lock(&spu_prio->runq_lock);
best = sched_find_first_bit(spu_prio->bitmap); best = sched_find_first_bit(spu_prio->bitmap);
if (best < MAX_PRIO) { if (best < MAX_PRIO) {
struct spu_context *ctx = spu_grab_context(best); struct list_head *rq = &spu_prio->runq[best];
if (ctx) 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); wake_up(&ctx->stop_wq);
} }
spin_unlock(&spu_prio->runq_lock); spin_unlock(&spu_prio->runq_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment