[Cbe-oss-dev] PATCH [7/7] fix time slicing [updated]

Luke Browning lukebr at linux.vnet.ibm.com
Fri Nov 2 01:52:45 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,39 +864,45 @@ 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;
+	if (status & (SPU_STATUS_STOPPED_BY_STOP |
+		      SPU_STATUS_STOPPED_BY_HALT |
+		      SPU_STATUS_SINGLE_STEP))
+		goto out;
 
-	/*
-	 * 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;
+	if (--ctx->time_slice)
+		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);
 }
 
-/**
+/*
  * count_active_contexts - count nr of active tasks
  *
  * Return the number of tasks currently running or waiting to run.
@@ -945,6 +956,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 +965,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
@@ -39,7 +39,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