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

Commit 27449971 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Paul Mackerras
Browse files

[POWERPC] spusched: Fix runqueue corruption



spu_activate can be called from multiple threads at the same time on
behalf of the same spu context.  We need to make sure to only add it
once to avoid runqueue corruption.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJeremy Kerr <jk@ozlabs.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent c77239b8
Loading
Loading
Loading
Loading
+28 −9
Original line number Original line Diff line number Diff line
@@ -292,13 +292,26 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
 */
 */
static void __spu_add_to_rq(struct spu_context *ctx)
static void __spu_add_to_rq(struct spu_context *ctx)
{
{
	int prio = ctx->prio;
	/*

	 * Unfortunately this code path can be called from multiple threads
	list_add_tail(&ctx->rq, &spu_prio->runq[prio]);
	 * on behalf of a single context due to the way the problem state
	set_bit(prio, spu_prio->bitmap);
	 * mmap support works.
	 *
	 * Fortunately we need to wake up all these threads at the same time
	 * and can simply skip the runqueue addition for every but the first
	 * thread getting into this codepath.
	 *
	 * It's still quite hacky, and long-term we should proxy all other
	 * threads through the owner thread so that spu_run is in control
	 * of all the scheduling activity for a given context.
	 */
	if (list_empty(&ctx->rq)) {
		list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]);
		set_bit(ctx->prio, spu_prio->bitmap);
		if (!spu_prio->nr_waiting++)
		if (!spu_prio->nr_waiting++)
			__mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK);
			__mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK);
	}
	}
}


static void __spu_del_from_rq(struct spu_context *ctx)
static void __spu_del_from_rq(struct spu_context *ctx)
{
{
@@ -440,12 +453,18 @@ int spu_activate(struct spu_context *ctx, unsigned long flags)
{
{
	spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
	spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);


	if (ctx->spu)
		return 0;

	do {
	do {
		struct spu *spu;
		struct spu *spu;


		/*
		 * If there are multiple threads waiting for a single context
		 * only one actually binds the context while the others will
		 * only be able to acquire the state_mutex once the context
		 * already is in runnable state.
		 */
		if (ctx->spu)
			return 0;

		spu = spu_get_idle(ctx);
		spu = spu_get_idle(ctx);
		/*
		/*
		 * If this is a realtime thread we try to get it running by
		 * If this is a realtime thread we try to get it running by