view TaskManager/kernel/schedule/Scheduler.cc @ 603:42c94f85c779

long -> memaddr (64 or 32)
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 07 Nov 2009 14:13:29 +0900
parents 1733f3cbfa28
children 0decff4e867b
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include "Scheduler.h"
#include "SchedNop.h"
#include "error.h"
#include <assert.h>

/*
 * Edit kernel/schedule/xx.cc, Cell/spe/xx.cc will be over writen by this.
 * Do not edit Cell/spe/xx.cc unless there is no kernel/schedule/xx.cc files.
 */

Scheduler::TaskObject task_list[MAX_TASK_OBJECT];

Scheduler::~Scheduler()
{
    delete connector;
}

/*! @brief speTaskの入出力のパイプラインバッファを確保する
 */

void
Scheduler::init()
{
    hash = 0;
    init_impl();

    for (int i = 0; i < 2; i++) {
        buff_taskList[i]    = (TaskListPtr)allocate(sizeof(TaskList));
        // buff_inListData[i]  = (ListDataPtr)allocate(sizeof(ListData));
        // buff_outListData[i] = (ListDataPtr)allocate(sizeof(ListData));
    }

    buffFlag_taskList = 0;
    // buffFlag_inListData = 0;
    // buffFlag_outListData = 0;
    flag_renewTaskList = 0;

    // bzero でもいいけど
    for (int i = 0; i < MAX_GLOBAL_AREA; i++) {
        globalList[i] = NULL;
    }

    for (int i = 0; i < MAX_MAINMEM_AREA; i++) {
        mainMemList[i] = NULL;
    }


    taskGroup = new TaskGroup;
    renewTop_taskList = NULL;
    renewCur_taskList = NULL;
    bak_curTaskList = NULL;
}

void
Scheduler::run()
{
    task1 = new SchedNop();
    task2 = new SchedNop();
    task3 = new SchedNop();

    // main loop
    do {
        __debug("----------\n");
        task3->write();
        task2->exec();
        task1->read();
	delete task3; 

        task3 = task2;
        task2 = task1;
        task1 = task1->next(this, 0);
    } while (task1);

    delete task3;
    delete task2;
}


void
Scheduler::finish()
{
    free(buff_taskList[0]);
    free(buff_taskList[1]);
    // free(buff_inListData[0]);
    // free(buff_inListData[1]);
    // free(buff_outListData[0]);
    // free(buff_outListData[1]);
}

/**
 * あらかじめ memory allocte してある TaskList の領域を
 * パイプラインの各処理が交代して使う。
 */
TaskListPtr
Scheduler::get_curListBuf()
{
    buffFlag_taskList ^= 1;

    return buff_taskList[buffFlag_taskList];
}


/**
 * Task に inListData, outListData を入れたので、
 * これは必要ないらしい。
 *
 * あらかじめ memory allocte してある ListData の領域を
 * パイプラインの各処理が交代して使う。
 */
#if 0
ListDataPtr
Scheduler::get_curWriteBuf()
{
    buffFlag_outListData ^= 1;
    return buff_outListData[buffFlag_outListData];
}


ListDataPtr
Scheduler::get_curReadBuf()
{
    buffFlag_inListData ^= 1;
    return buff_inListData[buffFlag_inListData];
}
#endif

/**
 * タスク内で生成されたタスクを格納する TaskList を取得する
 * 現在格納に使っている TaskList (renewCur_taskList) が使えるならそれを返す
 * もしそうでないなら、新しく TaskList を allocate してそれを返す
 * コード中で renewCur_taskList が NULL になるのは
 *   - プログラム開始時
 *   - タスク内生成タスクがある TaskList の実行を新しく始める (Nop2Ready 参照)
 * 以上の場合です
 */
TaskListPtr
Scheduler::get_renewListBuf()
{
    if (renewCur_taskList && renewCur_taskList->length < TASK_MAX_SIZE) {
        return renewCur_taskList;
    } else {
        TaskListPtr newList = (TaskListPtr)allocate(sizeof(TaskList));
        newList->length = 0;
        newList->next = NULL;
        renewTop_taskList = TaskList::append(renewTop_taskList, newList);
        renewCur_taskList = newList;
        return newList;
    }
}

/**
 * 次に実行する Renew Task List を返す
 *
 * @param[in] curList 現在実行中の TaskList
 *                    中断して RenewTaskList を行うため
 *                    バックアップを取っておく
 * @return next RenewTaskList
 */
