Windows版iTRONサービスコールの作成 (可変長メモリプール)
(その5)

メモリブロックを返却する

可変長メモリプールへメモリブロックを返却するサービスコールは以下のとおりです。


サービスコール名説明
rel_blk

可変長メモリプールへメモリブロックを返却します。

可変長メモリプールへメモリブロックを返却する

可変長メモリプールへメモリブロックを返却するには以下のサービスコールを使用します。



    ER rel_blk( ID mplid, VP blk )
	

引数説明
mplid

メモリプールID番号。

blk

返却するメモリブロックのポインタ。

戻り値説明
E_OK

正常終了。

E_ID

範囲外のメモリプールID番号。

E_NOEXS

指定したメモリプールID番号は登録されていない。

E_PAR

引数 blk が不正な値。


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


/****************************************************************************/
/*!
 *  @brief  可変長メモリブロックの返却.
 *
 *  @param  [in]    mplid   メモリプールID番号.
 *  @param  [in]    blk     返却するメモリブロックのアドレス.
 *
 *  @retval エラーコード.
 */
ER      rel_blk( ID mplid, VP blk )
{
    ER ercd;

    wi_CommonLock();

    //! 可変長メモリブロックを返却する.
    ercd = wi_ReleaseVarMemPool( mplid, blk );

    wi_CommonUnlock();
    return ercd;
}
	

指定したメモリプールID番号を引数としてメモリブロックの返却関数を呼び出します。

メモリブロックの返却関数

可変長メモリプールへメモリブロックを返却する関数のソースコードは以下のとおりです。



/****************************************************************************/
/*!
 *  @brief  可変長メモリ・ブロックの返却.
 *
 *  @param  [in]    id      メモリプールID番号.
 *  @param  [in]    adr     返却するメモリ・ブロックのアドレス.
 *
 *  @retval エラーコード.
 */
ER      wi_ReleaseVarMemPool( INT id, VP adr )
{
    ER          ercd;
    WIMPLOBJ    *p;

    //! メモリプールIDのオブジェクトを取得する.
    p = (WIMPLOBJ *)wi_FindObject( id, TMAX_MAXMPL, ObjList, &ercd );
    if( !p ){
        return ercd;
    }
    //! 引数が不正な場合はエラーにする.
    if( !adr ){
        return E_PAR;
    }
    //! 返却されたメモリブロックを解放する.
    if( !FreeVarMem( (BYTE*)adr, p->MemBuf, p->MemSize ) ){
        return E_PAR;
    }
    //! メモリブロック獲得待ちのタスクがある場合、メモリを確保する.
    MemAllocWaitTask( p );
    return E_OK;
}
	

可変長メモリプールへメモリブロックを返却する関数は以下のような処理を行います。

  • 引数で指定された可変長メモリプールID番号に該当する可変長メモリプール・オブジェクトを取り出します。
  • 返却されるメモリブロックのポインタがNULLに場合はエラー終了にします。
  • 返却されるメモリブロックのヘッダ情報を消去して、メモリバッファ上のメモリブロックを解放します。
  • メモリブロックの返却待ちをしているタスクがある場合、待ち行列の先頭のタスクを起床させます。

返却されたメモリブロックを解放する処理は以下のようになります。


/****************************************************************************/
/*!
 *  @brief  メモリブロックを返却して空きブロックにする.
 *
 *  @param  [in]    adr         返却するメモリブロックのポインタ.
 *  @param  [in]    buf         メモリバッファのポインタ.
 *  @param  [in]    max_size    メモリバッファのサイズ.
 *
 *  @retval TRUE = OK. / FALSE = NG.
 */
static BOOL     FreeVarMem( BYTE* adr, BYTE* buf, INT max_size )
{
    MEMHDR  *hdr1,*hdr2,*hdr3;
    INT     i,j,pos;

    //! 返却するメモリブロックのメモリバッファ上の位置を計算する.
    pos = ((INT)adr - (INT)buf) - (INT)sizeof(MEMHDR);

    //! 返却するメモリブロックがメモリバッファの範囲外の場合はエラーにする.
    if( pos < 0 || pos >= (max_size - (INT)sizeof(MEMHDR)) ){
        return FALSE;
    }
    //! メモリブロックの先頭からリンクを辿って、返却するメモリブロックを探す.
    hdr1 = NULL;
    for( i = 0; i < max_size && i <= pos; ){

        //! バッファからメモリブロックのヘッダを取り出す.
        hdr2 = (MEMHDR *)(&buf[i]);

        //! メモリブロックのバイト数が 0 の場合、メモリバッファが壊されているので処理を中断する.
        if( hdr2->Size == 0 ){
            break;
        }
        if( i == pos ){
            //! 返却するブロックが空きブロックの場合はエラーにする.
            if( hdr2->TaskId == 0 ){
                break;
            }
            //! メモリブロックを空きブロックにする.
            hdr2->TaskId = 0;

            /*!
             * 次のブロックが空きブロックの場合、返却したブロックと結合して
             * 次のブロックを消滅させる.
             */
            j = i + hdr2->Size;
            if( j < (max_size - (INT)sizeof(MEMHDR)) ){
                hdr3 = (MEMHDR *)(&buf[j]);
                if( hdr3->TaskId == 0 ){
                    hdr2->Size += hdr3->Size;
                }
            }
            /*!
             * 1つ手前のブロックが空きブロックの場合、返却したブロックと結合して
             * 返却したブロックを消滅させる.
             */
            if( hdr1 && hdr1->TaskId == 0 ){
                hdr1->Size += hdr2->Size;
            }
            return TRUE;
        }
        //! 次のメモリブロックを取り出す.
        i += hdr2->Size;

        //! 1つ手前のメモリブロックのヘッダ位置を更新する.
        hdr1 = hdr2;
    }
    return FALSE;
}
	


メモリブロックが解放されるのを待っているタスクがある場合、解放されたメモリブロックを再度取得します。


/****************************************************************************/
/*!
 *  @brief  メモリブロック獲得待ちをしているタスクにメモリを貸し出す.
 *
 *  @param  [in]    mpl         可変長メモリプール・オブジェクトのポインタ.
 *
 *  @retval なし.
 */
static void     MemAllocWaitTask( WIMPLOBJ *mpl )
{
    WITSKOBJ *tsk;

    tsk = (WITSKOBJ *)mpl->WaitQue;
    while( tsk ){
        //! 指定されたサイズの空きメモリを確保する.
        tsk->Param[1] = AllocVerMem( (INT)(tsk->Param[0]), mpl->MemBuf, mpl->MemSize, tsk->Hdr.Id );
        if( !tsk->Param[1] ){
            break;
        }
        //! スリープしているタスクを起床させる.
        wi_TaskWakeup( tsk->Hdr.Id, TTW_MPL, NULL );

        //! 待ち行列から次のタスクを取り出す.
        tsk = tsk->QueLink;
    }
}
	



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