Mercurial > hg > Members > kono > Cerium
view TaskManager/kernel/schedule/Scheduler.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 |
parents | 1733f3cbfa28 |
children | 0decff4e867b |
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() { delete connector; } /*! @brief speTaskの入出力のパイプラインバッファを確保する */ void Scheduler::init() { hash = 0; 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; bak_curTaskList = NULL; } void Scheduler::run() { task1 = new SchedNop(); task2 = new SchedNop(); task3 = new SchedNop(); // main loop do { __debug("----------\n"); task3->write(); task2->exec(); task1->read(); delete task3; task3 = task2; task2 = task1; task1 = task1->next(this, 0); } while (task1); delete task3; delete task2; } void Scheduler::finish() { 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() { buffFlag_taskList ^= 1; return buff_taskList[buffFlag_taskList]; } /** * Task に inListData, outListData を入れたので、 * これは必要ないらしい。 * * あらかじめ memory allocte してある ListData の領域を * パイプラインの各処理が交代して使う。 */ #if 0 ListDataPtr Scheduler::get_curWriteBuf() { buffFlag_outListData ^= 1; return buff_outListData[buffFlag_outListData]; } ListDataPtr Scheduler::get_curReadBuf() { buffFlag_inListData ^= 1; return buff_inListData[buffFlag_inListData]; } #endif /** * タスク内で生成されたタスクを格納する TaskList を取得する * 現在格納に使っている TaskList (renewCur_taskList) が使えるならそれを返す * もしそうでないなら、新しく TaskList を allocate してそれを返す * コード中で renewCur_taskList が NULL になるのは * - プログラム開始時 * - タスク内生成タスクがある TaskList の実行を新しく始める (Nop2Ready 参照) * 以上の場合です */ TaskListPtr Scheduler::get_renewListBuf() { 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() { if (renewTop_taskList) { TaskListPtr list = renewTop_taskList; renewTop_taskList = renewTop_taskList->next; renewCur_taskList = NULL; list->next = NULL; SchedTaskList *sched = createSchedTaskList((memaddr)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() { TaskListPtr ret = bak_curTaskList; bak_curTaskList = NULL; return ret; } int Scheduler::get_backupTaskListIndex() { 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() { 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() { 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]; } /** * Task load API */ void Scheduler::allocate_code_segment(int size, int count) { // 既に overlay 領域があるので、それを追加する必要がある... code_segment_pool = createMemList(size, count); } static void load_task(Scheduler *m, int task_id) { MemorySegment *s = m->get_segment( task_list[task_id].location, m->code_segment_pool, task_list[task_id].end-task_list[task_id].location); task_list[task_id].segment = s; #if 0 fprintf(stderr,"loadng task id %d at 0x%x entry 0x%x\n",task_id, (unsigned int)(task_list[task_id].segment->data ), (unsigned int)( (char*)task_list[task_id].segment->data + task_list[task_id].entry_offset)); #endif } static void null_loader(Scheduler *m, int task_id) { } static void wait_load(Scheduler *m, int task_id) { #if 0 MemorySegment *s = task_list[task_id].segment; if (s) fprintf(stderr,"wait load task id %d 0x%x\n",task_id,(int)s->data); else fprintf(stderr,"wait load task id %d 000000\n",task_id); #endif // wait for code segment load m->wait_segment(task_list[task_id].segment); // calcurate call address TaskObjectRun run = (TaskObjectRun)( (char*)task_list[task_id].segment->data + task_list[task_id].entry_offset); task_list[task_id].run = run; #if 0 fprintf(stderr,"wait load task id %d done. creator = 0x%x entry_offset = 0x%x\n",task_id, (unsigned int)run, task_list[task_id].entry_offset); #endif } static void null_waiter(Scheduler *m, int task_id) { } extern void register_task(int cmd, TaskObjectRun run) { task_list[cmd].run = run; task_list[cmd].load = null_loader; task_list[cmd].wait = null_waiter; } extern void register_dynamic_task(int cmd, memaddr start, int size, TaskObjectRun run, int entry_offset) { task_list[cmd].run = run; task_list[cmd].location = start; size &= 0xfffffffe; task_list[cmd].end = start+size; task_list[cmd].entry_offset = entry_offset; task_list[cmd].load = load_task; task_list[cmd].wait = wait_load; #if 0 fprintf(stderr,"cmd = %d\n",cmd); fprintf(stderr,"locatation = 0x%x\n",start); fprintf(stderr,"end = 0x%x\n",start+size); fprintf(stderr,"size = 0x%x\n",size); fprintf(stderr,"entry = 0x%x\n",entry_offset); #endif } /*! 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); if (!hash) { hash = new MemHash(); } 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; next->address = (memaddr)next; mlist->addLast(next); } return mlist; } /*! Main Memory のSegmentを取得する @param [addr] Main Memory のアドレス @param [m] Mem List @return allocate した領域のポインタ memory directory にあるべきだが... */ MemorySegment * Scheduler::get_segment(memaddr addr, MemList *m) { MemorySegment *s = m->getFirst(); return get_segment(addr, m, s->size); } MemorySegment * Scheduler::get_segment(memaddr addr, MemList *m, int size) { // memory segment のsizeをoverride する場合がある MemorySegment *s = hash->get(addr); if (s) { /* 既に load されている */ // fprintf(stderr,"get_segement loaded %llx 0x%x size 0x%d\n",addr,s->data,size); m->moveToFirst(s); return s; } /* LRU なので、もっとも使われてない segment を上書きする */ s = m->getLast(); m->moveToFirst(s); memaddr old_addr = s->address; s->tag = get_tag(); dma_load(s->data, addr, size, s->tag); /* 前のをhashから削除 */ hash->remove(old_addr); /* 新しいaddress を登録 */ s->address = addr; hash->put(s->address, s); // fprintf(stderr,"get_segement %llx 0x%x size 0x%d\n",addr, s->data,size); return s; } uint32 Scheduler::get_tag() { static int tag = 16; tag ++; tag &= 0x0f; return tag+16; } /*! Main Memory のSegmentを書き出す Segment は get_segement されていて、 追い出されていてはいけない。 それを保証するのは難しい? @param [addr] Main Memory のアドレス @param [m] Mem List @return allocate した領域のポインタ */ void Scheduler::put_segment(MemorySegment *s) { dma_store(s->data, s->address, s->size, s->tag); } /*! Main Memory のSegmentを読込、書き出しを待つ @param [id] MemorySegment のid */ void Scheduler::wait_segment(MemorySegment *s) { // えーと、dma してない時には、skip しないとだめなんじゃないの? if (s->tag) dma_wait(s->tag); s->tag = 0; } /* end */