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;
}
}