view TaskManager/kernel/ppe/TaskManagerImpl.cc @ 220:29e338dbc280

fix
author gongo@localhost.localdomain
date Mon, 09 Feb 2009 21:58:45 +0900
parents 44e3bf914155
children 58fd16298954
line wrap: on
line source

#include <stdio.h>
#include "TaskManagerImpl.h"
#include "types.h"
#include "error.h"
#include "../sys_task/SysTask.h"

static HTaskPtr systask_start;
static HTaskPtr systask_finish;

void
noaction(void *p)
{
}

TaskManagerImpl::TaskManagerImpl(int num)
    : machineNum(num), activeTaskQueue(NULL), waitTaskQueue(NULL) {}

/**
 * 一番最初に PPE で実行される systask_start
 * 一番最後に、全てのタスクの終了を待つ systask_finish
 * 番兵的な意味で実装
 */
void
TaskManagerImpl::systask_init(void)
{
    systask_register();

    systask_start = create_task(SYSTASK_START);
    systask_finish = create_task(SYSTASK_FINISH);

    systask_start->spawn();

    // systask_finish で spawn すると
    //   systask_finish->wait_for(systask_finish);
    // とかなって無限ループになるので、
    // これだけは明示的に append_waitTask() で
    append_waitTask(systask_finish);
}

HTaskPtr
TaskManagerImpl::create_task(int cmd)
{
    HTaskPtr new_task;

    new_task = bufferManager->create_task(cmd);
    new_task->post_func = noaction;
    new_task->mimpl = this;

    return new_task;
}

/**
 * task の依存関係を設定
 * master task が終わってから、slave task を実行するように
 * master->wait_for(slave);
 */
void
TaskManagerImpl::set_task_depend(HTaskPtr master, HTaskPtr slave)
{
    TaskQueuePtr m, s;

    m = bufferManager->create_taskQueue(master);
    s = bufferManager->create_taskQueue(slave);

    master->wait_me = TaskQueue::append(master->wait_me, s);
    slave->wait_i   = TaskQueue::append(slave->wait_i, m);
}

/**
 * タスクを実行可能キューまたは待機キューへ追加する。
 * 依存関係が満たされていれば active, まだだったら wait へ。
 * task->spawn();
 */
void
TaskManagerImpl::spawn_task(HTaskPtr task)
{
    // waiter // master
    // waitee // slave
    if (task->wait_i == NULL) {
	append_activeTask(task);
    } else {
	append_waitTask(task);	
    }

    systask_finish->wait_for(task);
}

/**
 * Task を実行可能キューに追加する
 */
void
TaskManagerImpl::append_activeTask(HTaskPtr task)
{
    TaskQueuePtr q;

    q = bufferManager->create_taskQueue(task);
    activeTaskQueue = TaskQueue::append(activeTaskQueue, q);
}

/**
 * タスクが実行する CPU を選択する
 *
 * 現在は CPU_PPE, CPU_SPE, SPE_ANY, SPE_0, SPE_1, ..., SPE_5
 * types.h に書いてます。
 */
void
TaskManagerImpl::set_task_cpu(HTaskPtr task, CPU_TYPE type)
{
    task->cpu_type = type;
}

/**
 * 終了したタスクから依存の処理とか
 * post_func() はこのタスクが終了したら実行する関数。
 * 今のところ使ってないっす
 *
 * @param [task] 終了したタスク
 */
void
TaskManagerImpl::check_task_finish(HTaskPtr task)
{
    notify_wait_taskQueue(task, task->wait_me);
    task->post_func(task->post_arg);
    bufferManager->free_task(task);
}

/**
 * 終了したタスク [depend] を待っている TaskList に
 * 終わった事を知らせる(削除する
 */
void
TaskManagerImpl::notify_wait_taskQueue(HTaskPtr depend, TaskQueuePtr list)
{
    TaskQueuePtr p;
    HTaskPtr task;    

    p = list; // wait task list

    while (p) {
	task = (HTaskPtr)p->task;
	task->wait_i = remove_taskQueue_eq_task(task->wait_i, depend);
	p = p->next;
    }

    remove_taskQueue_all(list);
}

void
TaskManagerImpl::append_waitTask(HTaskPtr task)
{
    TaskQueuePtr q;

    q = bufferManager->create_taskQueue(task);
    waitTaskQueue = TaskQueue::append(waitTaskQueue, q);
}

/**
 * waitQueue の中で依存関係を満たしたタスクは
 * activeQueue へ移す
 */
void
TaskManagerImpl::wakeup_waitTask(void)
{
    TaskQueuePtr p, tmp;

    p = waitTaskQueue;
    while (p) {
	HTaskPtr task = (HTaskPtr)p->task;
	tmp = p;
	p = p->next;
	if (task->wait_i == NULL) {
	    append_activeTask(task);
	    waitTaskQueue = remove_taskQueue(waitTaskQueue, tmp);
	}
    }
}

void
TaskManagerImpl::remove_taskQueue_all(TaskQueuePtr list)
{
    TaskQueuePtr p = list;
    TaskQueuePtr p1;

    while (p != NULL) {
	p1 = p->next;
	bufferManager->free_taskQueue(p);
	p = p1;
    }
}

/**
 * [list] が持つ queue->task の中に [task] と同じ奴があれば
 * 削除する。まあ remove_taskQueue() の HTask で比較するverです。
 * こういうのはオーバーロードでやるもんなのかな?
 */
TaskQueuePtr
TaskManagerImpl::remove_taskQueue_eq_task(TaskQueuePtr list, HTaskPtr task)
{
    TaskQueuePtr p = list;
    TaskQueuePtr p1;
    
    if (p == NULL) return p;

    if (p->task == task) {
	list = list->next;
	bufferManager->free_taskQueue(p);
    } else {
	p1 = p->next;
	while (p1 && p1->task && p1->task != task) {
	    p1 = p1->next;
	    p = p->next;
	}
	if (p1) {
	    p->next = p1->next;
	    bufferManager->free_taskQueue(p1);
	}
    }

    return list;    
}

TaskQueuePtr
TaskManagerImpl::remove_taskQueue(TaskQueuePtr list, TaskQueuePtr q)
{
    TaskQueuePtr p = list;
    TaskQueuePtr p1;

    if (!p) return p;

    if (p == q) {
	list = list->next;
	bufferManager->free_taskQueue(p);
    } else {
	p1 = p->next;
	while (p1 && p1 != q) {
	    p1 = p1->next;
	    p = p->next;
	}
	if (p1) {
	    p->next = p1->next;
	    bufferManager->free_taskQueue(p1);
	}
    }

    return list;
}