diff options
author | Christoph Hellwig <hch@lst.de> | 2007-04-23 15:08:11 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@klappe.arndb.de> | 2007-04-23 15:18:54 -0400 |
commit | a475c2f43520cb095452201da57395000cfeb94c (patch) | |
tree | 0cfe49111b15cf20b03d308ec8b5a8b5210b0363 /arch | |
parent | 390c53430498c9973e015432806edd53b2efe6c6 (diff) |
[POWERPC] spufs: remove woken threads from the runqueue early
A single context should only be woken once, and we should not have
more wakeups for a given priority than the number of contexts on
that runqueue position.
Also add some asserts to trap future problems in this area more
easily.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 44 |
2 files changed, 19 insertions, 27 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index b3954aba424e..065147fb1cc2 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
@@ -52,6 +52,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
52 | ctx->state = SPU_STATE_SAVED; | 52 | ctx->state = SPU_STATE_SAVED; |
53 | ctx->ops = &spu_backing_ops; | 53 | ctx->ops = &spu_backing_ops; |
54 | ctx->owner = get_task_mm(current); | 54 | ctx->owner = get_task_mm(current); |
55 | INIT_LIST_HEAD(&ctx->rq); | ||
55 | if (gang) | 56 | if (gang) |
56 | spu_gang_add_ctx(gang, ctx); | 57 | spu_gang_add_ctx(gang, ctx); |
57 | ctx->rt_priority = current->rt_priority; | 58 | ctx->rt_priority = current->rt_priority; |
@@ -76,6 +77,7 @@ void destroy_spu_context(struct kref *kref) | |||
76 | spu_fini_csa(&ctx->csa); | 77 | spu_fini_csa(&ctx->csa); |
77 | if (ctx->gang) | 78 | if (ctx->gang) |
78 | spu_gang_remove_ctx(ctx->gang, ctx); | 79 | spu_gang_remove_ctx(ctx->gang, ctx); |
80 | BUG_ON(!list_empty(&ctx->rq)); | ||
79 | kfree(ctx); | 81 | kfree(ctx); |
80 | } | 82 | } |
81 | 83 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 1582d7645237..876828cc95a2 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -245,6 +245,14 @@ static void spu_add_to_rq(struct spu_context *ctx) | |||
245 | spin_unlock(&spu_prio->runq_lock); | 245 | spin_unlock(&spu_prio->runq_lock); |
246 | } | 246 | } |
247 | 247 | ||
248 | static void __spu_del_from_rq(struct spu_context *ctx, int prio) | ||
249 | { | ||
250 | if (!list_empty(&ctx->rq)) | ||
251 | list_del_init(&ctx->rq); | ||
252 | if (list_empty(&spu_prio->runq[prio])) | ||
253 | clear_bit(ctx->prio, spu_prio->bitmap); | ||
254 | } | ||
255 | |||
248 | /** | 256 | /** |
249 | * spu_del_from_rq - remove a context from the runqueue | 257 | * spu_del_from_rq - remove a context from the runqueue |
250 | * @ctx: context to remove | 258 | * @ctx: context to remove |
@@ -252,33 +260,10 @@ static void spu_add_to_rq(struct spu_context *ctx) | |||
252 | static void spu_del_from_rq(struct spu_context *ctx) | 260 | static void spu_del_from_rq(struct spu_context *ctx) |
253 | { | 261 | { |
254 | spin_lock(&spu_prio->runq_lock); | 262 | spin_lock(&spu_prio->runq_lock); |
255 | list_del_init(&ctx->rq); | 263 | __spu_del_from_rq(ctx, ctx->prio); |
256 | if (list_empty(&spu_prio->runq[ctx->prio])) | ||
257 | clear_bit(ctx->prio, spu_prio->bitmap); | ||
258 | spin_unlock(&spu_prio->runq_lock); | 264 | spin_unlock(&spu_prio->runq_lock); |
259 | } | 265 | } |
260 | 266 | ||
261 | /** | ||
262 | * spu_grab_context - remove one context from the runqueue | ||
263 | * @prio: priority of the context to be removed | ||
264 | * | ||
265 | * This function removes one context from the runqueue for priority @prio. | ||
266 | * If there is more than one context with the given priority the first | ||
267 | * task on the runqueue will be taken. | ||
268 | * | ||
269 | * Returns the spu_context it just removed. | ||
270 | * | ||
271 | * Must be called with spu_prio->runq_lock held. | ||
272 | */ | ||
273 | static struct spu_context *spu_grab_context(int prio) | ||
274 | { | ||
275 | struct list_head *rq = &spu_prio->runq[prio]; | ||
276 | |||
277 | if (list_empty(rq)) | ||
278 | return NULL; | ||
279 | return list_entry(rq->next, struct spu_context, rq); | ||
280 | } | ||
281 | |||
282 | static void spu_prio_wait(struct spu_context *ctx) | 267 | static void spu_prio_wait(struct spu_context *ctx) |
283 | { | 268 | { |
284 | DEFINE_WAIT(wait); | 269 | DEFINE_WAIT(wait); |
@@ -309,9 +294,14 @@ static void spu_reschedule(struct spu *spu) | |||
309 | spin_lock(&spu_prio->runq_lock); | 294 | spin_lock(&spu_prio->runq_lock); |
310 | best = sched_find_first_bit(spu_prio->bitmap); | 295 | best = sched_find_first_bit(spu_prio->bitmap); |
311 | if (best < MAX_PRIO) { | 296 | if (best < MAX_PRIO) { |
312 | struct spu_context *ctx = spu_grab_context(best); | 297 | struct list_head *rq = &spu_prio->runq[best]; |
313 | if (ctx) | 298 | struct spu_context *ctx; |
314 | wake_up(&ctx->stop_wq); | 299 | |
300 | BUG_ON(list_empty(rq)); | ||
301 | |||
302 | ctx = list_entry(rq->next, struct spu_context, rq); | ||
303 | __spu_del_from_rq(ctx, best); | ||
304 | wake_up(&ctx->stop_wq); | ||
315 | } | 305 | } |
316 | spin_unlock(&spu_prio->runq_lock); | 306 | spin_unlock(&spu_prio->runq_lock); |
317 | } | 307 | } |