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

メモリブロックの取得する

可変長メモリプールからメモリブロックの取得するサービスコールは以下のとおりです。


サービスコール名説明
get_mpl

タイムアウトなしで可変長メモリプールからメモリブロックの取得します。

pget_blf

ポーリング方式で可変長メモリプールからメモリブロックの取得します。

tget_blf

タイムアウト付きで可変長メモリプールからメモリブロックの取得します。

※ Ver3.0と4.0では関数名は同じですが、引数の順番が逆になりますので注意してください。

可変長メモリプールからメモリブロックの取得する (タイムアウトなし)

タイムアウトなしで可変長メモリプールからメモリブロックの取得するには以下のサービスコールを使用します。


・Ver3.0の場合


    ER get_blk( VP p_blk, ID mplid, INT blksz )
	

・Ver4.0の場合


    ER get_mpl( ID mplid, UINT blksz, VP *p_blk )
	

引数説明
p_blk

メモリブロックのポインタを格納する領域のポインタ。

mplid

メモリプールID番号。

blksz

確保するメモリブロックのバイト数。

戻り値説明
E_OK

正常終了。

E_ID

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

E_NOEXS

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

E_PAR

引数 p_blk または blksz が不正な値。

E_CTX

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


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


/****************************************************************************/
/*!
 *  @brief  可変長メモリブロックの獲得 (タイムアウトなし).
 *
 *  @param  [in]    p_blk   メモリブロックのアドレスを格納する領域のポインタ.
 *  @param  [in]    mplid   メモリプールID番号.
 *  @param  [in]    blksz   メモリブロックのサイズ.
 *
 *  @retval エラーコード.
 */
ER      get_blk( VP p_blk, ID mplid, INT blksz )
{
    //! タイムアウトなしで可変長メモリブロックを獲得する.
    return tget_blk( p_blk, mplid, blksz, TMO_FEVR );
}
	

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


/****************************************************************************/
/*!
 *  @brief  可変長メモリブロックの獲得 (タイムアウトなし).
 *
 *  @param  [in]    mplid   メモリプールID番号.
 *  @param  [in]    blksz   メモリブロックのサイズ.
 *  @param  [in]    p_blk   メモリブロックのアドレスを格納する領域のポインタ.
 *
 *  @retval エラーコード.
 */
ER      get_mpl( ID mplid, UINT blksz, VP *p_blk )
{
    //! タイムアウトなしで可変長メモリブロックを獲得する.
    return tget_mpl( mplid, blksz, p_blk, TMO_FEVR );
}
	

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

指定したサイズ分の連続した未使用のメモリブロックが無い場合は、メモリブロックが解放されるまでタスクをスリープさせます。

可変長メモリプールからメモリブロックを取得する (ポーリング)

ポーリングで可変長メモリプールからメモリブロックを取得するには以下のサービスコールを使用します。


・Ver3.0の場合


    ER pget_blk( VP p_blk, ID mplid, INT blksz )
	

・Ver4.0の場合


    ER pget_mpl( ID mplid, UINT blksz, VP *p_blk )
	

引数説明
p_blk

メモリブロックのポインタを格納する領域のポインタ。

mplid

メモリプールID番号。

blksz

確保するメモリブロックのバイト数。

戻り値説明
E_OK

正常終了。

E_ID

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

E_NOEXS

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

E_PAR

引数 p_blk または blksz が不正な値。

E_TMOUT

未使用のメモリブロックが無い。


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


/****************************************************************************/
/*!
 *  @brief  可変長メモリブロックの獲得 (ポーリング).
 *
 *  @param  [in]    p_blk   メモリブロックのアドレスを格納する領域のポインタ.
 *  @param  [in]    mplid   メモリプールID番号.
 *  @param  [in]    blksz   メモリブロックのサイズ.
 *
 *  @retval エラーコード.
 */
ER      pget_blk( VP p_blk, ID mplid, INT blksz )
{
    //! 獲得待ちなしで可変長メモリブロックを獲得する.
    return tget_blk( p_blk, mplid, blksz, TMO_POL );
}
	

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


/****************************************************************************/
/*!
 *  @brief  可変長メモリブロックの獲得 (ポーリング).
 *
 *  @param  [in]    mplid   メモリプールID番号.
 *  @param  [in]    blksz   メモリブロックのサイズ.
 *  @param  [in]    p_blk   メモリブロックのアドレスを格納する領域のポインタ.
 *
 *  @retval エラーコード.
 */
