[POWERPC] spufs: use cancel_rearming_delayed_workqueue when stopping spu contexts
authorChristoph Hellwig <hch@lst.de>
Mon, 23 Apr 2007 19:08:06 +0000 (21:08 +0200)
committerArnd Bergmann <arnd@klappe.arndb.de>
Mon, 23 Apr 2007 19:18:52 +0000 (21:18 +0200)
The scheduler workqueue may rearm itself and deadlock when we try to stop
it.  Put a flag in place to avoid skip the work if we're tearing down
the context.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spufs.h

index c9561582ce2a30da4ec2674414c273b7b79e32a4..003e330fc76fd90b1826860cf47155a72113d93e 100644 (file)
@@ -71,14 +71,25 @@ static inline int node_allowed(int node)
 
 void spu_start_tick(struct spu_context *ctx)
 {
-       if (ctx->policy == SCHED_RR)
+       if (ctx->policy == SCHED_RR) {
+               /*
+                * Make sure the exiting bit is cleared.
+                */
+               clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
                queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE);
+       }
 }
 
 void spu_stop_tick(struct spu_context *ctx)
 {
-       if (ctx->policy == SCHED_RR)
+       if (ctx->policy == SCHED_RR) {
+               /*
+                * While the work can be rearming normally setting this flag
+                * makes sure it does not rearm itself anymore.
+                */
+               set_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
                cancel_delayed_work(&ctx->sched_work);
+       }
 }
 
 void spu_sched_tick(struct work_struct *work)
@@ -88,6 +99,14 @@ void spu_sched_tick(struct work_struct *work)
        struct spu *spu;
        int rearm = 1;
 
+       /*
+        * If this context is being stopped avoid rescheduling from the
+        * scheduler tick because we would block on the state_mutex.
+        * The caller will yield the spu later on anyway.
+        */
+       if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags))
+               return;
+
        mutex_lock(&ctx->state_mutex);
        spu = ctx->spu;
        if (spu) {
@@ -377,7 +396,7 @@ static struct spu *find_victim(struct spu_context *ctx)
  * @ctx:       spu context to schedule
  * @flags:     flags (currently ignored)
  *
- * Tries to find a free spu to run @ctx.  If no free spu is availble
+ * Tries to find a free spu to run @ctx.  If no free spu is available
  * add the context to the runqueue so it gets woken up once an spu
  * is available.
  */
index 5c4e47d69d79478a37d7ff62563b5dea8d6fd7b8..f418378abdff5173292919c246d64e23166f1932 100644 (file)
@@ -41,7 +41,7 @@ struct spu_gang;
 
 /* ctx->sched_flags */
 enum {
-       SPU_SCHED_WAKE = 0, /* currently unused */
+       SPU_SCHED_EXITING = 0,
 };
 
 struct spu_context {