Mercurial > hg > Members > kono > Cerium
view TaskManager/kernel/schedule/SchedTask.cc @ 603:42c94f85c779
long -> memaddr (64 or 32)
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Sat, 07 Nov 2009 14:13:29 +0900 (2009-11-07) |
parents | 1733f3cbfa28 |
children | 0decff4e867b |
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" #include <stdarg.h> extern Scheduler::TaskObject task_list[MAX_TASK_OBJECT]; //#define NO_PIPELINE /** Task Object を作る */ SchedTask * createSchedTask(Scheduler *scheduler, TaskPtr task) { return new SchedTask(); } /** code load を始める。既に get_segment hash に入っていれば何もしない。 最初の一回は SchedTaskList:: next から呼ばれる。 この段階では、SchedTask object は、まだ作られてない。 */ void loadSchedTask(Scheduler *scheduler,TaskPtr task) { // fprintf(stderr,"loadSchedTask %d\n",task->command); task_list[task->command].load(scheduler,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; this->stdout_ = stdout; this->stderr_ = stderr; this->stdin_ = stdin; 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; } /** * dma_store の wait を行う */ SchedTask::~SchedTask() { if (flag_renewTask == SCHED_TASK_RENEW) { /** * list != NULL の場合、 * この Task が list の最後の Task になるので (SchedTask::next 参照) * このタイミングで list を解放する * (free に渡されるアドレスが正しいものとなる)。 * それ以外の Task では当然解放しない。 * list == NULL なので、free に渡しても無問題 */ free(list); } } /** * このタスクを Renew Task とし、それに応じた関数をセットする */ void SchedTask::setRenew() { 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 = &_task->inData; outListData = &_task->outData; scheduler = sc; cur_index = index; scheduler->mainMem_wait(); (this->*ex_init)(); } /** * PPE 内で生成されたタスクの ex_init() */ void SchedTask::ex_init_normal() { #if 0 // task list に入れたので既に読んでいる? // 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 #endif taskGroup = new TaskGroup; taskGroup->command = (int)task->self; } /** * SPE 内で生成されたタスクの ex_init() * 各データは SPE 内の create_task 時に生成もしくは引き継がれているので * ex_init_normal() と違い、ここでは値を渡すだけ */ void SchedTask::ex_init_renew() { inListData = &task->inData; outListData = &task->outData; taskGroup = (TaskGroupPtr)task->self; } void SchedTask::read() { __debug("[SchedTask:%s]\n", __FUNCTION__); #if 0 #if !defined(NO_PIPELINE) scheduler->dma_wait(DMA_READ_IN_LIST); scheduler->dma_wait(DMA_READ_OUT_LIST); #endif #endif // object creation をSchedTask生成時にやらないので、 // exec の直前のread で十分に間に合う if (cur_index < list->length) { // load next task loadSchedTask(scheduler, &list->tasks[cur_index]); } 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)(); } /** * PPE 内で生成されたタスクの ex_read() * * [Todo] * データの読み込み場所を readbuf ではなく、 * ユーザ自身で決めれるようになるといいかもしれない。 * * # TaskManager が勝手に消すことなく、 * # ユーザが SPE 上に持ち続けることができるため。 * # もちろん管理はユーザに任せるわけだ。 */ void SchedTask::ex_read_normal() { } void SchedTask::exec() { __debug("[SchedTask:%s]\n", __FUNCTION__); #if !defined(NO_PIPELINE) scheduler->dma_wait(DMA_READ); task_list[task->command].wait(scheduler,task->command); #endif task_list[task->command].run(this, readbuf, writebuf); free(readbuf); if (taskGroup->status() != 0) { task->self = (int)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() { __debug("[SchedTask:%s]\n", __FUNCTION__); #if !defined(NO_PIPELINE) scheduler->dma_wait(DMA_WRITE); free(writebuf); #endif if ((int)task->self == MY_SPE_NOP) return; (this->*ex_write)(); } /** * SPE 内で生成されたタスクの ex_read() */ void SchedTask::ex_read_renew() { writebuf = scheduler->allocate(outListData->size); } /** * PPE 内で生成されたタスクの ex_exec() */ void SchedTask::ex_exec_normal() { } /** * SPE 内で生成されたタスクの ex_exec() */ void SchedTask::ex_exec_renew() { } /** * PPE 内で生成されたタスクの ex_write() * * このタスク内で新たにタスクが生成され、 * 且つそのタスクの終了を待つ必要がある場合、 * PPE に終了したことは知らせない(command は送信しない) */ void SchedTask::ex_write_normal() { /** * このタスク内で新たにタスクが生成されなかった * or 生成されたが、そのタスクの終了を待つ必要は無い */ if (renew_flag == 0) { scheduler->mail_write((int)task->self); } } /** * SPE 内で生成されたタスクの ex_write() * * A <- 親タスク * | \ * B C <- SPE 内で生成されたタスク * * A は SPE 内で B, C を生成したとする。 * B と C が終了したら、A が PPE に送るはずだったコマンドが * 子タスクに引き継がれているので、最後に実行された子タスクが * PPE に mail 送信する。 */ void SchedTask::ex_write_renew() { uint32 cmd; taskGroup->remove(task); cmd = taskGroup->status(); // タスク内で作られた全てのタスクが終了した if (cmd != 0) { delete taskGroup; scheduler->mail_write(cmd); } } SchedTaskBase* SchedTask::next(Scheduler *scheduler, SchedTaskBase *p) { __debug("[SchedTask:%s]\n", __FUNCTION__); // delete p; move to Scheduler return (this->*ex_next)(); } SchedTaskBase* SchedTask::ex_next_normal() { 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(scheduler, nextTask); ((SchedTask*)nextSched)->init(list, nextTask, cur_index, // scheduler->get_curReadBuf(), // scheduler->get_curWriteBuf(), scheduler); return nextSched; } } else { memaddr nextList = (memaddr)list->next; if (nextList == 0) { return new SchedNop2Ready(scheduler); } else { return createSchedTaskList(nextList, scheduler, SCHED_TASKLIST_NORMAL); } } } /** * */ SchedTaskBase* SchedTask::ex_next_renew() { TaskPtr nextTask; SchedTask *nextSched; if (cur_index < list->length) { nextTask = &list->tasks[cur_index++]; nextSched = createSchedTask(scheduler, 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(scheduler, 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() { return scheduler->id; } /** * task->add_inData で与えられた順番に対応する index (0〜n-1) で、 * buffer から対応するデータを返す。 */ void* SchedTask::get_input(void *buff, int index) { if (buff != NULL) { return (void*)((memaddr)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*)((memaddr)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; // already allocated // p->inData = (ListData*)scheduler->allocate(sizeof(ListData)); // p->outData = (ListData*)scheduler->allocate(sizeof(ListData)); p->inData.clear(); p->outData.clear(); p->self = (int)MY_SPE_NOP; p->param_size = 0; return p; } /** * * @param[in] waitTask タスク内で生成したタスクの登録(spawn()に相当) */ void SchedTask::wait_task(TaskPtr waitTask) { waitTask->self = (memaddr)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_set(int id, void *addr) { scheduler->global_set(id, addr); } void SchedTask::global_free(int id) { scheduler->global_free(id); } MemList* SchedTask::createMemList(int size, int count) { return scheduler->createMemList(size, count); } void SchedTask::mainMem_alloc(int id, int size) { scheduler->mainMem_alloc(id, size); } void SchedTask::mainMem_wait() { 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); } void SchedTask::show_dma_wait() { scheduler->show_dma_wait(); } MemorySegment * SchedTask::get_segment(memaddr addr, MemList *m) { return scheduler->get_segment(addr,m); } void SchedTask::put_segment(MemorySegment *s) { scheduler->put_segment(s); } void SchedTask::wait_segment(MemorySegment *s) { scheduler->wait_segment(s); } /* system call */ int SchedTask::fprintf(FILE * stream, const char * format, ...) { va_list ap; va_start(ap,format); int ret = vfprintf(stream,format, ap); va_end(ap); return ret; } int SchedTask::printf(const char * format, ...) { va_list ap; va_start(ap,format); int ret= vfprintf(stdout,format, ap); va_end(ap); return ret; } /* end */