view TaskManager/kernel/schedule/Scheduler.cc @ 386:6113af8f183b

MemHash...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Thu, 06 Aug 2009 19:31:51 +0900
parents eab18aa0c7f6
children 5e2d30bfbf23
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include "Scheduler.h"
#include "SchedNop.h"
#include "error.h"
#include <assert.h>

/*
 * Edit kernel/schedule/xx.cc, Cell/spe/xx.cc will be over writen by this.
 * Do not edit Cell/spe/xx.cc unless there is no kernel/schedule/xx.cc files.
 */

Scheduler::TaskObject task_list[MAX_TASK_OBJECT];

Scheduler::~Scheduler(void)
{
    delete connector;
}

/*! @brief speTaskの入出力のパイプラインバッファを確保する
 */

void
Scheduler::init(void)
{
    init_impl();

    for (int i = 0; i < 2; i++) {
        buff_taskList[i]    = (TaskListPtr)allocate(sizeof(TaskList));
        buff_inListData[i]  = (ListDataPtr)allocate(sizeof(ListData));
        buff_outListData[i] = (ListDataPtr)allocate(sizeof(ListData));
    }

    buffFlag_taskList = 0;
    buffFlag_inListData = 0;
    buffFlag_outListData = 0;
    flag_renewTaskList = 0;

    // bzero でもいいけど
    for (int i = 0; i < MAX_GLOBAL_AREA; i++) {
        globalList[i] = NULL;
    }

    for (int i = 0; i < MAX_MAINMEM_AREA; i++) {
        mainMemList[i] = NULL;
    }


    taskGroup = new TaskGroup;
    renewTop_taskList = NULL;
    renewCur_taskList = NULL;
}

void
Scheduler::run(void)
{
    SchedTaskBase* taskTmp;

    task1 = new SchedNop();
    task2 = new SchedNop();
    task3 = new SchedNop();

    // main loop
    do {
        __debug("----------\n");
        task3->write();
        task2->exec();
        task1->read();

        taskTmp = task3;
        task3 = task2;
        task2 = task1;
        task1 = task1->next(this, taskTmp);
    } while (task1);

    delete task3;
    delete task2;
}


void
Scheduler::finish(void)
{
    free(buff_taskList[0]);
    free(buff_taskList[1]);
    free(buff_inListData[0]);
    free(buff_inListData[1]);
    free(buff_outListData[0]);
    free(buff_outListData[1]);
}

/**
 * あらかじめ memory allocte してある TaskList の領域を
 * パイプラインの各処理が交代して使う。
 */
TaskListPtr
Scheduler::get_curListBuf(void)
{
    buffFlag_taskList ^= 1;

    return buff_taskList[buffFlag_taskList];
}


/**
 * あらかじめ memory allocte してある ListData の領域を
 * パイプラインの各処理が交代して使う。
 */
ListDataPtr
Scheduler::get_curWriteBuf(void)
{
    buffFlag_outListData ^= 1;
    return buff_outListData[buffFlag_outListData];
}


ListDataPtr
Scheduler::get_curReadBuf(void)
{
    buffFlag_inListData ^= 1;
    return buff_inListData[buffFlag_inListData];
}

/**
 * タスク内で生成されたタスクを格納する TaskList を取得する
 * 現在格納に使っている TaskList (renewCur_taskList) が使えるならそれを返す
 * もしそうでないなら、新しく TaskList を allocate してそれを返す
 * コード中で renewCur_taskList が NULL になるのは
 *   - プログラム開始時
 *   - タスク内生成タスクがある TaskList の実行を新しく始める (Nop2Ready 参照)
 * 以上の場合です
 */
TaskListPtr
Scheduler::get_renewListBuf(void)
{
    if (renewCur_taskList && renewCur_taskList->length < TASK_MAX_SIZE) {
        return renewCur_taskList;
    } else {
        TaskListPtr newList = (TaskListPtr)allocate(sizeof(TaskList));
        newList->length = 0;
        newList->next = NULL;
        renewTop_taskList = TaskList::append(renewTop_taskList, newList);
        renewCur_taskList = newList;
        return newList;
    }
}

/**
 * 次に実行する Renew Task List を返す
 *
 * @param[in] curList 現在実行中の TaskList
 *                    中断して RenewTaskList を行うため
 *                    バックアップを取っておく
 * @return next RenewTaskList
 */
SchedTaskList*
Scheduler::get_nextRenewTaskList(void)
{
    if (renewTop_taskList) {
        TaskListPtr list  = renewTop_taskList;
        renewTop_taskList = renewTop_taskList->next;
        renewCur_taskList = NULL;

        list->next = NULL;
        SchedTaskList *sched
            = createSchedTaskList((uint32)list, this, SCHED_TASKLIST_RENEW);
        return sched;
    } else {
        return NULL;
    }
}

void
Scheduler::set_backupTaskList(TaskListPtr cur_taskList)
{
    bak_curTaskList = cur_taskList;
}

void
Scheduler::set_backupTaskListIndex(int cur_index)
{
    bakIndex_taskList = cur_index;
}

/**
 * RenewTaskList 実行前に中断した TaskList を返す
 * NULL の場合、中断した TaskList は無い。
 *
 * @return TaskList
 */
