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 */