[Cbe-oss-dev] [PATCH 2/2] MARS: kernel scheduler fix overwrite queue block
Yuji Mano
Yuji.Mano at am.sony.com
Fri Aug 15 07:26:28 EST 2008
This fixes a bug inside the kernel scheduler that would cause the currently
checked workload queue block to be overwritten by a different workload queue
block if a workload waits for completion of a workload in another workload
queue block.
This also optimizes the checking for workload completion by only fetching the
workload queue block when the workload we are waiting for is in a workload
queue block that is different from the one currently being processed.
Signed-off-by: Yuji Mano <yuji.mano at am.sony.com>
---
src/mpu/kernel/mars_kernel_scheduler.c | 77 +++++++++++++++++++--------------
1 file changed, 46 insertions(+), 31 deletions(-)
--- a/src/mpu/kernel/mars_kernel_scheduler.c
+++ b/src/mpu/kernel/mars_kernel_scheduler.c
@@ -51,7 +51,17 @@ uint64_t workload_ea;
int reserve_workload(void);
void release_workload(void);
-static int search_block(struct mars_workload_queue_block *block)
+static inline void get_block(int block, struct mars_workload_queue_block *dst)
+{
+ mars_dma_get_and_wait(dst,
+ queue_header.queue_ea +
+ offsetof(struct mars_workload_queue, block) +
+ sizeof(struct mars_workload_queue_block) * block,
+ sizeof(struct mars_workload_queue_block),
+ MARS_DMA_TAG);
+}
+
+static int search_block(int block)
{
int i;
int index = -1;
@@ -63,50 +73,55 @@ static int search_block(struct mars_work
* and pick the workload that has been waiting the longest
*/
for (i = 0; i < MARS_WORKLOAD_PER_BLOCK; i++) {
- switch (block->state[i]) {
+ struct mars_workload_queue_block *p = &queue_block;
+
+ switch (p->state[i]) {
case MARS_WORKLOAD_STATE_READY:
/* priority greater than max priority so select */
- if ((int)block->priority[i] > max_priority) {
+ if ((int)p->priority[i] > max_priority) {
index = i;
- max_count = block->counter[i];
- max_priority = block->priority[i];
+ max_count = p->counter[i];
+ max_priority = p->priority[i];
/* priority equal and wait counter greater so select */
- } else if ((int)block->priority[i] == max_priority &&
- (int)block->counter[i] > max_count) {
+ } else if ((int)p->priority[i] == max_priority &&
+ (int)p->counter[i] > max_count) {
index = i;
- max_count = block->counter[i];
+ max_count = p->counter[i];
}
/* increment wait counter without overflowing */
- if (block->counter[i] < MARS_WORKLOAD_COUNTER_MAX)
- block->counter[i]++;
+ if (p->counter[i] < MARS_WORKLOAD_COUNTER_MAX)
+ p->counter[i]++;
break;
case MARS_WORKLOAD_STATE_WAITING:
/* waiting for workload to finish so check status */
- if (block->wait[i] != MARS_WORKLOAD_ID_NONE) {
- int bl = block->wait[i]/MARS_WORKLOAD_PER_BLOCK;
- int id = block->wait[i]%MARS_WORKLOAD_PER_BLOCK;
-
- /* fetch the necessary workload block */
- mars_dma_get_and_wait(&queue_block,
- queue_header.queue_ea +
- offsetof(struct mars_workload_queue, block) +
- sizeof(struct mars_workload_queue_block) * bl,
- sizeof(struct mars_workload_queue_block),
- MARS_DMA_TAG);
+ if (p->wait[i] != MARS_WORKLOAD_ID_NONE) {
+ struct mars_workload_queue_block wait_block;
+ struct mars_workload_queue_block *p_wait_block;
+
+ int bl = p->wait[i] / MARS_WORKLOAD_PER_BLOCK;
+ int id = p->wait[i] % MARS_WORKLOAD_PER_BLOCK;
+
+ /* check if workload id is in the same block */
+ if (block != bl) {
+ /* fetch the necessary block */
+ get_block(bl, &wait_block);
+ /* set pointer to check fetched block */
+ p_wait_block = &wait_block;
+ } else {
+ /* set pointer to check current block */
+ p_wait_block = p;
+ }
/* check if workload is finished and reset */
- if (queue_block.state[id] ==
+ if (p_wait_block->state[id] ==
MARS_WORKLOAD_STATE_FINISHED) {
- block->wait[i] =
- MARS_WORKLOAD_ID_NONE;
- block->state[i] =
- MARS_WORKLOAD_STATE_READY;
+ p->wait[i] = MARS_WORKLOAD_ID_NONE;
+ p->state[i] = MARS_WORKLOAD_STATE_READY;
}
/* waiting for signal so check signal bit and reset */
- } else if (block->signal[i] ==
- MARS_WORKLOAD_SIGNAL_ON) {
- block->signal[i] = MARS_WORKLOAD_SIGNAL_OFF;
- block->state[i] = MARS_WORKLOAD_STATE_READY;
+ } else if (p->signal[i] == MARS_WORKLOAD_SIGNAL_ON) {
+ p->signal[i] = MARS_WORKLOAD_SIGNAL_OFF;
+ p->state[i] = MARS_WORKLOAD_STATE_READY;
i--;
}
break;
@@ -135,7 +150,7 @@ static int reserve_block(int block)
sizeof(struct mars_workload_queue_block) * block);
/* set the workload index */
- index = search_block(&queue_block);
+ index = search_block(block);
if (index >= 0) {
/* update the current state of the workload */
queue_block.state[index] = MARS_WORKLOAD_STATE_RUNNING;
More information about the cbe-oss-dev
mailing list