view TaskManager/Fifo/FifoTaskManagerImpl.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 eab18aa0c7f6
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "FifoTaskManagerImpl.h"
#include "types.h"
#include "error.h"

FifoTaskManagerImpl::~FifoTaskManagerImpl(void)
{
    delete mailManager;
    delete scheduler;
    delete bufferManager;
}

/**
 * MailManager は PPE スケジューラとのメール交換、
 * FifoScheduler は PPE 側のスケジューラ
 * BufferManager は Task、TaskList などのメモリ管理(大層なことしてないが
 */
void
FifoTaskManagerImpl::init(void)
{
    mailManager = new MailManager();
    mailManager->init(20);

    scheduler = new MainScheduler();
    scheduler->init();
    scheduler->set_mailManager(mailManager);
    scheduler->id = 0;

    bufferManager = new BufferManager;
    bufferManager->init();

    mainTaskList = bufferManager->create_taskList();
}

/**
 * これは CellTaskManagerImpl から呼ばれる。
 * BufferManager は共用で使うので引数に。
 * CellTaskManagerImpl と FifoTaskManagerImpl が同時に
 * 上のデータにアクセスする事は(今は)ないのでこれでおk 
 */
void
FifoTaskManagerImpl::init(MainScheduler *_sched, BufferManager *buff)
{
    mailManager = new MailManager();
    mailManager->init(20);

    //scheduler = new MainScheduler();
    scheduler = _sched;
    scheduler->init();
    scheduler->set_mailManager(mailManager);

    bufferManager = buff;

    mainTaskList = bufferManager->create_taskList();
}

/**
 * スケジューラに渡す TaskList を取得する。
 *
 * @return 実行タスクリスト
 *
 * ActiveTaskQueue (依存条件は満たし済み) のタスクを
 * 実行タスクリストに入れる
 */
TaskListPtr
FifoTaskManagerImpl::get_runTaskList(void)
{
    TaskListPtr list, list_top;
    TaskQueuePtr queue;
    TaskQueuePtr d;
    HTaskPtr htask; // HTask (PPE にある)
    TaskPtr task; // Task (SPE に送る Task)

    queue = activeTaskQueue;
    if (queue == NULL) {
	return NULL;
    }

    // PPE 側で実行される TaskList
    list_top = mainTaskList;

    // list_top->clear() とかの方がいいかもしれん。
    list_top = bufferManager->clear_taskList(list_top);
    list = list_top;

    while (queue) {
	htask = (HTaskPtr)queue->task;
	d = queue;
	queue = queue->next;

	task = &list->tasks[list->length++];

#if 0
	task->command  = htask->command;
	task->inData   = htask->inData;
	task->outData  = htask->outData;
	task->self     = (unsigned int)htask;
#else
	memcpy(task, htask, sizeof(Task));
#endif

	if (list->length >= TASK_MAX_SIZE) {
	    TaskListPtr newList = bufferManager->create_taskList();
	    list_top = TaskListInfo::append(list_top, newList);
	    list = newList;
	}

	bufferManager->free_taskQueue(d);
    }

    activeTaskQueue = NULL;
    mainTaskList = list_top;

    return list_top;
}


void
FifoTaskManagerImpl::run(void)
{
    TaskListPtr list;
    MailQueuePtr mail;

    list = get_runTaskList();

    do {
	// list を実行する
	mail = schedule(list);

	// mail には、ppe scheduler からの mail がある
	mail_check(mail);

	// 依存関係を満たしたものは実行可能キューへ
	wakeup_waitTask();
	list = get_runTaskList();
    } while (list);
}

/**
 * @param [list] 実行タスクリスト
 * @return FifoScheduler からのメール
 *
 * [Tasklist] -> [番兵] -> scheduler->run を抜ける
 */
MailQueuePtr
FifoTaskManagerImpl::schedule(TaskListPtr list)
{
    MailQueuePtr list_mail; // task list
    MailQueuePtr sentinel;  // 番兵
    MailQueuePtr in_mail_list = NULL;
    MailQueuePtr out_mail_list = NULL;

    // TaskList のアドレス
    list_mail =	mailManager->create((unsigned int)list);
    in_mail_list = MailManager::append_mailQueue(in_mail_list, list_mail);

    // EXIT_COMMAND (番兵的な意味で)
    sentinel  = mailManager->create(MY_SPE_COMMAND_EXIT);
    in_mail_list = MailManager::append_mailQueue(in_mail_list, sentinel);
    
    // scheduler は受け取ったメールを元に実行する
    scheduler->send_mailList(in_mail_list);
    scheduler->run();
    out_mail_list = scheduler->recv_mailList(); 

    return out_mail_list;
}

/**
 * PPE Scheduler からのメールをチェックする
 *
 * @param [mail_list]
 *        PPE 側で動く Scheduler からのメールリスト
 *        終了した Task や、その他(今はまだ実装してないけど)の情報が入ってる
 *
 * @return Scheduler が次に実行する Task List                       
 *         NULL なら全てのタスクが実行終了したということ
 */
void
FifoTaskManagerImpl::mail_check(MailQueuePtr mail_list)
{
    MailQueuePtr q = mail_list;
    MailQueuePtr d;
    unsigned int data;

    while (q) {
	data = q->data;

	/**
	 * MY_SPE_STATUS_READY: SPE が持ってた Task 全て終了
	 * MY_SPE_NOP: 特に意味のないコマンド
	 * それ以外:終了したタスク(PPEにあるのでアドレス
	 *
	 * MY_SPE_NOP が 0 なので、
	 * 下のように data > MY_SPE_NOP とかしています。
	 * 一目でよくわからない書き方なんで、直したいところですが。。。
	 */
	if (data == MY_SPE_STATUS_READY) {
	    __debug_ppe("mail_check(): Task List finish\n");
	} else if (data > MY_SPE_NOP) {
	    __debug_ppe("mail_check(): recv from 0x%x\n", data);
	    check_task_finish((HTaskPtr)data);
	}

	d = q;
	q = q->next;

	mailManager->free(d);
    }
}

void
FifoTaskManagerImpl::mail_check(MailQueuePtr mail_list, TaskQueuePtr *wait)
{
    waitTaskQueue = *wait;
    mail_check(mail_list);
}

void*
FifoTaskManagerImpl::allocate(int size)
{
    return malloc(size);
}

/**
 * こういう使い方を
 *   Abstract Factory Pattern
 * というらしい。
 */
#ifdef __CERIUM_FIFO__
TaskManagerImpl* 
create_impl(int num)
{
    return new FifoTaskManagerImpl();
}
#endif // __CERIUM_FIFO__