Mercurial > hg > Members > kono > Cerium
view TaskManager/Cell/spe/SchedTask.cc @ 230:2b114977852d
fix Random
author | gongo@localhost.localdomain |
---|---|
date | Fri, 13 Feb 2009 10:53:58 +0900 |
parents | 29e338dbc280 |
children | d734af296d38 |
line wrap: on
line source
#include <stdlib.h> #include <string.h> #include "SchedTask.h" #include "SchedTaskList.h" #include "SchedNop2Ready.h" #include "DmaManager.h" #include "error.h" #include "TaskManager.h" extern Scheduler::TaskObject task_list[MAX_TASK_OBJECT]; SchedTask* createSchedTask(TaskPtr task) { return task_list[task->command](); } SchedTask::SchedTask(void) { __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) { //printf("%p\n", this); 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); __scheduler->dma_wait(DMA_READ_IN_LIST); __scheduler->dma_wait(DMA_READ_OUT_LIST); __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__); // wait for load inListData __scheduler->dma_wait(DMA_READ_IN_LIST); // 読むデータが一つもなければ無視 if (__inListData->length < 1 || __inListData->size == 0) return; // load Input Data __readbuf = __scheduler->allocate(__inListData->size); __scheduler->dma_loadList(__inListData, __readbuf, DMA_READ); __scheduler->dma_wait(DMA_READ); (this->*ex_read)(); } void SchedTask::exec(void) { __debug("[SchedTask:%s]\n", __FUNCTION__); // wait for load outListData __scheduler->dma_wait(DMA_READ_OUT_LIST); __writebuf = __scheduler->allocate(__outListData->size); __debug(" task->command = %d\n", __task->command); __debug(" task->in_size = %d\n", __task->in_size); __debug(" task->in_addr = 0x%x\n", __task->in_addr); __debug(" task->out_addr = 0x%x\n", __task->out_addr); __debug(" list->next = 0x%x\n", (unsigned int)__list->next); __debug(" list->length = 0x%x\n", (unsigned int)__list->length); __scheduler->dma_wait(DMA_READ); //run(__readbuf, __writebuf); (this->*run_func)(__readbuf, __writebuf); free(__readbuf); if (__taskGroup->status() != 0) { __task->self = __taskGroup->command; delete __taskGroup; __taskGroup = NULL; } // 書き込む領域がなければ無視 if (__outListData->size > 0 || __outListData->length > 0) { __scheduler->dma_storeList(__outListData, __writebuf, DMA_WRITE); __scheduler->dma_wait(DMA_WRITE); } (this->*ex_exec)(); } void SchedTask::write(void) { __debug("[SchedTask:%s]\n", __FUNCTION__); __scheduler->dma_wait(DMA_WRITE); free(__writebuf); 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); }