ER      pget_mpl( ID mplid, UINT blksz, VP *p_blk )
{
    //! 獲得待ちなしで可変長メモリブロックを獲得する.
    return tget_mpl( mplid, blksz, p_blk, TMO_POL );
}
	

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

指定したサイズ分の連続した未使用のメモリブロックが無い場合は、タスクをスリープさせずに戻り値をE_TMOUTとしてすぐにサービスコールから戻ります。

可変長メモリプールからメモリブロックを取得する (タイムアウト付き)

タイムアウト付きで可変長メモリプールからメモリブロックを取得するには以下のサービスコールを使用します。


・Ver3.0の場合


    ER tget_blk( VP p_blk, ID mplid, INT blksz, TMO tmout )
	

・Ver4.0の場合


    ER tget_blf(ID mpfid, VP *p_blf, TMO tmout )
	

引数説明
p_blf

メモリブロックのポインタを格納する領域のポインタ。

mpfid

メモリプールID番号。

tmout

タイムアウトの設定値。

  • TMO_FEVRの場合、永久にメモリブロックが解放されるのを待ちます。
  • TMO_POLの場合、メモリブロックが取得できなくてもタスクをスリープしません。
  • その他の正数はタイムアウト値となります。

戻り値説明
E_OK

正常終了。

E_ID

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

E_NOEXS

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

E_PAR

引数 p_blk または blksz が不正な値。

E_TMOUT

メモリブロックが取得できずにタイムアウト。

E_CTX

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


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


/****************************************************************************/
/*!
 *  @brief  可変長メモリブロックの獲得 (タイムアウトあり).
 *
 *  @param  [in]    p_blk   メモリブロックのアドレスを格納する領域のポインタ.
 *  @param  [in]    mplid   メモリプールID番号.
 *  @param  [in]    blksz   メモリブロックのサイズ.
 *  @param  [in]    tmout   タイムアウト設定.
 *
 *  @retval エラーコード.
 */
ER      tget_blk( VP p_blk, ID mplid, INT blksz,  TMO tmout )
{
    ER ercd;

    wi_CommonLock();

    //! 可変長メモリブロックを獲得する.
    ercd = wi_GetVarMemPool( mplid, p_blk, blksz, tmout );

    wi_CommonUnlock();
    return ercd;
}
	

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


/****************************************************************************/
/*!
 *  @brief  可変長メモリブロックの獲得 (タイムアウトあり).
 *
 *  @param  [in]    mplid   メモリプールID番号.
 *  @param  [in]    blksz   メモリブロックのサイズ.
 *  @param  [in]    p_blk   メモリブロックのアドレスを格納する領域のポインタ.
 *  @param  [in]    tmout   タイムアウト設定.
 *
 *  @retval エラーコード.
 */
ER      tget_mpl( ID mplid, UINT blksz, VP *p_blk, TMO tmout )
{
    ER ercd;

    wi_CommonLock();

    //! 可変長メモリブロックを獲得する.
    ercd = wi_GetVarMemPool( mplid, p_blk, blksz, tmout );

    wi_CommonUnlock();
    return ercd;
}
	

可変長メモリープールから未使用のメモリブロックを取得する関数を呼び出します。

メモリブロックが取得できない場合は、メモリブロックが解放されるか、タイムアウトで設定した時間が経過するまでタスクをスリープさせます。

未使用のメモリブロックを取得する関数

可変長メモリープールから未使用のメモリブロックを取得する関数のソースコードは以下のとおりです。



/****************************************************************************/
/*!
 *  @brief  可変長メモリ・ブロックの獲得.
 *
 *  @param  [in]    id      メモリプールID番号.
 *  @param  [in]    adr     メモリブロックのアドレスを格納する領域のポインタ.
 *  @param  [in]    size    メモリブロックのサイズ.
 *  @param  [in]    tmout   タイムアウト設定.
 *
 *  @retval エラーコード.
 */
