From: Masato Noguchi Date: Mon, 20 Nov 2006 17:45:04 +0000 (+0100) Subject: [POWERPC] spufs: Fix missing stop-and-signal X-Git-Tag: v2.6.20-rc1~34^2~40^2~8^2~86 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2ebb2477f9a61b436dd22b75189857df1a77e585;p=linux-2.6 [POWERPC] spufs: Fix missing stop-and-signal When there is pending signals, current spufs_run_spu() always returns -ERESTARTSYS and it is called again automatically. But, if spe already stopped by stop-and-signal or halt instruction, returning -ERESTARTSYS makes stop-and-signal/halt lost and spu run over the end-point. For your convenience, I attached a sample code to restage this bug. If there is no bug, printed NPC will be 0x4000. Signed-off-by: Masato Noguchi Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 88a41d83a7..c88fd7f9ea 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -79,13 +79,7 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, if (signal_pending(current)) ret = -ERESTARTSYS; - if (unlikely(current->ptrace & PT_PTRACED)) { - if ((*status & SPU_STATUS_STOPPED_BY_STOP) - && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { - force_sig(SIGTRAP, current); - ret = -ERESTARTSYS; - } - } + return ret; } @@ -232,7 +226,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { ret = spu_reacquire_runnable(ctx, npc, &status); if (ret) - goto out; + goto out2; continue; } ret = spu_process_events(ctx); @@ -242,10 +236,24 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, ctx->ops->runcntl_stop(ctx); ret = spu_run_fini(ctx, npc, &status); - if (!ret) - ret = status; spu_yield(ctx); +out2: + if ((ret == 0) || + ((ret == -ERESTARTSYS) && + ((status & SPU_STATUS_STOPPED_BY_HALT) || + ((status & SPU_STATUS_STOPPED_BY_STOP) && + (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) + ret = status; + + if (unlikely(current->ptrace & PT_PTRACED)) { + if ((status & SPU_STATUS_STOPPED_BY_STOP) + && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { + force_sig(SIGTRAP, current); + ret = -ERESTARTSYS; + } + } + out: *event = ctx->event_return; up(&ctx->run_sema);