SchedTaskList*
Scheduler::get_nextRenewTaskList()
{
    if (renewTop_taskList) {
        TaskListPtr list  = renewTop_taskList;
        renewTop_taskList = renewTop_taskList->next;
        renewCur_taskList = NULL;

        list->next = NULL;
        SchedTaskList *sched
            = createSchedTaskList((memaddr)list, this, SCHED_TASKLIST_RENEW);
        return sched;
    } else {
        return NULL;
    }
}

void
Scheduler::set_backupTaskList(TaskListPtr cur_taskList)
{
    bak_curTaskList = cur_taskList;
}

void
Scheduler::set_backupTaskListIndex(int cur_index)
{
    bakIndex_taskList = cur_index;
}

/**
 * RenewTaskList 実行前に中断した TaskList を返す
 * NULL の場合、中断した TaskList は無い。
 *
 * @return TaskList
 */
TaskListPtr
Scheduler::get_backupTaskList()
{
    TaskListPtr ret = bak_curTaskList;

    bak_curTaskList = NULL;
    return ret;
}

int
Scheduler::get_backupTaskListIndex()
{
    int ret = bakIndex_taskList;

    bakIndex_taskList = 0;
    return ret;
}

void
Scheduler::dma_load(void *buf, uint32 addr, uint32 size, uint32 mask)
{
    connector->dma_load(buf, addr, size, mask);
}

void
Scheduler::dma_store(void *buf, uint32 addr, uint32 size, uint32 mask)
{
    connector->dma_store(buf, addr, size, mask);
}

void
Scheduler::dma_wait(uint32 mask)
{
    connector->dma_wait(mask);
}

void
Scheduler::dma_loadList(ListDataPtr list, void *buff, uint32 mask)
{
    connector->dma_loadList(list, buff, mask);
}


void
Scheduler::dma_storeList(ListDataPtr list, void *buff, uint32 mask)
{
    return connector->dma_storeList(list, buff, mask);
}

void
Scheduler::mail_write(uint32 data)
{
    connector->mail_write(data);
}

uint32
Scheduler::mail_read()
{
    return connector->mail_read();
}

TaskGroupPtr
Scheduler::set_groupTask(uint32 command)
{
    TaskGroupPtr ret = taskGroup;

    reload_groupTask();

    ret->command = command;
    return ret;
}

void
Scheduler::add_groupTask(TaskGroupPtr group, TaskPtr task)
{
    group->add(task);
}

void
Scheduler::remove_groupTask(TaskGroupPtr group, TaskPtr task)
{
    group->remove(task);
}

void
Scheduler::reload_groupTask()
{
    taskGroup = new TaskGroup;
}

uint32
Scheduler::status_groupTask(TaskGroupPtr group)
{
    return group->status();
}

/*
    ここから下は、memory 以下にあるべき
 */

void*
Scheduler::global_alloc(int id, int size)
{
    globalList[id] = allocate(size);
    return globalList[id];
}

void*
Scheduler::global_get(int id)
{
    return globalList[id];
}

void
Scheduler::global_set(int id, void *addr)
{
    globalList[id] = addr;
}

void
Scheduler::global_free(int id)
{
    free(globalList[id]);
    globalList[id] = NULL;
}

/**
 * mainMem_alloc で確保したメインメモリの領域アドレスを返す。
 * これは Fifo, Cell で共通
 */
void*
Scheduler::mainMem_get(int id)
{
    return mainMemList[id];
}

/** 
 *  Task load API
 */
void
Scheduler::allocate_code_segment(int size, int count)
{
    // 既に overlay 領域があるので、それを追加する必要がある...
    code_segment_pool = createMemList(size, count);
}

static void
load_task(Scheduler *m, int task_id)
{
    MemorySegment *s = m->get_segment(
	task_list[task_id].location, 
	m->code_segment_pool, 
	task_list[task_id].end-task_list[task_id].location);
    task_list[task_id].segment = s;
#if 0
    fprintf(stderr,"loadng task id %d at 0x%x entry 0x%x\n",task_id,
	    (unsigned int)(task_list[task_id].segment->data ),
	    (unsigned int)(
            (char*)task_list[task_id].segment->data +
            task_list[task_id].entry_offset));
#endif
}

static void
null_loader(Scheduler *m, int task_id)
{
}

