セルタイプコードでのアロケータ¶
シグニチャの関数の引数の基本指定子として send または receive を指定すると、引数としてアロケータによりアロケートされたメモリ領域のアドレスが渡されます。 渡されたメモリ領域は、受け取った側で解放します。
send 指定された引数の場合、呼び元でアロケートし、呼び先でデアロケートします。 receive 指定された引数の場合、呼び先でアロケートし、呼び元でデアロケートします。 アロケート、デアロケート操作は、アロケータ呼び口を通して行います。
アロケータ呼び口¶
TECS では、メモリアロケータをセルとして実装しますが、アロケータセルの受け口に結合する呼び口が必要となります。 この呼び口のことをアロケータ呼び口と呼びます。 アロケータ呼び口は TECS CDL に明示的に記述しません。TECS ジェネレータにより生成されます。
アロケータ呼び口には、以下の名前が与えられます。
(アロケータ呼び口名) = (呼び口名または受け口名) + '_' + (関数名) + '_' + (引数名)
アロケータ使用の具体例¶
以下に、アロケータを使用する例を示します。
TECS CDL のコード例には、呼び先のセルタイプおよびセル、呼び元のセルタイプおよびセルが実装されているとします。 ジェネレータによって呼び先および呼び元の双方に、アロケータ呼び口およびその結合が自動的に挿入されます。
【TECS CDL 記述例】
signature sSendRecv {
/* この関数名に send, receive を使ってしまうとアロケータ指定できない */
ER snd( [send(sAlloc),size_is(sz)]int8 *buf, [in]int32 sz );
ER rcv( [receive(sAllocTMO),size_is(*sz)]int8 **buf, [out]int32 *sz );
};
celltype tTestComponent {
entry sSendRecv eS;
};
// 受け口側で、send/receive 指定された引数ごとにアロケータを指定
[allocator(eS.snd.buf=alloc.eA,eS.rcv.buf=alloc.eA)]
cell tTestComponent comp{
};
celltype tTestClient {
call sSendRecv cS;
};
// 呼び口側では、アロケータを指定しない
cell tTestClient cl {
cS = comp.eS;
};
【アロケータ呼び口が挿入されたコード(TECS ジェネレータにより内部生成された状態)】
以下のコードは、内部状態を説明するためのものであって、以下のような TECS CDL コードを記述するものではありません。
celltype tTestComponent {
entry sSendRecv eS;
/* 自動生成されたアロケータ呼び口 */
call sAlloc cS_snd_buf; <<< 自動生成された呼び口
call sAlloc cS_rcv_buf; <<< 自動生成された呼び口
};
[allocator(eS.snd.buf=alloc.eA,eS.rcv.buf=alloc.eA)]
cell tTestComponent comp{
/* 自動生成されたアロケータ呼び口の結合 */
eS_snd_buf = alloc.eA; <<< 自動生成された結合
eS_rcv_buf = alloc.eA; <<< 自動生成された結合
};
celltype tTestClient {
call sSendRecv cS;
/* 自動生成されたアロケータ呼び口 */
call sAlloc cS_snd_buf; <<< 自動生成された呼び口
call sAlloc cS_rcv_buf; <<< 自動生成された呼び口
};
cell tTestClient cl {
cS = comp.eS;
/* 自動生成されたアロケータ呼び口の結合 */
cS_snd_buf = alloc.eA; <<< 自動生成された結合
cS_rcv_buf = alloc.eA; <<< 自動生成された結合
};
セルタイプ tTestClient の呼び口 cS の関数の send, receive 指定された引数に対して、以下のようなアロケータ呼び口関数が、生成されます。 アロケート関数、デアロケート関数の両方が使用できますが、send 指定された引数の場合、通常、呼び元で使用する必要があるのは、アロケート関数です。 rceive 指定された引数の場合は、デアロケート関数です。
// allocator port for call port: cS func: send param: buf
ER cS_snd_buf_alloc( int32_t size, void** p );
ER cS_snd_buf_dealloc( const void* p );
// allocator port for call port: cS func: receive param: buf
ER cS_rcv_buf_alloc( int32_t size, void** p );
ER cS_rcv_buf_dealloc( const void* p );
// allocator port for call port: cA func: send param: buf
ER cA_snd_buf_alloc( subscript, int32_t size, void** p );
ER cA_snd_buf_dealloc( subscript, const void* p );
// allocator port for call port: cA func: receive param: buf
ER cA_rcv_buf_alloc( subscript, int32_t size, void** p );
ER cA_rcv_buf_dealloc( subscript, const void* p );
セルタイプ tTestComponent の受け口 eS の関数の send, receive 指定された引数に対しても、同様なアロケータ呼び口関数が、生成されます。
【未決定事項】アロケータを一々使い分けるのは、誤りのもとである。まとめる手段が必要。
アロケータの例¶
アロケータセルの例を以下に示します。
【TECS CDL 記述例】
signature sAlloc {
ER alloc( [in]size_t len, [out]void *p );
ER dealloc( [in]void *p );
};
celltype tAlloc {
entry sAlloc eA;
};
cell alloc {
};
リレーアロケータ¶
リレーアロケータの TECS CDL 記述例を示します。
【TECS CDL 記述例】
signature sSendRecv {
/* この関数名に send, receive を使ってしまうとアロケータ指定できない */
ER snd( [send(sAlloc),size_is(sz)]int8_t *buf, [in]int32_t sz );
ER rcv( [receive(sAlloc),size_is(*sz)]int8_t **buf, [out]int32_t *sz );
};
celltype tThroughComponent {
[allocator( /* 受け口から呼び口へリレー */
snd.buf <= cSR.snd.buf, /* cSR:前方参照可能 */
rcv.buf <= cSR.rcv.buf
)]
entry sSendRecv eS;
call sSendRecv cSR;
};
/* セルの定義で、受け口の send/receive 指定された引数のアロケータ指定不要 */
cell tThroughComponent comp{
cSR = TargetCell.eS; /* TargetCell でアロケータ指定が必要 */
};
リレーアロケータの場合も、上述のアロケータの例と同様に、アロケータ呼び口と結合が生成されます。 tThroughComponent のセルタイプコードでは、以下のアロケータ呼び口関数が生成されます。 ただし、受け取ったものをそのまま渡すため、これらの呼び口関数は、実際には使用する必要はありません。 もし、受け取ったものをそのまま渡すのではなく、再アロケート(reallc) するような場合には、これらの呼び口を用いることになります。 (この例では realloc は含まれません)
// allocator port for call port: eA func: snd param: buf
ER eA_snd_buf_alloc( subscript, int32_t size, void** p );
ER eA_snd_buf_dealloc( subscript, const void* p );
// allocator port for call port: eA func: rcv param: buf
ER eA_rcv_buf_alloc( subscript, int32_t size, void** p );
ER eA_rcv_buf_dealloc( subscript, const void* p );
// allocator port for call port: eS func: snd param: buf
ER eS_snd_buf_alloc( int32_t size, void** p );
ER eS_snd_buf_dealloc( const void* p );
// allocator port for call port: eS func: rcv param: buf
ER eS_rcv_buf_alloc( int32_t size, void** p );
ER eS_rcv_buf_dealloc( const void* p );
// allocator port for call port: cSR func: snd param: buf
ER cSR_snd_buf_alloc( int32_t size, void** p );
ER cSR_snd_buf_dealloc( const void* p );
// allocator port for call port: cSR func: rcv param: buf
ER cSR_rcv_buf_alloc( int32_t size, void** p );
ER cSR_rcv_buf_dealloc( const void* p );