view TaskManager/kernel/schedule/SchedTask.cc @ 109:5c194c71eca8

Cerium cvs version
author gongo@gendarme.local
date Wed, 12 Nov 2008 17:39:33 +0900
parents 3e331f7576a1
children 5cde66c926b4
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"

extern Scheduler::TaskObject task_list[MAX_TASK_OBJECT];

SchedTask*
CreateSchedTask(TaskListPtr taskList, Scheduler *sched)
{
    TaskPtr task = &taskList->tasks[sched->curIndex_taskList++];
    
    return task_list[task->command](taskList, task, sched->get_curReadBuf(),
				    sched->get_curWriteBuf(), sched);
}

SchedTask::SchedTask(TaskListPtr _list, TaskPtr _task, ListDataPtr rbuf,
		     ListDataPtr wbuf, Scheduler* sc)
{
    __list        = _list;
    __task        = _task;
    __inListData  = rbuf;
    __outListData = wbuf;
    __readbuf     = NULL;
    __writebuf    = NULL;
    __scheduler   = sc;
    __taskGroup   = NULL;
    __renew_flag  = 0;

    smanager = new STaskManager(this);
}

SchedTask::~SchedTask(void)
{
    if (__flag_renewTask) {
	/**
	 * __inListData と __outListData はタスク自身のものなので
	 * 終わったら即 free する。
	 */
	free(__inListData);
        free(__outListData);
 
	/**
	 * __list != NULL の場合、
	 * この Task が __list の最後の Task になるので (SchedTask::next 参照)
	 * このタイミングで __list を解放する
	 *   (free に渡されるアドレスが正しいものとなる)。
	 * それ以外の Task では当然解放しない。
	 *  __list == NULL なので、free に渡しても無問題
	 */
	free(__list);
    }

    delete smanager;
}

void
SchedTask::__init__(void)
{
    /**
     * task->inData や task->outData が
     * PPE のものか、SPE のものかって
     * アドレスで判定できれば楽になると思うんだが。。。
     */
    /**
     * 関数ポインタでやるか・・?
     */
    if (__flag_renewTask == 0) {
	__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);
	
	__taskGroup = new TaskGroup;
	__taskGroup->command = __task->self;
    } else {
	__inListData = __task->inData;
	__outListData = __task->outData;
	__taskGroup = (TaskGroupPtr)__task->self;
    }
}


/**
 * [Todo]
 *   データの読み込み場所を readbuf ではなく、
 *   ユーザ自身で決めれるようになるといいかもしれない。
 *
 *   # TaskManager が勝手に消すことなく、
 *   # ユーザが SPE 上に持ち続けることができるため。
 *   # もちろん管理はユーザに任せるわけだ。
 */
void
SchedTask::read(void)
{    
    __debug("[SchedTask:%s]\n", __FUNCTION__);

    // wait for load inListData 
    __scheduler->dma_wait(DMA_READ_IN_LIST);

    // 読むデータが一つもなければ無視
    if (__inListData->length < 1 || __inListData->size == 0) return;

    // load Input Data
    __readbuf = __scheduler->allocate(__inListData->size);
    __scheduler->dma_loadList(__inListData, __readbuf, DMA_READ);
}

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

    // wait for load outListData 
    __scheduler->dma_wait(DMA_READ_OUT_LIST);
    __scheduler->dma_wait(DMA_READ);

    __writebuf = __scheduler->allocate(__outListData->size);

    __debug("  task->command  = %d\n", __task->command);
    __debug("  task->in_size  = %d\n", __task->in_size);
    __debug("  task->in_addr  = 0x%x\n", __task->in_addr);
    __debug("  task->out_addr = 0x%x\n", __task->out_addr);
    __debug("  list->next     = 0x%x\n", (unsigned int)__list->next);
    __debug("  list->length   = 0x%x\n", (unsigned int)__list->length);

    run(__readbuf, __writebuf);

    // 書き込む領域が要らなければ無視
    if (__outListData->size > 0) {
	__scheduler->dma_storeList(__outListData, __writebuf, DMA_WRITE);
    }

    if (__taskGroup->status() != 0) {
	__task->self = __taskGroup->command;
	delete __taskGroup;
	__taskGroup = NULL;
    }

    free(__readbuf);
}

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

    __scheduler->dma_wait(DMA_WRITE);

    free(__writebuf);

    /**
     * タスクが生成されている場合、
     * そのタスクが終わってからこのタスク終了コマンドを送る。
     * # コマンドは生成されたタスクに引き継がれる
     */
    if (__task->self == MY_SPE_NOP) return;

    if (__flag_renewTask) {
	uint32 cmd;
	
	__taskGroup->remove(__task);
	cmd = __taskGroup->status();

	if (cmd != 0) {
	    delete __taskGroup;
	    __scheduler->mail_write(cmd);
	}
    } else {
	if (__renew_flag == 0) {
	    __scheduler->mail_write(__task->self);
	}
    }
}
    
SchedTaskBase*
SchedTask::next(Scheduler *m, SchedTaskBase *p)
{
    __debug("[SchedTask:%s]\n", __FUNCTION__);

    delete p;

    if (__scheduler->curIndex_taskList < __list->length) {
	SchedTask* schedTask = CreateSchedTask(__list, __scheduler);
	schedTask->__flag_renewTask = this->__flag_renewTask;
	schedTask->__init__();

	/**
	 * この理由は SchedTask:~SchedTask() で
	 */
	__list = NULL;

	return schedTask;
    } else {
	uint32 nextList = (uint32)__list->next;

	if (nextList == 0) {
	    return new SchedNop2Ready(__scheduler);
	} else {
	    return new SchedTaskList(nextList, __scheduler);
	}
    }
}

/**
 * task->add_input で与えられた順番に対応する 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;
    }
}

/**
 * write buffer の領域を返す。
 */
void*
SchedTask::get_output(void *buff, int index)
{
    if (buff != NULL) {
	return (void*)((int)buff + __outListData->bound[index]);
    } else {
	return NULL;
    }
}

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

/**
 * 名前が。。。
 */
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);
}