Mercurial > hg > Members > e085722 > Cerium
diff TaskManager/kernel/ppe/TaskManagerImpl.cc @ 0:04e28d8d3c6f
first commit
author | Daiki KINJYO <e085722@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 08 Nov 2010 01:23:25 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TaskManager/kernel/ppe/TaskManagerImpl.cc Mon Nov 08 01:23:25 2010 +0900 @@ -0,0 +1,312 @@ +#include <stdio.h> +#include "TaskManagerImpl.h" +#include "types.h" +#include "error.h" +#include "SchedTask.h" +#include "Scheduler.h" +#include "SysTask.h" +#include "SysFunc.h" +#include <string.h> + +// singleton +QueueInfo<TaskQueue> *taskQueuePool = new QueueInfo<TaskQueue>() ; +QueueInfo<HTask> *htaskPool = new QueueInfo<HTask>() ; +QueueInfo<TaskList> *taskListPool = new QueueInfo<TaskList>() ; + + +static HTaskPtr systask_start; +static HTaskPtr systask_finish; + +static void +noaction(SchedTask *s, void *read, void *write) +{ +} + +TaskManagerImpl::TaskManagerImpl(int num) + : machineNum(num){ + // 実行可能なHTaskのリスト + activeTaskQueue = new QueueInfo<HTask>(htaskPool); + // wait_forで止まっているHTaskのリスト。必要ないが、Dead lock detection に使う + waitTaskQueue = new QueueInfo<HTask>(htaskPool); + // HTask の factory. QueueInfo<HTask> ならなんでもいい。 + htaskImpl = waitTaskQueue ; // any QueueInfo<HTask> + // Task の dependency を表現する double linked list. QueueInfo<HTask> とは別に必要。 + taskQueueImpl = new QueueInfo<TaskQueue>(taskQueuePool); +} + +/** + * 一番最初に PPE で実行される systask_start + */ +void +TaskManagerImpl::systask_init() +{ + systask_register(); + systask_start = create_task(StartTask,0,0,0,0,__builtin_return_address(0)); + systask_finish = create_task(FinishTask,0,0,0,0,__builtin_return_address(0)); + + systask_start->spawn(); + + // すべての Task が FinishTask を wait_for すると、 + // あらゆる Task が FinishTask の waiting task queue を操作する + // ことになる。それは、重すぎる。PPE/SPE Task が終了した時点で、 + // TaskManager が実行する方が安い。 + // append_waitTask(systask_finish); +} + +/** + * Create Simple Task + */ +HTaskPtr +TaskManagerImpl::create_task(int cmd,memaddr rbuf, long r_size, memaddr wbuf, long w_size, void *from) { + HTaskPtr new_task; + + new_task = htaskImpl->create(); + new_task->init(cmd, rbuf, r_size, wbuf, w_size); + new_task->post_func = noaction; + new_task->mimpl = this; + new_task->from = (memaddr)from; +#ifdef EARLY_TOUCH + if (rbuf) { + if ((unsigned long)rbuf&0xf) { + printf("Data is not aligned. command = %d, addr = 0x%lx, size = %ld\n", + cmd, (unsigned long)rbuf, r_size); + } + char *p = (char *)rbuf; char b = *p; + p = (char *)(rbuf+r_size-1); b += *p; + } + if (wbuf) { + if ((unsigned long)wbuf&0xf) { + printf("Data is not aligned. command = %d, addr = 0x%lx, size = %ld\n", + cmd, (unsigned long)wbuf, w_size); + } + char *p = (char *)wbuf; char b = *p; + p = (char *)(wbuf+w_size-1); b += *p; + } +#endif + + return new_task; +} + +/** + * Create Compatible Task (TaskArray1) + */ +HTaskPtr +TaskManagerImpl::create_task(int cmd,void *from) +{ + HTaskPtr new_task; + + // for compatibility + new_task = htaskImpl->create(); new_task->init(TaskArray1); + new_task->post_func = noaction; + new_task->mimpl = this; + new_task->create_task_array(cmd,1,8,8,8); + // rbuf, r_size were set + new_task->command = TaskArray1; + new_task->from = (memaddr)from; + + return new_task; +} + +/** + * Create Task Array + */ +HTaskPtr +TaskManagerImpl::create_task_array(int id, int num_task, int num_param, int num_inData, int num_outData, void *from) +{ + HTaskPtr ta = create_task(TaskArray,0,0,0,0, from); + ta->create_task_array(id, num_task, num_param, num_inData, num_outData) ; + return ta; +} + +/** + * task の依存関係を設定 + * master task が終わってから、slave task を実行するように + * master->wait_for(slave); + */ +void +TaskManagerImpl::set_task_depend(HTaskPtr master, HTaskPtr slave) +{ + TaskQueuePtr m, s; + if (!master->self) return; + + m = taskQueueImpl->create(); m->init(master); + s = taskQueueImpl->create(); s->init(slave); + + master->wait_me->addLast(s); + slave->wait_i->addLast(m); + s->waiter = m; +} + +/** + * タスクを実行可能キューまたは待機キューへ追加する。 + * 依存関係が満たされていれば active, まだだったら wait へ。 + * task->spawn(); + */ +void +TaskManagerImpl::spawn_task(HTaskPtr task) +{ + // waiter // master + // waitee // slave + if (task->wait_i->empty()) { + append_activeTask(task); + } else { + append_waitTask(task); + } +} + + +/** + * Task を実行可能キューに追加する + */ +void +TaskManagerImpl::append_activeTask(HTaskPtr q) +{ + activeTaskQueue->addLast(q); +} + +/** + * タスクが実行する CPU を選択する + * + * 現在は CPU_PPE, CPU_SPE, SPE_ANY, SPE_0, SPE_1, ..., SPE_5 + * types.h に書いてます。 + */ +void +TaskManagerImpl::set_task_cpu(HTaskPtr task, CPU_TYPE type) +{ + if (machineNum==0) + task->cpu_type = CPU_PPE ; + else + task->cpu_type = type; +} + +#if 0 +static void +check_wait(TaskManagerImpl *tm, QueueInfo<TaskQueue> *wait_i) { + for(TaskQueue *t = wait_i->getFirst(); t; t = wait_i->getNext(t)) { + if (!tm->waitTaskQueue->find(t->task)) { + printf("stray waiting task%d %lx\n",t->task->command, (long)t->task); + } else if (tm->activeTaskQueue->find(t->task)) { + printf(" active task%d in waiting queue %lx\n",t->task->command, (long)t->task); + } else + printf("."); + } +} +#endif + +/** + * @brief 終了したタスクから依存の処理とか + * post_func() はこのタスクが終了したら実行する関数。 + * + * @param [task] 終了したタスク + */ +void +TaskManagerImpl::check_task_finish(HTaskPtr me, QueueInfo<HTask> *wait_queue) +{ + while(TaskQueue *p = me->wait_me->poll()) { + HTaskPtr you = p->task; + QueueInfo<TaskQueue> *wait_i = you->wait_i; + // 相手の wait queue から自分(を指しているTaskQueue)を削除 + wait_i->remove(p->waiter); + // queue を free する + wait_i->free_(p->waiter); + + if (wait_i->empty()) { + wait_queue->remove(you); + append_activeTask(you); + } + + wait_i->free_(p); // p->wait_i, p->wait_me は再利用される + } + + // me を誰かが持っていて、me が finish した後に、 + // me->wait_for(i) とか、やられると気まずい。 + // 特に、me が他人に再利用されていると。そういう時には、 + // このfreeをコメントアウトしてみる。 + + // id かななんかでチェックした方が良いが... + + me->self = 0; + if (!me->flag.no_auto_free) + htaskImpl->free_(me); +} + +/** + * @brief 終了したタスクリストの依存の処理 + * @param [task] 終了したタスク + */ +void +TaskManagerImpl::check_task_list_finish(SchedTask *s, TaskListPtr list, QueueInfo<HTask> *wait_queue) +{ + for(int i = 0;i<list->length;i++) { + SimpleTaskPtr task = &list->tasks[i]; + HTask *me = (HTask*)task->self; + me->post_func(s, me->post_arg1, me->post_arg2); + if (task->command==TaskArray1) { + int next = ((task->r_size)/sizeof(SimpleTask))+1; + // assert(next<list->length); + i+=next; + } + s->polling(); + check_task_finish(me, wait_queue); + } +} + +/** + * @brief waitTaskqueue への挿入 。必須ではない。 + * 現状では、dead lock 検出にしか使ってない + * + * @param [task] 終了したタスク + */ +void +TaskManagerImpl::append_waitTask(HTaskPtr q) +{ + waitTaskQueue ->addLast(q); +} + +/** + @brief htask を DMA でCPUに渡すための TaskList に入れる (copy) + @param htask + @param taskList + TaskList は自動的に延長される + */ +void +TaskManagerImpl::set_taskList(HTaskPtr htask, QueueInfo<TaskList> * taskList) { + TaskListPtr list ; + if ( taskList->empty() ) { + list = taskList->create(); + taskList->addLast(list); + } else + list = taskList->getLast(); + SimpleTaskPtr task = &list->tasks[list->length++]; + if (htask->command==TaskArray1) { + // compatibility + int next = ((htask->r_size)/sizeof(SimpleTask))+1; + if (list->length+next>=TASK_MAX_SIZE) { + list->length--; + TaskListPtr newList = taskList->create(); + taskList->addLast(newList); + list = newList; + task = &list->tasks[list->length++]; + } + Task *array = (Task*)&list->tasks[list->length]; + list->length += next; + if (list->length>=TASK_MAX_SIZE) { + perror("task array1 overflow\n"); + } + memcpy(array, htask->rbuf, htask->r_size); + free(htask->rbuf); + // htask->rbuf = 0; htask->r_size = 0; we need this... + *task = *(SimpleTask*)htask; + } else { + *task = *(SimpleTask*)htask; + } + if (list->length >= TASK_MAX_SIZE) { + TaskListPtr newList = taskList->create(); + taskList->addLast(newList); + list = newList; + } +} + + + +/* end */