static void
wait_load(Scheduler *m, int task_id)
{
#if 0
    MemorySegment *s = task_list[task_id].segment;
    if (s)
	fprintf(stderr,"wait load task id %d 0x%x\n",task_id,(int)s->data);
    else
	fprintf(stderr,"wait load task id %d 000000\n",task_id);
#endif
    // wait for code segment load
    m->wait_segment(task_list[task_id].segment);
    // calcurate call address
    TaskObjectRun run = 
        (TaskObjectRun)(
            (char*)task_list[task_id].segment->data +
            task_list[task_id].entry_offset);
    task_list[task_id].run = run;
#if 0
    fprintf(stderr,"wait load task id %d done. creator = 0x%x entry_offset = 0x%x\n",task_id,
	(unsigned int)run,
            task_list[task_id].entry_offset);
#endif
}

static void
null_waiter(Scheduler *m, int task_id)
{
}

extern void 
register_task(int cmd, TaskObjectRun run)
{
    task_list[cmd].run = run;
    task_list[cmd].load = null_loader;
    task_list[cmd].wait = null_waiter;
}

extern void 
register_dynamic_task(int cmd, 
    memaddr start, int size,
    TaskObjectRun run, int entry_offset)
{
    task_list[cmd].run = run;
    task_list[cmd].location = start;
    size &= 0xfffffffe;
    task_list[cmd].end = start+size;
    task_list[cmd].entry_offset = entry_offset;
    task_list[cmd].load = load_task;
    task_list[cmd].wait = wait_load;
#if 0
fprintf(stderr,"cmd        = %d\n",cmd);
fprintf(stderr,"locatation = 0x%x\n",start);
fprintf(stderr,"end        = 0x%x\n",start+size);
fprintf(stderr,"size       = 0x%x\n",size);
fprintf(stderr,"entry      = 0x%x\n",entry_offset);
#endif

}


/*!

  size 単位のMemory Segment を count 個作る

  @param [size] リストの要素1つのサイズ
  @param [count] 要素数
  @return allocate した領域のポインタ

 */
MemList*
Scheduler::createMemList(int size, int count)
{
    uint32 head_size = round_up16(sizeof(MemorySegment));
    uint32 seg_size = round_up16(head_size+size);
    char* mseg = (char*)allocate(seg_size*count);
    MemList* mlist = new MemList((MemorySegment*)mseg);

    if (!hash) {
	hash = new MemHash();
    }

    for(int i = 0; i < count; i++) {
        MemorySegment* next = (MemorySegment*)(mseg+seg_size*i);
        char* data = (char*)next+head_size;
        next->data = (void*)data;
        next->size = size;
	next->address = (memaddr)next;
        mlist->addLast(next);
    }

    return mlist;
}

/*!

    Main Memory のSegmentを取得する

  @param [addr] Main Memory のアドレス
  @param [m]    Mem List
  @return allocate した領域のポインタ
    memory directory にあるべきだが...

 */
MemorySegment * 
Scheduler::get_segment(memaddr addr, MemList *m) 
{
    MemorySegment *s = m->getFirst();
    return get_segment(addr, m, s->size); 
}

MemorySegment * 
Scheduler::get_segment(memaddr addr, MemList *m, int size) 
{
    // memory segment のsizeをoverride する場合がある
    MemorySegment *s = hash->get(addr);
    if (s) {
	/* 既に load されている */
// fprintf(stderr,"get_segement loaded %llx 0x%x size 0x%d\n",addr,s->data,size);
	m->moveToFirst(s);
	return s;
    }
   
    /* LRU なので、もっとも使われてない segment を上書きする */ 
    s = m->getLast();
    m->moveToFirst(s);

    memaddr old_addr = s->address;
    s->tag = get_tag();
    dma_load(s->data, addr,
                       size, s->tag);
    /* 前のをhashから削除 */
    hash->remove(old_addr);
    /* 新しいaddress を登録 */
    s->address = addr;
    hash->put(s->address, s);

// fprintf(stderr,"get_segement %llx 0x%x size 0x%d\n",addr, s->data,size);

    return s;
}


uint32
Scheduler::get_tag()
{
    static int tag = 16;
    tag ++;
    tag &= 0x0f;
    return tag+16;
}

/*!

    Main Memory のSegmentを書き出す
    Segment は get_segement されていて、
    追い出されていてはいけない。
       それを保証するのは難しい?

  @param [addr] Main Memory のアドレス
  @param [m]    Mem List
  @return allocate した領域のポインタ

 */
void
Scheduler::put_segment(MemorySegment *s)
{
    dma_store(s->data, s->address,
                       s->size, s->tag);
}

/*!

    Main Memory のSegmentを読込、書き出しを待つ

  @param [id]    MemorySegment のid

 */
void
Scheduler::wait_segment(MemorySegment *s)
{
    // えーと、dma してない時には、skip しないとだめなんじゃないの?

    if (s->tag) dma_wait(s->tag);
    s->tag = 0;
}

/* end */