/*
 *  TOPPERS/JSP Kernel
 *      Toyohashi Open Platform for Embedded Real-Time Systems/
 *      Just Standard Profile Kernel
 * 
 *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
 *                              Toyohashi Univ. of Technology, JAPAN
 * 
 *  上記著作権者は，以下の (1)〜(4) の条件か，Free Software Foundation 
 *  によって公表されている GNU General Public License の Version 2 に記
 *  述されている条件を満たす場合に限り，本ソフトウェア（本ソフトウェア
 *  を改変したものを含む．以下同じ）を使用・複製・改変・再配布（以下，
 *  利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，その適用可能性も
 *  含めて，いかなる保証も行わない．また，本ソフトウェアの利用により直
 *  接的または間接的に生じたいかなる損害に関しても，その責任を負わない．
 * 
 *  @(#) $Id: wait.c,v 1.1 2009/01/31 05:27:37 suikan Exp $
 */

/*
 *  待ち状態管理モジュール
 */

#include "jsp_kernel.h"
#include "wait.h"

/*
 *  待ち状態への移行（タイムアウト指定）
 *
 */
#ifdef __waimake

void
make_wait_tmout(WINFO *winfo, TMEVTB *tmevtb, TMO tmout)
{
    make_non_runnable(runtsk);
    runtsk->winfo = winfo;
    if (tmout > 0) {
        winfo->tmevtb = tmevtb;
        tmevtb_enqueue(tmevtb, (RELTIM) tmout,
                    (CBACK) wait_tmout, (VP) runtsk);
    }
    else {
        assert(tmout == TMO_FEVR);
        winfo->tmevtb = NULL;
    }
}

#endif /* __waimake */

/*
 *  待ち解除のためのタスク状態の更新
 *
 *  tcb で指定されるタスクを，待ち解除するようタスク状態を更新する．待
 *  ち解除するタスクが実行できる状態になる場合は，レディキューにつなぐ．
 *  また，ディスパッチが必要な場合には TRUE を返す．
 */
Inline BOOL
make_non_wait(TCB *tcb)
{
    assert(TSTAT_WAITING(tcb->tstat));

    if (!(TSTAT_SUSPENDED(tcb->tstat))) {
        /*
         *  待ち状態から実行できる状態への遷移
         */
        return(make_runnable(tcb));
    }
    else {
        /*
         *  二重待ち状態から強制待ち状態への遷移
         */
        tcb->tstat = TS_SUSPENDED;
        LOG_TSKSTAT(tcb);
        return(FALSE);
    }
}

/*
 *  待ち解除
 */
#ifdef __waicmp

BOOL
wait_complete(TCB *tcb)
{
    if (tcb->winfo->tmevtb != NULL) {
        tmevtb_dequeue(tcb->winfo->tmevtb);
    }
    tcb->winfo->wercd = E_OK;
    return(make_non_wait(tcb));
}

#endif /* __waicmp */

/*
 *  タイムアウトに伴う待ち解除
 */
#ifdef __waitmo

void
wait_tmout(TCB *tcb)
{
    if ((tcb->tstat & TS_WAIT_WOBJ) != 0) {
        queue_delete(&(tcb->task_queue));
    }
    tcb->winfo->wercd = E_TMOUT;
    if (make_non_wait(tcb)) {
        reqflg = TRUE;
    }
}

#endif /* __waitmo */
#ifdef __waitmook

void
wait_tmout_ok(TCB *tcb)
{
    tcb->winfo->wercd = E_OK;
    if (make_non_wait(tcb)) {
        reqflg = TRUE;
    }
}

#endif /* __waitmook */

/*
 *  待ち状態の強制解除
 */
#ifdef __waican

void
wait_cancel(TCB *tcb)
{
    if (tcb->winfo->tmevtb != NULL) {
        tmevtb_dequeue(tcb->winfo->tmevtb);
    }
    if ((tcb->tstat & TS_WAIT_WOBJ) != 0) {
        queue_delete(&(tcb->task_queue));
    }
}

#endif /* __waican */
#ifdef __wairel

BOOL
wait_release(TCB *tcb)
{
    wait_cancel(tcb);
    tcb->winfo->wercd = E_RLWAI;
    return(make_non_wait(tcb));
}

#endif /* __wairel */

/*
 *  タスクの優先度順の待ちキューへの挿入
 */
Inline void
queue_insert_tpri(TCB *tcb, QUEUE *queue)
{
    QUEUE   *entry;
    UINT    priority = tcb->priority;

    for (entry = queue->next; entry != queue; entry = entry->next) {
        if (priority < ((TCB *) entry)->priority) {
            break;
        }
    }
    queue_insert_prev(entry, &(tcb->task_queue));
}

/*
 *  実行中のタスクの同期・通信オブジェクトの待ちキューへの挿入
 */
Inline void
wobj_queue_insert(WOBJCB *wobjcb)
{
    if ((wobjcb->wobjinib->wobjatr & TA_TPRI) != 0) {
        queue_insert_tpri(runtsk, &(wobjcb->wait_queue));
    }
    else {
        queue_insert_prev(&(wobjcb->wait_queue),
                    &(runtsk->task_queue));
    }
}

/*
 *  同期・通信オブジェクトに対する待ち状態への移行
 */
#ifdef __wobjwai

void
wobj_make_wait(WOBJCB *wobjcb, WINFO_WOBJ *winfo)
{
    runtsk->tstat = (TS_WAITING | TS_WAIT_WOBJ | TS_WAIT_WOBJCB);
    make_wait(&(winfo->winfo));
    wobj_queue_insert(wobjcb);
    winfo->wobjcb = wobjcb;
    LOG_TSKSTAT(runtsk);
}

#endif /* __wobjwai */
#ifdef __wobjwaitmo

void
wobj_make_wait_tmout(WOBJCB *wobjcb, WINFO_WOBJ *winfo,
                    TMEVTB *tmevtb, TMO tmout)
{
    runtsk->tstat = (TS_WAITING | TS_WAIT_WOBJ | TS_WAIT_WOBJCB);
    make_wait_tmout(&(winfo->winfo), tmevtb, tmout);
    wobj_queue_insert(wobjcb);
    winfo->wobjcb = wobjcb;
    LOG_TSKSTAT(runtsk);
}

#endif /* __wobjwaitmo */
/*
 *  タスクの優先度変更時の処理
 */
#ifdef __wobjpri

void
wobj_change_priority(WOBJCB *wobjcb, TCB *tcb)
{
    if ((wobjcb->wobjinib->wobjatr & TA_TPRI) != 0) {
        queue_delete(&(tcb->task_queue));
        queue_insert_tpri(tcb, &(wobjcb->wait_queue));
    }
}

#endif /* __wobjpri */
