diff TaskManager/kernel/schedule/SchedTask.cc @ 308:2ac66db4dd11

remove SchedTaskImpl
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 08 Jun 2009 19:36:48 +0900
parents b0d37afab06a
children c59d8927c4d1
line wrap: on
line diff
--- a/TaskManager/kernel/schedule/SchedTask.cc	Mon Jun 08 19:32:38 2009 +0900
+++ b/TaskManager/kernel/schedule/SchedTask.cc	Mon Jun 08 19:36:48 2009 +0900
@@ -1,8 +1,559 @@
+#include <stdlib.h>
+#include <string.h>
 #include "SchedTask.h"
+#include "SchedTask.h"
+#include "SchedTaskList.h"
+#include "SchedNop2Ready.h"
+#include "DmaManager.h"
+#include "error.h"
+#include "TaskManager.h"
 
-SchedTask*
+extern Scheduler::TaskObject task_list[MAX_TASK_OBJECT];
+
+//#define NO_PIPELINE 
+
+SchedTask *
 createSchedTask(TaskPtr task)
 {
-    return createSchedTaskImpl(task);
+    return task_list[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;
+    
+    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)
+{
+    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);
+#if defined(NO_PIPELINE)
+    __scheduler->dma_wait(DMA_READ_IN_LIST);
+    __scheduler->dma_wait(DMA_READ_OUT_LIST);
+#endif
+    
+    __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__);
+
+#if !defined(NO_PIPELINE)
+    __scheduler->dma_wait(DMA_READ_IN_LIST);
+    __scheduler->dma_wait(DMA_READ_OUT_LIST);
+#endif
+
+    __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)();
+}
+
+void
+SchedTask::exec(void)
+{
+    __debug("[SchedTask:%s]\n", __FUNCTION__);
+
+#if !defined(NO_PIPELINE)
+    __scheduler->dma_wait(DMA_READ);
+#endif
+
+    //run(__readbuf, __writebuf);
+    (this->*run_func)(__readbuf, __writebuf);
+
+    free(__readbuf);
+
+    if (__taskGroup->status() != 0) {
+	__task->self = __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(void)
+{
+    __debug("[SchedTask:%s]\n", __FUNCTION__);
+    
+#if !defined(NO_PIPELINE)
+    __scheduler->dma_wait(DMA_WRITE);
+    free(__writebuf);
+#endif
+
+    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);
+}
+
+/* end */