01.2ストレージ・プールの作成(CPOOL)
リエントラントプログラムでは書き込みを行うレジスター保管域や作業域はプログラムの外に確保するため、GETMAIN/FREEMAINマクロを利用します。しかし頻繁に呼び出されるモジュールでは呼び出しの度にこれらの領域の獲得と解放を繰り返すのはパフォーマンスの点で劣ります。そこでこのような場合は作業に使用する領域をまとめて確保し、必要の都度そこから切り出して使う方法が行われます。まとめて確保した領域をプール(POOL)、切り出す領域をセル(CELL)と呼びます。セルは固定長と可変長の両方の構造がありますが、可変長セルはストレージの利用効率は上がりますが実現方法はむずかしいです。ここでは固定長のセルを使ったストレージ・プールの利用を解説します。
CPOOLマクロでストレージ・プールを作る
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- CPOOL BUILD, BUILD LOCAL WORKAREA POOL + PCELLCT=64, PRIMARY CELL = 64 ENTRIES + SCELLCT=8, SECONDARY CELL = 8 ENTRIES + CSIZE=1024, CELL SIZE + LOC=(BELOW,ANY), LOCATION IS BELOW + HDR='SUB-ROUTINES LOCAL WORKAREA POOL' ST R0,POOLID SAVE CELL POOL ID : : POOLID DC A(0) CELL POOL ID CPOOL DELETE, DELETE LOCAL WORKAREA POOL + CPID=POOLID
CPOOL BUILDマクロはセル・プールの作成を行い、CPOOL DELETEマクロはセル・プールの削除を行います。このサンプルでは1KBの固定長セル64個分のプールを16MB未満のリージョンに作成します。作成されたプールの識別子がGR0に返ります。この識別子(セル・プールID)は以降のGET,FREE,DELETEの各サービスで使用します。
64個以上のセルが要求された場合は8個単位でプールが拡張されます。(拡張されたプールが未使用となっても解放はなされません、より細かなセルとプールの制御が必要ならCSRPxxxルーチン(呼び出し可能セル・プール・サービス)も利用できます。)
CPOOLマクロでセルを切り出す
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- 呼び出すプログラム L R0,POOLID GR0 <-- our pool id la r1,plist gr1 <-- parameter list l rf,=V(SUB1) load sub routine entry basr re,rf call it : : 呼び出されるプログラム sub1 csect , define code section using *,rc base register stm re,rc,12(rd) save caller registers lr rc,rf gr12 -> OUR 1ST BASE ADDRESS + GR0 --> CELLPOOL ID + GR1 --> PARAMETER LIST SPACE , CPOOL GET,UNCOND, GET LOCAL WORKAREA FROM CPOOL + CPID=(0), CPOOL ID IN GR0 + REGS=USE ST RD,4(,R1) SAVE CALLER SAVEAREA ST R1,8(,RD) CHAIN OUR SAVEAREA LR RD,R1 GR13 -> OUR SAVEAREA AND + LOCAL WORKAREA(1024BYTES) USING DWORK,RD ADDRESS IT : : : : : LR R2,RD GR2 --> OUR LOCAL WORKAREA L RD,4(,RD) LOAD CALLER SAVEAREA ST RF,16(,RD) PASS RETURN CODE IN GR15 L R0,20(,RD) LOAD CELLPOOL ID CPOOL FREE, BACK USED CELL TO OUR CPOOL + CPID=(0), + CELL=(2), + REGS=USE LM RE,RC,12(RD) RESTORE CALLER GPRS BR RE RETURN TO CALLER SPACE , DWORK DSECT , OUR LOCAL WORKAREA MAP DC 18F'0' OUR GPR SAVEAREA DOUBLE DC D'0' DOUBLE WORD WORKAREA WORKAREA DC XL128'00' 128BYTES WORKAREA
セル・プールはサブルーチンを呼び出す親プログラムがあらかじめ作成しておくものとします。サンプルでは親プログラムはサブルーチンを呼び出す時、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パラメーターは利用できません。
CPOOLはz/OSでのみ利用できます。MSPには同等機能としてBLDCPOOL,GETCELL,FREECEEL,DELCPOOLの各マクロがありますが、プールの作成と削除はキー0・スーパーバイザーモードのプログラムでしか利用できず一般プログラムでの利用を想定していません。VOS3では同等機能が公開されていません。
マルチタスク構造のプログラムで各タスクが同じサブルーチンを頻繁に呼び出すならば、GETMAIN/FREEMAINよりCPOOLでセルを切り出す方がオーバーヘッドが少なくなります。