view TaskManager/kernel/schedule/SchedTask.cc @ 321:f64d75473f95

merge 317
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Wed, 10 Jun 2009 15:23:25 +0900
parents 7efc5ede2c03
children 20f2459041cb
line wrap: on
line source

#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"

extern Scheduler::TaskObject task_list[MAX_TASK_OBJECT];

//#define NO_PIPELINE 

SchedTask *
createSchedTask(TaskPtr 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;
    run_func1 = &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);
    }


}

/**                                                                         
 * このタスクを 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 = 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);
    (this->*run_func1)(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(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 */