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 |
タイムアウトの設定値。
|
戻り値 | 説明 |
---|---|
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;
}
メモリブロックを貸し出す場合、貸し出すブロックの先頭に次のメモリブロックの位置が検出できるようにヘッダ情報を付加します。