view TaskManager/kernel/schedule/SchedTask.cc @ 467:44c0bce54dcf

fix all examples. test_render is not working now.
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Thu, 01 Oct 2009 19:25:25 +0900
parents 4fa8760e18c2
children bd5b93d39597
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 を行う
 * このタスクが RenewTask だった場合、
 * __inListData や __outListData は
 * Scheduler の持つ、使い回しの buffer ではなく
 * 新たに allocate されたものなので、ここで free する
 */
SchedTask::~SchedTask()
{
    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);
    }


}

/**
 * このタスクを 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  = rbuf;
    __outListData = wbuf;
    __scheduler   = sc;
    __cur_index   = index;

    __scheduler->mainMem_wait();

    (this->*ex_init)();
}

/**
 * PPE 内で生成されたタスクの ex_init()
 */
void
SchedTask::ex_init_normal()
{
    __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()
{
    __inListData = __task->inData;
    __outListData = __task->outData;
    __taskGroup = (TaskGroupPtr)__task->self;
}

/**
 * [Todo]
 *   データの読み込み場所を readbuf ではなく、
 *   ユーザ自身で決めれるようになるといいかもしれない。
 *
 *   # TaskManager が勝手に消すことなく、
 *   # ユーザが SPE 上に持ち続けることができるため。
 *   # もちろん管理はユーザに任せるわけだ。
 */
void
SchedTask::read()
{
    __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()
{
    __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 = __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 (__task->self == MY_SPE_NOP) return;

    (this->*ex_write)();
}

/**
 * PPE 内で生成されたタスクの ex_read()
 */
void
SchedTask::ex_read_normal()
{
}

/**
 * SPE 内で生成されたタスクの ex_read()
 */
void
SchedTask::ex_read_renew()
{
}

/**
 * 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(__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;

    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++];
	    if (__cur_index < __list->length) {
		// load next task
		loadSchedTask(__scheduler, &__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 {
        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()
{
    TaskPtr nextTask;
    SchedTask *nextSched;

    if (__cur_index < __list->length) {
        nextTask = &__list->tasks[__cur_index++];
	if (__cur_index < __list->length) {
	    // load next task
	    loadSchedTask(__scheduler, &__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++];
		if (__cur_index < __list->length) {
		    // load next task
		    loadSchedTask(__scheduler, &__list->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*)((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_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 */