view TaskManager/kernel/schedule/SchedTask.cc @ 602:1733f3cbfa28

64bit mode try... not worked.
author e075740@nw0740.st.ie.u-ryukyu.ac.jp
date Fri, 06 Nov 2009 21:20:26 +0900
parents 47b61865ea8c
children 42c94f85c779
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 を行う
 */
SchedTask::~SchedTask()
{
    if (flag_renewTask == SCHED_TASK_RENEW) {
        /**
         * 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  = &_task->inData;
    outListData = &_task->outData;
    scheduler   = sc;
    cur_index   = index;

    scheduler->mainMem_wait();

    (this->*ex_init)();
}

/**
 * PPE 内で生成されたタスクの ex_init()
 */
void
SchedTask::ex_init_normal()
{
#if 0
    // task list に入れたので既に読んでいる?
    //
    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
#endif

    taskGroup = new TaskGroup;
    taskGroup->command = (int)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;
}

void
SchedTask::read()
{
    __debug("[SchedTask:%s]\n", __FUNCTION__);

#if 0
#if !defined(NO_PIPELINE)
    scheduler->dma_wait(DMA_READ_IN_LIST);
    scheduler->dma_wait(DMA_READ_OUT_LIST);
#endif
#endif
    // object creation をSchedTask生成時にやらないので、
    // exec の直前のread で十分に間に合う
    if (cur_index < list->length) {
	// load next task
	loadSchedTask(scheduler, &list->tasks[cur_index]);
    }

    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)();
}

/**
 * PPE 内で生成されたタスクの ex_read()
 *
 * [Todo]
 *   データの読み込み場所を readbuf ではなく、
 *   ユーザ自身で決めれるようになるといいかもしれない。
 *
 *   # TaskManager が勝手に消すことなく、
 *   # ユーザが SPE 上に持ち続けることができるため。
 *   # もちろん管理はユーザに任せるわけだ。
 */
void
SchedTask::ex_read_normal()
{
}

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 = (int)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 ((int)task->self == MY_SPE_NOP) return;

    (this->*ex_write)();
}


/**
 * SPE 内で生成されたタスクの ex_read()
 */
void
SchedTask::ex_read_renew()
{
    writebuf = scheduler->allocate(outListData->size);
}

/**
 * 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((int)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;  move to Scheduler

    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++];
            nextSched = createSchedTask(scheduler, nextTask);
            ((SchedTask*)nextSched)->init(list, nextTask, cur_index,
                                              // scheduler->get_curReadBuf(),
                                              // scheduler->get_curWriteBuf(),
                                              scheduler);
            return nextSched;
        }
    } else {
        long nextList = (long)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++];
        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++];
                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*)((long)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*)((long)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;

    // already allocated 
    // p->inData = (ListData*)scheduler->allocate(sizeof(ListData));
    // p->outData = (ListData*)scheduler->allocate(sizeof(ListData));

    p->inData.clear();
    p->outData.clear();

    p->self = (int)MY_SPE_NOP;
    p->param_size = 0;

    return p;
}

/**
 *
 * @param[in] waitTask タスク内で生成したタスクの登録(spawn()に相当)
 */
void
SchedTask::wait_task(TaskPtr waitTask)
{
    waitTask->self = (long)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 */