TaskListPtr
Scheduler::get_backupTaskList(void)
{
    TaskListPtr ret = bak_curTaskList;

    bak_curTaskList = NULL;
    return ret;
}

int
Scheduler::get_backupTaskListIndex(void)
{
    int ret = bakIndex_taskList;

    bakIndex_taskList = 0;
    return ret;
}

void
Scheduler::dma_load(void *buf, uint32 addr, uint32 size, uint32 mask)
{
    connector->dma_load(buf, addr, size, mask);
}

void
Scheduler::dma_store(void *buf, uint32 addr, uint32 size, uint32 mask)
{
    connector->dma_store(buf, addr, size, mask);
}

void
Scheduler::dma_wait(uint32 mask)
{
    connector->dma_wait(mask);
}

void
Scheduler::dma_loadList(ListDataPtr list, void *buff, uint32 mask)
{
    connector->dma_loadList(list, buff, mask);
}


void
Scheduler::dma_storeList(ListDataPtr list, void *buff, uint32 mask)
{
    return connector->dma_storeList(list, buff, mask);
}

void
Scheduler::mail_write(uint32 data)
{
    connector->mail_write(data);
}

uint32
Scheduler::mail_read(void)
{
    return connector->mail_read();
}

TaskGroupPtr
Scheduler::set_groupTask(uint32 command)
{
    TaskGroupPtr ret = taskGroup;

    reload_groupTask();

    ret->command = command;
    return ret;
}

void
Scheduler::add_groupTask(TaskGroupPtr group, TaskPtr task)
{
    group->add(task);
}

void
Scheduler::remove_groupTask(TaskGroupPtr group, TaskPtr task)
{
    group->remove(task);
}

void
Scheduler::reload_groupTask(void)
{
    taskGroup = new TaskGroup;
}

uint32
Scheduler::status_groupTask(TaskGroupPtr group)
{
    return group->status();
}

/*
    ここから下は、memory 以下にあるべき
 */

void*
Scheduler::global_alloc(int id, int size)
{
    globalList[id] = allocate(size);
    return globalList[id];
}

void*
Scheduler::global_get(int id)
{
    return globalList[id];
}

void
Scheduler::global_set(int id, void *addr)
{
    globalList[id] = addr;
}

void
Scheduler::global_free(int id)
{
    free(globalList[id]);
    globalList[id] = NULL;
}

/**
 * mainMem_alloc で確保したメインメモリの領域アドレスを返す。
 * これは Fifo, Cell で共通
 */
void*
Scheduler::mainMem_get(int id)
{
    return mainMemList[id];
}


/**
 * 本当は Scheduler クラスに入れるべきなんだろうか。。。
 * なんか手抜きの感がある
 */
void
register_task(int cmd, Scheduler::TaskObject task)
{
    task_list[cmd] = task;
}

/*!

  size 単位のMemory Segment を count 個作る

  @param [size] リストの要素1つのサイズ
  @param [count] 要素数
  @return allocate した領域のポインタ

 */
MemList*
Scheduler::createMemList(int size, int count)
{
    uint32 head_size = round_up16(sizeof(MemorySegment));
    uint32 seg_size = round_up16(head_size+size);
    char* mseg = (char*)allocate(seg_size*count);
    MemList* mlist = new MemList((MemorySegment*)mseg);

    for(int i = 0; i < count; i++) {
        MemorySegment* next = (MemorySegment*)(mseg+seg_size*i);
        char* data = (char*)next+head_size;
        next->data = (void*)data;
        next->size = size;
        mlist->addLast(next);
    }

    return mlist;
}

/*!

    Main Memory のSegmentを取得する

  @param [addr] Main Memory のアドレス
  @param [m]    Mem List
  @return allocate した領域のポインタ

    memory directory にあるべきだが...

 */
MemorySegement * 
Scheduler::get_segment(memaddr addr, MemList *m) 
{
    MemorySegment *s = hash->get(addr);
    if (s) {
	/* 既に load されている */
	return s;
    }
   
    /* LRU なので、もっとも使われてない segment を上書きする */ 
    s = m->getLast();
    m->moveToFirst(s);

    memaddr old_addr = s->address;
    s->tag = getTag();
    smanager->dma_load(s->data, addr,
                       s->size, s->tag);
    /* 前のをhashから削除 */
    hash->remove(old_addr);
    /* 新しいaddress を登録 */
    s->address = addr;
    hash->put(s->address, s);

    return s;
}

uint32
Scheduler::get_tag()
{
    return 0;
}

/*!

    Main Memory のSegmentを書き出す
    Segment は get_segement されていて、
    追い出されていてはいけない。
       それを保証するのは難しい?

  @param [addr] Main Memory のアドレス
  @param [m]    Mem List
  @return allocate した領域のポインタ

 */
void
Scheduler::put_segment(MemorySegment *s)
{
    smanager->dma_store(s->data, s->addr,
                       s->size, s->tag);
}

/*!

    Main Memory のSegmentを読込、書き出しを待つ

  @param [id]    MemorySegment のid

 */
void
Scheduelr::wait_segment(MemorySegment *s)
{
    smanager->dma_wait(s->tag);
}

/* end */