Mercurial > hg > Game > Cerium
diff TaskManager/kernel/schedule/SchedTask.cc @ 308:b85b920628e2 draft
remove SchedTaskImpl
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 08 Jun 2009 19:36:48 +0900 |
parents | 40db021f6272 |
children | 364abe879376 |
line wrap: on
line diff
--- a/TaskManager/kernel/schedule/SchedTask.cc Mon Jun 08 19:32:38 2009 +0900 +++ b/TaskManager/kernel/schedule/SchedTask.cc Mon Jun 08 19:36:48 2009 +0900 @@ -1,8 +1,559 @@ +#include <stdlib.h> +#include <string.h> #include "SchedTask.h" +#include "SchedTask.h" +#include "SchedTaskList.h" +#include "SchedNop2Ready.h" +#include "DmaManager.h" +#include "error.h" +#include "TaskManager.h" -SchedTask* +extern Scheduler::TaskObject task_list[MAX_TASK_OBJECT]; + +//#define NO_PIPELINE + +SchedTask * createSchedTask(TaskPtr task) { - return createSchedTaskImpl(task); + return task_list[task->command](); +} + + +SchedTask::SchedTask() +{ + __list = NULL; + __task = NULL; + __inListData = NULL; + __outListData = NULL; + __readbuf = NULL; + __writebuf = NULL; + __scheduler = NULL; + __taskGroup = NULL; + __renew_flag = 0; + __cur_index = 0; + __flag_renewTask = SCHED_TASK_NORMAL; + + ex_init = &SchedTask::ex_init_normal; + ex_read = &SchedTask::ex_read_normal; + ex_exec = &SchedTask::ex_exec_normal; + ex_write = &SchedTask::ex_write_normal; + ex_next = &SchedTask::ex_next_normal; + + run_func = &SchedTask::run; +} + +/** + * dma_store の wait を行う + * このタスクが RenewTask だった場合、 + * __inListData や __outListData は + * Scheduler の持つ、使い回しの buffer ではなく + * 新たに allocate されたものなので、ここで free する + */ +SchedTask::~SchedTask(void) +{ + if (__flag_renewTask == SCHED_TASK_RENEW) { + free(__inListData); + free(__outListData); + + /** + * __list != NULL の場合、 + * この Task が __list の最後の Task になるので (SchedTask::next 参照) + * このタイミングで __list を解放する + * (free に渡されるアドレスが正しいものとなる)。 + * それ以外の Task では当然解放しない。 + * __list == NULL なので、free に渡しても無問題 + */ + free(__list); + } + + delete smanager; +} + +/** + * このタスクを Renew Task とし、それに応じた関数をセットする + */ +void +SchedTask::__setRenew(void) +{ + __flag_renewTask = SCHED_TASK_RENEW; + + ex_init = &SchedTask::ex_init_renew; + ex_read = &SchedTask::ex_read_renew; + ex_exec = &SchedTask::ex_exec_renew; + ex_write = &SchedTask::ex_write_renew; + ex_next = &SchedTask::ex_next_renew; +} + +void +SchedTask::__init__(TaskListPtr _list, TaskPtr _task, int index, + ListDataPtr rbuf, ListDataPtr wbuf, Scheduler* sc) +{ + __list = _list; + __task = _task; + __inListData = rbuf; + __outListData = wbuf; + __scheduler = sc; + __cur_index = index; + + smanager = new STaskManager(this); + + __scheduler->mainMem_wait(); + + (this->*ex_init)(); +} + +/** + * PPE 内で生成されたタスクの ex_init() + */ +void +SchedTask::ex_init_normal(void) +{ + __scheduler->dma_load(__inListData, (uint32)__task->inData, + sizeof(ListData), DMA_READ_IN_LIST); + __scheduler->dma_load(__outListData, (uint32)__task->outData, + sizeof(ListData), DMA_READ_OUT_LIST); +#if defined(NO_PIPELINE) + __scheduler->dma_wait(DMA_READ_IN_LIST); + __scheduler->dma_wait(DMA_READ_OUT_LIST); +#endif + + __taskGroup = new TaskGroup; + __taskGroup->command = __task->self; +} + +/** + * SPE 内で生成されたタスクの ex_init() + * 各データは SPE 内の create_task 時に生成もしくは引き継がれているので + * ex_init_normal() と違い、ここでは値を渡すだけ + */ +void +SchedTask::ex_init_renew(void) +{ + __inListData = __task->inData; + __outListData = __task->outData; + __taskGroup = (TaskGroupPtr)__task->self; +} + +/** + * [Todo] + * データの読み込み場所を readbuf ではなく、 + * ユーザ自身で決めれるようになるといいかもしれない。 + * + * # TaskManager が勝手に消すことなく、 + * # ユーザが SPE 上に持ち続けることができるため。 + * # もちろん管理はユーザに任せるわけだ。 + */ +void +SchedTask::read(void) +{ + __debug("[SchedTask:%s]\n", __FUNCTION__); + +#if !defined(NO_PIPELINE) + __scheduler->dma_wait(DMA_READ_IN_LIST); + __scheduler->dma_wait(DMA_READ_OUT_LIST); +#endif + + __writebuf = __scheduler->allocate(__outListData->size); + + // 読むデータが一つもなければ無視 + if (__inListData->length == 0) return; + + // load Input Data + __readbuf = __scheduler->allocate(__inListData->size); + __scheduler->dma_loadList(__inListData, __readbuf, DMA_READ); + +#if defined(NO_PIPELINE) + __scheduler->dma_wait(DMA_READ); +#endif + + (this->*ex_read)(); +} + +void +SchedTask::exec(void) +{ + __debug("[SchedTask:%s]\n", __FUNCTION__); + +#if !defined(NO_PIPELINE) + __scheduler->dma_wait(DMA_READ); +#endif + + //run(__readbuf, __writebuf); + (this->*run_func)(__readbuf, __writebuf); + + free(__readbuf); + + if (__taskGroup->status() != 0) { + __task->self = __taskGroup->command; + delete __taskGroup; + __taskGroup = NULL; + } + + + // 書き込む領域がなければ無視 + if (__outListData->length > 0) { + __scheduler->dma_storeList(__outListData, __writebuf, DMA_WRITE); + +#if defined(NO_PIPELINE) + __scheduler->dma_wait(DMA_WRITE); + free(__writebuf); +#endif + } + + (this->*ex_exec)(); +} + +void +SchedTask::write(void) +{ + __debug("[SchedTask:%s]\n", __FUNCTION__); + +#if !defined(NO_PIPELINE) + __scheduler->dma_wait(DMA_WRITE); + free(__writebuf); +#endif + + if (__task->self == MY_SPE_NOP) return; + + (this->*ex_write)(); +} + +/** + * PPE 内で生成されたタスクの ex_read() + */ +void +SchedTask::ex_read_normal(void) +{ +} + +/** + * SPE 内で生成されたタスクの ex_read() + */ +void +SchedTask::ex_read_renew(void) +{ +} + +/** + * PPE 内で生成されたタスクの ex_exec() + */ +void +SchedTask::ex_exec_normal(void) +{ +} + +/** + * SPE 内で生成されたタスクの ex_exec() + */ +void +SchedTask::ex_exec_renew(void) +{ +} + + + +/** + * PPE 内で生成されたタスクの ex_write() + * + * このタスク内で新たにタスクが生成され、 + * 且つそのタスクの終了を待つ必要がある場合、 + * PPE に終了したことは知らせない(command は送信しない) + */ +void +SchedTask::ex_write_normal(void) +{ + /** + * このタスク内で新たにタスクが生成されなかった + * or 生成されたが、そのタスクの終了を待つ必要は無い + */ + if (__renew_flag == 0) { + __scheduler->mail_write(__task->self); + } } +/** + * SPE 内で生成されたタスクの ex_write() + * + * A <- 親タスク + * | \ + * B C <- SPE 内で生成されたタスク + * + * A は SPE 内で B, C を生成したとする。 + * B と C が終了したら、A が PPE に送るはずだったコマンドが + * 子タスクに引き継がれているので、最後に実行された子タスクが + * PPE に mail 送信する。 + */ +void +SchedTask::ex_write_renew(void) +{ + uint32 cmd; + + __taskGroup->remove(__task); + cmd = __taskGroup->status(); + + // タスク内で作られた全てのタスクが終了した + if (cmd != 0) { + delete __taskGroup; + __scheduler->mail_write(cmd); + } +} + +SchedTaskBase* +SchedTask::next(Scheduler *m, SchedTaskBase *p) +{ + __debug("[SchedTask:%s]\n", __FUNCTION__); + + delete p; + + return (this->*ex_next)(); +} + +SchedTaskBase* +SchedTask::ex_next_normal(void) +{ + if (__cur_index < __list->length) { + SchedTaskBase *nextSched; + + nextSched = __scheduler->get_nextRenewTaskList(); + + // RenewTask がある + if (nextSched) { + __scheduler->set_backupTaskList(__list); + __scheduler->set_backupTaskListIndex(__cur_index); + return nextSched; + } else { + TaskPtr nextTask = &__list->tasks[__cur_index++]; + nextSched = createSchedTask(nextTask); + ((SchedTask*)nextSched)->__init__(__list, nextTask, __cur_index, + __scheduler->get_curReadBuf(), + __scheduler->get_curWriteBuf(), + __scheduler); + return nextSched; + } + } else { + uint32 nextList = (uint32)__list->next; + + if (nextList == 0) { + return new SchedNop2Ready(__scheduler); + } else { + return createSchedTaskList(nextList, __scheduler, + SCHED_TASKLIST_NORMAL); + } + } +} + +/** + * + */ +SchedTaskBase* +SchedTask::ex_next_renew(void) +{ + TaskPtr nextTask; + SchedTask *nextSched; + + if (__cur_index < __list->length) { + nextTask = &__list->tasks[__cur_index++]; + nextSched = createSchedTask(nextTask); + + // RenewTaskList を実行中なので + nextSched->__setRenew(); + nextSched->__init__(__list, nextTask, __cur_index, + __scheduler->get_curReadBuf(), + __scheduler->get_curWriteBuf(), + __scheduler); + + /** + * この理由は SchedTask:~SchedTask() で + */ + __list = NULL; + return nextSched; + } else { + SchedTaskBase *nextList; + + nextList = __scheduler->get_nextRenewTaskList(); + + if (nextList) { + return nextList; + } else { + TaskListPtr nextList = __scheduler->get_backupTaskList(); + + // 中断した TaskList がある + if (nextList) { + __cur_index = __scheduler->get_backupTaskListIndex(); + + nextTask = &nextList->tasks[__cur_index++]; + nextSched = createSchedTask(nextTask); + + nextSched->__init__(nextList, nextTask, __cur_index, + __scheduler->get_curReadBuf(), + __scheduler->get_curWriteBuf(), + __scheduler); + return nextSched; + } else { + return new SchedNop2Ready(__scheduler); + } + } + } +} + +int +SchedTask::get_cpuid(void) +{ + return __scheduler->id; +} + +/** + * task->add_inData で与えられた順番に対応する index (0〜n-1) で、 + * buffer から対応するデータを返す。 + */ +void* +SchedTask::get_input(void *buff, int index) +{ + if (buff != NULL) { + return (void*)((int)buff + __inListData->bound[index]); + } else { + return NULL; + } +} + +/** + * get_input(index) のアドレスを返す + */ +uint32 +SchedTask::get_inputAddr(int index) +{ + return __inListData->element[index].addr; +} + +/** + * get_input(index) のサイズを返す + */ +int +SchedTask::get_inputSize(int index) +{ + return __inListData->element[index].size; +} + +/** + * write buffer の領域を返す。 + */ +void* +SchedTask::get_output(void *buff, int index) +{ + if (buff != NULL) { + return (void*)((int)buff + __outListData->bound[index]); + } else { + return NULL; + } +} + +/** + * get_output(index) のアドレスを返す + */ +uint32 +SchedTask::get_outputAddr(int index) +{ + return __outListData->element[index].addr; +} + +/** + * get_output(index) のサイズを返す + */ +int +SchedTask::get_outputSize(int index) +{ + return __outListData->element[index].size; +} + +int +SchedTask::get_param(int index) +{ + return __task->param[index]; +} + +TaskPtr +SchedTask::create_task(int cmd) +{ + TaskListPtr taskList = __scheduler->get_renewListBuf(); + TaskPtr p = &taskList->tasks[taskList->length++]; + p->command = cmd; + + p->inData = (ListData*)__scheduler->allocate(sizeof(ListData)); + p->outData = (ListData*)__scheduler->allocate(sizeof(ListData)); + + p->inData->clear(); + p->outData->clear(); + + p->self = MY_SPE_NOP; + p->param_size = 0; + + return p; +} + +/** + * 生成したタスクが終了してから、メインスケジューラ(PPE) に + * タスクが終了した旨を知らせる。 + * + * @param[in] waitTask タスク内で生成したタスク + */ +void +SchedTask::wait_task(TaskPtr waitTask) +{ + waitTask->self = (uint32)__taskGroup; + + __scheduler->add_groupTask(__taskGroup, waitTask); + + __renew_flag++; +} + +void* +SchedTask::global_alloc(int id, int size) { + return __scheduler->global_alloc(id, size); +} + +void* +SchedTask::global_get(int id) { + return __scheduler->global_get(id); +} + +void +SchedTask::global_free(int id) { + __scheduler->global_free(id); +} + +void +SchedTask::mainMem_alloc(int id, int size) { + __scheduler->mainMem_alloc(id, size); +} + +void +SchedTask::mainMem_wait(void) { + __scheduler->mainMem_wait(); +} + +void* +SchedTask::mainMem_get(int id) { + return __scheduler->mainMem_get(id); +} + +void* +SchedTask::allocate(int size) { + return __scheduler->allocate(size); +} + +void +SchedTask::dma_load(void *buf, uint32 addr, uint32 size, uint32 mask) { + __scheduler->dma_load(buf, addr, size, mask); +} + +void +SchedTask::dma_store(void *buf,uint32 addr, uint32 size, uint32 mask) { + __scheduler->dma_store(buf, addr, size, mask); +} + +void +SchedTask::dma_wait(uint32 mask) { + __scheduler->dma_wait(mask); +} + +/* end */