01.2 ストレージ・プールの作成(CPOOL)

リエントラント・プログラムでは、書き込みを行うレジスター保管域や作業域はプログラムの外に確保するためGETMAINとFREEMAINマクロを利用します。しかし、頻繁に呼び出されるモジュールでは、呼び出しの度にこれらの領域の獲得と解放を繰り返すのはパフォーマンスの点で劣ります。そこで、このような場合は作業に使用する領域をまとめて確保しておき、必要の都度そこから切り出して使う方法が行われます。まとめて確保した領域をプール(POOL)、切り出す領域をセル(CELL)と呼びます。セルには固定長と可変長の両方の構造があります。可変長セルではストレージの利用効率は上がりますが実現方法はむずかしいです。ここでは、固定長のセルを使ったストレージ・プールの利用を解説します。

CPOOLマクロでストレージ・プールを作る

CPOOL BUILDマクロはセル・プールの作成を行い、CPOOL DELETEマクロはセル・プールの削除を行います。このサンプルでは、1KBの固定長セル64個分のプールを16MB未満のリージョンに作成します。作成されたプールの識別子がGR0に返ります。この識別子(セル・プールID)は、以降のGET、FREE及びDELETEの各サービスで使用します。64個以上のセルが要求された場合は、8個単位でプールが拡張されます(*1)。

*1 拡張されたプールが未使用となっても解放はされない。より細かなセルとプールの制御が必要ならCSRPxxxルーチン(呼び出し可能セル・プール・サービス)も利用できる。

CPOOLマクロでセルを切り出す

セル・プールは、サブルーチンを呼び出す親プログラムがあらかじめ作成しておくものとします。サンプルでは親プログラムはサブルーチンを呼び出す時、GR0にセル・プールIDを、GR1にパラメーター・リストを設定しています。呼び出されたサブルーチンは、プログラムの先頭でCPOOL GETマクロを使ってプールからセルを切り出します。切り出されるセルの長さは、親プログラムがプール作成時に定義します。レジスター保管域の目的なら72バイトあればいいのですが、リエントラント・プログラムでは作業域も必要になりますからそれらの長さも考慮して適当な大きさのセルを定義する方がいいでしょう。サンプルではレジスター保管域の後ろにプログラム作業域をDSECTでマッピングしています。GETMAINの代わりにCPOOL GETを使うと考えればいいでしょう。
呼び出し元プログラムへ復帰する際に切り出したセルを返却します。セル・プールIDは、入口点で保管したGR0を復元して指定しています。返却するセルのアドレスはGR2に設定しています。セル返却前に、呼び出し元のレジスター保管域アドレスをGR13にロードしておきます。こちらも、FREEMAINの代わりにCPOOL FREEを使うと考えればいいでしょう。

プールを各サブルーチンで作成する方法も考えられますが、プールIDをどこに保管するか?という問題がありますので、サンプルのように親プログラムでプールを作成する方が簡単です。なお、サンプルのような使い方では影響ありませんが、GETではGR2~4が、FREEではGR2~3が破壊されます。REGS=SAVEパラメーターを指定すれば内容は保証されますが、GR13がレジスター保管域をポイントしていなければなりません。したがって、サンプルのようにリエントラント・プログラム用レジスター保管域のためのセルのGETやFREEであれば、REGS=SAVEパラメーターは利用できません。

マルチタスク構造のプログラムで各タスクが同じサブルーチンを頻繁に呼び出すならば、GETMAINとFREEMAINよりCPOOLでセルを切り出す方がオーバーヘッドが少なくなります。