[Cbe-oss-dev] PATCH [7/7] fix time slicing
Luke Browning
lukebr at linux.vnet.ibm.com
Thu Nov 1 11:07:25 EST 2007
This patch avoids a deadlock in time slicing code surrounding
the use of the cbe_spu_info lock.
Signed-off-by: Luke Browning <lukebr at linux.vnet.ibm.com>
---
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/sched.c
@@ -146,6 +146,10 @@ void spu_update_sched_info(struct spu_co
if (ctx->state == SPU_STATE_RUNNABLE) {
node = ctx->spu->node;
+
+ /*
+ * Take cbe_spu_info[] lock to sync with find_victim().
+ */
mutex_lock(&cbe_spu_info[node].list_mutex);
__spu_update_sched_info(ctx);
mutex_unlock(&cbe_spu_info[node].list_mutex);
@@ -666,9 +670,10 @@ static struct spu *find_victim(struct sp
victim->stats.invol_ctx_switch++;
spu->stats.invol_ctx_switch++;
+ spu_add_to_rq(victim);
+
mutex_unlock(&victim->state_mutex);
- spu_add_to_rq(victim);
return spu;
}
}
@@ -695,7 +700,7 @@ static void __spu_schedule(struct spu *s
if (success)
wake_up_all(&ctx->run_wq);
else
- __spu_add_to_rq(ctx);
+ spu_add_to_rq(ctx);
}
static void spu_schedule(struct spu *spu, struct spu_context *ctx)
@@ -859,36 +864,37 @@ void spu_yield(struct spu_context *ctx)
static noinline void spusched_tick(struct spu_context *ctx)
{
+ struct spu_context *new = NULL;
+ struct spu *spu;
+ u32 status;
+
+ spu_acquire(ctx);
+
+ if (ctx->state != SPU_STATE_RUNNABLE)
+ goto out;
+ if (spu_stopped(ctx, &status))
+ goto out;
if (ctx->flags & SPU_CREATE_NOSCHED)
- return;
+ goto out;
if (ctx->policy == SCHED_FIFO)
- return;
+ goto out;
if (--ctx->time_slice)
- return;
-
- /*
- * Unfortunately list_mutex ranks outside of state_mutex, so
- * we have to trylock here. If we fail give the context another
- * tick and try again.
- */
- if (mutex_trylock(&ctx->state_mutex)) {
- struct spu *spu = ctx->spu;
- struct spu_context *new;
+ goto out;
- new = grab_runnable_context(ctx->prio + 1, spu->node);
- if (new) {
- spu_unschedule(spu, ctx);
- spu_add_to_rq(ctx);
- } else {
- spu_set_timeslice(ctx);
- }
- mutex_unlock(&ctx->state_mutex);
- if (new)
- spu_schedule(spu, new);
+ spu = ctx->spu;
+ new = grab_runnable_context(ctx->prio + 1, spu->node);
+ if (new) {
+ spu_unschedule(spu, ctx);
+ spu_add_to_rq(ctx);
} else {
ctx->time_slice++;
}
+out:
+ spu_release(ctx);
+
+ if (new)
+ spu_schedule(spu, new);
}
/**
@@ -945,6 +951,7 @@ static void spusched_wake(unsigned long
static int spusched_thread(void *unused)
{
+ struct list_head *tmp, *cur;
struct spu *spu;
int node;
@@ -953,9 +960,15 @@ static int spusched_thread(void *unused)
schedule();
for (node = 0; node < MAX_NUMNODES; node++) {
mutex_lock(&cbe_spu_info[node].list_mutex);
- list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+ list_for_each_safe(cur, tmp, &cbe_spu_info[node].spus) {
+ spu = list_entry(cur, struct spu, cbe_list);
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+
if (spu->ctx)
spusched_tick(spu->ctx);
+
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ }
mutex_unlock(&cbe_spu_info[node].list_mutex);
}
}
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/run.c
@@ -37,7 +37,7 @@ void spufs_stop_callback(struct spu *spu
spu->dar = 0;
}
-static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+int spu_stopped(struct spu_context *ctx, u32 * stat)
{
u64 dsisr;
u32 stopped;
Index: linux-2.6.22/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.22.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6.22/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -261,6 +261,7 @@ int spu_acquire_runnable(struct spu_cont
void spu_acquire_saved(struct spu_context *ctx);
void spu_release_saved(struct spu_context *ctx);
+int spu_stopped(struct spu_context *ctx, u32 * stat);
void spu_del_from_rq(struct spu_context *ctx);
int spu_activate(struct spu_context *ctx, unsigned long flags);
void spu_deactivate(struct spu_context *ctx);
More information about the cbe-oss-dev
mailing list