Windows版iTRONサービスコールの作成 (タスク管理)
(その8)

タスクをスリープさせる

タスクをスリープさせるサービスコールは以下のとおりです。


サービスコール名説明
slp_tsk

タイムアウトなしでタスクをスリープさせます。

tslp_tsk

タイムアウト付きでタスクをスリープさせます。

※ Ver3.0、Ver4.0共に同じサービスコールの形式です。

タスクをスリープさせる (タイムアウトなし)

タイムアウトなしでスリープさせるには以下のサービスコールを使用します。



    ER slp_tsk( void )
	

戻り値説明
E_OK

正常終了。

E_CTX

非コンテキスト・タスクからの呼び出し。


・サービスコールのソースコードは以下のようになります。


/****************************************************************************/
/*!
 *  @brief  起床待ち (タイムアウトなし).
 *
 *  @param  なし.
 *
 *  @retval エラーコード.
 */
ER      slp_tsk( void )
{
    //! タイムアウトなしでタスクを起床待ちにする.
    return tslp_tsk( TMO_FEVR );
}
	

tslp_tsk()のタイムアウト設定に TMO_FEVR を指定して呼び出します。

wup_tsk()またはiwup_tsk()から起床されるまでタスクをスリープさせます。

タスクをスリープさせる (タイムアウト付き)

タイムアウト付きでスリープさせるには以下のサービスコールを使用します。



    ER tslp_tsk( TMO tmout )
	

引数説明
tmout

タイムアウトの設定値。

  • TMO_FEVRの場合、永久にwup_tsk()を待ちます。
  • その他の正数はタイムアウト値となります。

戻り値説明
E_OK

正常終了。

E_TMOUT

wup_tsk()から起床されずにタイムアウト。

E_CTX

非コンテキスト・タスクからの呼び出し。


・サービスコールのソースコードは以下のようになります。


/****************************************************************************/
/*!
 *  @brief  起床待ち (タイムアウトあり).
 *
 *  @param  [in]    tmout   タイムアウト設定.
 *
 *  @retval エラーコード.
 */
ER      tslp_tsk( TMO tmout )
{
    ER ercd;

    wi_CommonLock();

    //! タスクを起床待ちにする.
    ercd = wi_SleepTask( tmout );

    wi_CommonUnlock();
    return ercd;
}
	

サービスコールを呼び出したタスクをスリープさせます。

wup_tsk()またはiwup_tsk()から起床されるか、タイムアウトで設定した時間が経過するまでタスクをスリープさせます。

タスクをスリープさせる関数

タスクをスリープさせる関数のソースコードは以下のとおりです。



/****************************************************************************/
/*!
 *  @brief  起床待ち.
 *
 *  @param  [in]    tmout   タイムアウト設定.
 *
 *  @retval エラーコード.
 */
ER      wi_SleepTask( TMO tmout )
{
    ER          ercd;
    WITSKOBJ    *p;

    //! 自タスクのタスク・オブジェクトを取得する.
    p = FindTaskObject( TSK_SELF, &ercd );
    if( !p ){
        return E_OBJ;
    }
    if( !p->hThread ){
        return E_OBJ;
    }
    //! 起床要求カウンタが貯まっている場合はイベント待ちをしないで正常終了にする.
    if( p->WakeupCnt > 0 ){
        p->WakeupCnt--;
        return E_OK;
    }
    //! イベント待ちをする.
    return wi_TaskWait( p->Hdr.Id, TTW_SLP, tmout, 0, NULL );
}
	

タスクをスリープさせる関数は以下のような処理を行います。

  • 自タスクのタスク・オブジェクトをリストから取得します。
  • 既にwup_tsk()またはiwup_tsk()が呼び出されて起床要求カウンタが貯まっている場合はイベント待ちをしないで正常終了にします。
  • 起床要求カウンタが 0 の場合は、wup_tsk()またはiwup_tsk()が呼び出されるまで、オブジェクト共通のタスク・スリープ処理()を呼び出してタスクをスリープさせます。

共通のタスク起動処理のソースコードは以下のとおりです。


/****************************************************************************/
/*!
 *  @brief  自タスクをイベント待ちにする.
 *
 *  @param  [in]    wid     待ちオブジェクトのID.
 *  @param  [in]    type    イベント種別.
 *  @param  [in]    tmout   タイムアウト設定.
 *  @param  [in]    pri     オブジェクトの属性.
 *  @param  [out]   que     待ち行列の先頭のタスク・オブジェクトのポインタのポインタ.
 *
 *  @retval エラーコード.
 */
