Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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);
}

+17 −27
Original line number Diff line number Diff line
@@ -245,38 +245,23 @@ static void spu_add_to_rq(struct spu_context *ctx)
	spin_unlock(&spu_prio->runq_lock);
}

/**
 * spu_del_from_rq - remove a context from the runqueue
 * @ctx:       context to remove
 */
static void spu_del_from_rq(struct spu_context *ctx)
static void __spu_del_from_rq(struct spu_context *ctx, int prio)
{
	spin_lock(&spu_prio->runq_lock);
	if (!list_empty(&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);
	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.
 * spu_del_from_rq - remove a context from the runqueue
 * @ctx:       context to remove
 */
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];

	if (list_empty(rq))
		return NULL;
	return list_entry(rq->next, struct spu_context, rq);
	spin_lock(&spu_prio->runq_lock);
	__spu_del_from_rq(ctx, ctx->prio);
	spin_unlock(&spu_prio->runq_lock);
}

static void spu_prio_wait(struct spu_context *ctx)
@@ -309,8 +294,13 @@ 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)
		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);