ER      wi_GetVarMemPool( INT id, VP adr, INT size, TMO tmout )
{
    ER          ercd;
    WITSKOBJ    *tsk;
    WIMPLOBJ    *p;
    BYTE        *blk;

    //! メモリプールIDのオブジェクトを取得する.
    p = (WIMPLOBJ *)wi_FindObject( id, TMAX_MAXMPL, ObjList, &ercd );
    if( !p ){
        return ercd;
    }
    //! 引数が不正な場合はエラーにする.
    if( !adr || size <= 0 || size > (INT)(p->MemSize - sizeof(MEMHDR)) ){
        return E_PAR;
    }
    *((BYTE **)adr) = NULL;

    //! タスク以外からの呼び出しの場合はエラーにする.
    tsk = wi_GetTaskObject( TSK_SELF );
    if( !tsk ){
        return E_CTX;
    }
    //! 指定されたサイズの空きメモリを確保する.
    blk = AllocVerMem( size, p->MemBuf, p->MemSize, tsk->Hdr.Id );

    //! メモリが確保できない場合.
    if( !blk ){
        //! 必要なメモリサイズをタスク・オブジェクトにセットする.
        tsk->Param[0] = (VP)size;
        tsk->Param[1] = NULL;

        //! メモリブロックが返却されるまでタスクをスリープさせる.
        ercd = wi_TaskWait( id, TTW_MPL, tmout, p->Attribute, &(p->WaitQue) );

        //! エラー検出と同時にメモリの確保が出来てしまった場合、メモリは返却する.
        if( ercd != E_OK ){
            if( tsk->Param[1] ){
                FreeVarMem( tsk->Param[1], p->MemBuf, p->MemSize );
            }
            return ercd;
        }
        //! メモリブロックの返却処理で確保したメモリブロックのアドレスを取り出す.
        blk = (BYTE *)(tsk->Param[1]);
    }
    //! 貸し出すメモリのアドレスを戻り値に格納する.
    *((BYTE **)adr) = blk;
    return E_OK;
}
	

未使用のメモリブロックを取得する関数は以下のような処理を行います。

  • 引数で指定された可変長メモリプールID番号に該当する可変長メモリプール・オブジェクトを取り出します。
  • 非タスクコンテキストから呼び出された場合はエラー終了します。
  • 引数で指定されたサイズ分の連続した未使用のメモリブロックがない場合、メモリブロックが解放されるか、タイムアウトになるまでタスクをスリープさせます。
  • 引数で指定されたサイズ分の連続した未使用のメモリブロックをメモリバッファから確保します。

メモリブロックを取得する処理は以下のようになります。


/****************************************************************************/
/*!
 *  @brief  指定したサイズのメモリブロックを取得する.
 *
 *  @param  [in]    len         取得するメモリブロックのサイズ.
 *  @param  [in]    buf         メモリバッファのポインタ.
 *  @param  [in]    max_size    メモリバッファのサイズ.
 *  @param  [in]    tskid       メモリを取得するタスクのID.
 *
 *  @retval 取得したメモリブロックのポインタ.
 */
static BYTE *AllocVerMem( INT len, BYTE* buf, INT max_size, DWORD tskid )
{
    MEMHDR  *hdr;
    INT     i,req_size,remain;

    //! 取得するサイズにヘッダサイズを加えて必要なメモリサイズを計算する.
    req_size = len + sizeof(MEMHDR);

    for( i = 0; i < max_size; ){

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

        if( hdr->TaskId == 0 ){
            if( hdr->Size >= req_size ){
                //! 空きブロックのサイズから必要なサイズを引いた余りを計算しておく.
                remain = hdr->Size - req_size;

                //! 空きブロックを「貸し出し中」にする.
                hdr->Size   = req_size;
                hdr->TaskId = tskid;

                if( remain > sizeof(MEMHDR) ){
                    //! 空きブロックに余りがある場合はメモリブロックを分割して余りの空きブロックを作成する.
                    hdr         = (MEMHDR *)(&buf[i+req_size]);
                    hdr->Size   = remain;
                    hdr->TaskId = 0;
                }else{
                    //! 余りがヘッダサイズ以下の場合、貸し出したメモリサイズに余りも加えておく.
                    hdr->Size += remain;
                }
                //! 戻り値は使用可能は空きブロックの先頭アドレスを返す.
                return &buf[i + sizeof(MEMHDR)];
            }
        }
        //! 次のメモリブロックを取り出す.
        i += hdr->Size;
    }
    return NULL;
}
	

メモリブロックを貸し出す場合、貸し出すブロックの先頭に次のメモリブロックの位置が検出できるようにヘッダ情報を付加します。



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