view TaskManager/Fifo/FifoTaskManagerImpl.cc @ 640:a909c50081c2

SimpeTask on Cell worked.
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Fri, 20 Nov 2009 23:12:34 +0900
parents 671fca057ad3
children bffdede05f1e
line wrap: on
line source

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

FifoTaskManagerImpl::~FifoTaskManagerImpl()
{
    delete mailManager;
    delete mainScheduler;

    delete taskListImpl  ;
    delete taskQueueImpl ;
    delete htaskImpl     ;

}

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

    mainScheduler = new MainScheduler();
    mainScheduler->init(this);
    mainScheduler->set_mailManager(mailManager);
    mainScheduler->id = 0;
    set_scheduler(mainScheduler);

    taskListImpl  = new TaskListInfo;
    taskQueueImpl = new TaskQueueInfo;
    htaskImpl     = new HTaskInfo();

    mainTaskList = taskListImpl->create();

    schedTaskManager = new SchedTask();
    schedTaskManager->init(0,0,0,mainScheduler);

}

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

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

    taskListImpl  = tm-> taskListImpl  ;
    taskQueueImpl = tm-> taskQueueImpl ;
    htaskImpl     = tm-> htaskImpl     ;
    waitTaskQueue     = NULL;   // mail_check で外から設定される

    mainTaskList = taskListImpl->create();


}

/**
 * スケジューラに渡す TaskList を取得する。
 *
 * @return 実行タスクリスト
 *
 * ActiveTaskQueue (依存条件は満たし済み) のタスクを
 * 実行タスクリストに入れる
 */
TaskListPtr
FifoTaskManagerImpl::get_runTaskList()
{
    TaskListPtr list, list_top;
#ifdef SIMPLE_TASK
    TaskPtr task; // Task (SPE に送る Task)
#else
    SimpleTaskPtr task; // Task (SPE に送る Task)
#endif

    if (activeTaskQueue->empty()) {
        return NULL;
    }

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

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

    // printf("active task queue length = %d\n",activeTaskQueue->length());
    while (HTaskPtr htask = activeTaskQueue->poll()) {
        task = &list->tasks[list->length++];
#ifdef SIMPLE_TASK
	*task = *(SimpleTask*)htask;
#else
        memcpy(task, (Task*)htask, sizeof(Task));
#endif
        if (list->length >= TASK_MAX_SIZE) {
            TaskListPtr newList = taskListImpl->create();
            list_top = TaskListInfo::append(list_top, newList);
            list = newList;
        }
        // activeTaskQueue->free_(htask); ここで free しないで、
        // mail を待つ
    }

    mainTaskList = list_top;

    return list_top;
}


void
FifoTaskManagerImpl::run()
{
    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 out_mail_list = NULL;
    if (list) {
	MailQueuePtr list_mail; // task list
	MailQueuePtr sentinel;  // 番兵
	MailQueuePtr in_mail_list = NULL;

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

	// EXIT_COMMAND (番兵的な意味で)
	sentinel  = mailManager->create((memaddr)MY_SPE_COMMAND_EXIT);
	in_mail_list = MailManager::append_mailQueue(in_mail_list, sentinel);

	// scheduler は受け取ったメールを元に実行する
	mainScheduler->send_mailList(in_mail_list);
	mainScheduler->run();
    }
    out_mail_list = mainScheduler->recv_mailList();
#if 0
    if (MailManager::length(out_mail_list )==-1) {
	fprintf(stderr, "Error on mail list\n");
	exit(0);
    }
#endif

    return out_mail_list;
}

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

void
FifoTaskManagerImpl::mail_check(MailQueuePtr mail_list)
{
    MailQueuePtr q = mail_list;
    MailQueuePtr d;
    memaddr data;

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

        if (data == (memaddr)MY_SPE_STATUS_READY) {
            __debug_ppe("mail_check(): Task List finish\n");
        } else if (data == (memaddr)MY_SPE_COMMAND_EXIT) {
            __debug_ppe("mail_check(): Task List finish COMMAND\n");
        } else if (data != (memaddr)MY_SPE_NOP) {
            __debug_ppe("mail_check(): recv from 0x%x\n", data);
	    // post_func を先に実行しないと、systask_finish が active_queue
	    // 移されてから、wait_for されるという事態が起きることがある。
            HTaskPtr task = (HTaskPtr)data;
            task->post_func(schedTaskManager, task->post_arg1, task->post_arg2);
            check_task_finish(task);
        }

        d = q;
        q = q->next;

        mailManager->free(d);
    }
}


/**
 * # # # # # # # # 
 *   Abstract Factory Pattern
 * # # # # # # # 
 */
#ifdef __CERIUM_FIFO__
TaskManagerImpl*
create_impl(int num)
{
    return new FifoTaskManagerImpl();
}
#endif // __CERIUM_FIFO__