ER      wi_TaskWait( INT wid, INT type, TMO tmout, ATR pri, WIHDR **que )
{
    DWORD       ret_code;
    ER          ercd;
    WITSKOBJ    *tsk;

    //! ポーリングの場合はタイムアウトで終了する.
    if( tmout == TMO_POL ){
        return E_TMOUT;
    }
    //! 自タスクのタスク・オブジェクトを取得する.
    tsk = FindTaskObject( TSK_SELF, &ercd );
    if( !tsk ){
        return E_CTX;
    }
    //! イベント・ハンドルを作成していない場合はエラーにする.
    if( !tsk->hEvent ){
        return E_NOEXS;
    }
    //! 他のオブジェクトがイベント待ちをしている場合は処理を終了にする.
    if( tsk->EventType != 0 ){
        return E_OACV;
    }
    //! イベント・ハンドルを「使用中」にする.
    tsk->EventType = type;
    tsk->WaitId    = wid;
    tsk->QueLink   = NULL;
    tsk->TaskState = TTS_WAI;

    //! タスクを待ち行列に追加する.
    if( que ){
        *que = wi_AddWaitTaskList( TSK_SELF, pri, *que );
    }
    //! ミューテックスを一旦解除する.
    wi_CommonUnlock();

    //! イベントの発生を待つ.
    ret_code = WaitForSingleObject( tsk->hEvent, wi_CvtTimeOutValue( tmout ) );

    //! 再度ミューテックスを掛ける.
    wi_CommonLock();

    //! タスクを待ち行列から削除する.
    if( que ){
        *que = wi_DelWaitTaskList( TSK_SELF, *que );
    }
    //! イベント・ハンドルを「未使用」に戻す.
    tsk->EventType = 0;
    tsk->WaitId    = 0;
    tsk->QueLink   = NULL;
    tsk->TaskState = TTS_RUN;

    switch( ret_code ){
    case WAIT_OBJECT_0:
        if( tsk->DelRes ){
            ercd = E_DLT;
        }else
        if( tsk->RelRes ){
            ercd = E_RLWAI;
        }else{
            ercd = E_OK;
        }
        break;

    case WAIT_TIMEOUT:
        ercd = E_TMOUT;
        break;

    default:
        ercd = E_SYS;
        break;
    }
    tsk->DelRes = FALSE;
    tsk->RelRes = FALSE;
    return ercd;
}
	

共通のタスク・スリープ処理は以下のような処理を行います。

  • タスクをスリープさせるオブジェクトがポーリング方式で呼ばれていた場合はタイムアウトでエラー終了します。
  • 自タスクのタスク・オブジェクトをリストから取得します。
  • 既に他のオブジェクトでタスクがスリープされている場合はエラー終了します。(多分、ないですけど。)
  • スリープするオブジェクト種別とオブジェクトIDをタスク・オブジェクトにセットします。
  • 呼び出し元から待ち行列が指定されている場合、待ち行列にスリープするタスク・オブジェクトを追加します。
  • 呼び出し元でロックしてあるはずのミューテックスを一旦解除します。
  • イベント待ちでタスクをスリープさせます。
  • 一旦解除したミューテックスを再びロックします。
  • 呼び出し元から待ち行列が指定されている場合、待ち行列からスリープしたタスク・オブジェクトを削除します。
  • スリープしたタスク・オブジェクトからオブジェクト種別とオブジェクトIDをクリアします。
  • タスクがイベントを受けて起床した場合、戻り値を以下のようにします。
    1. タスクが削除されるときに起床した場合、戻り値は『E_DLT(タスクの削除)』にします。
    2. rel_wai() または irel_wai() によっていタスクが起床した場合、戻り値は『E_RLWAI(タスクの待ち状態の強制解除)』にします。
    3. その他の場合、戻り値は『E_OK(正常終了)』にします。
  • タスクがタイムアウトで起床した場合、戻り値は『E_TMOUT(タイムアウト)』にします。
  • その他の要因で起床した場合、戻り値は『E_SYS(システムエラー)』にします。



Windowsは米国Microsoft Corporationの登録商標です。