メインフレームの真髄:再入可能(REENTRANT)なPL/Iプログラム設計と静的ストレージの罠
諸君、お疲れ様。今日も今日とて、数十年前に書かれたレガシーコードの解析と格闘していることだろう。
PL/Iという言語は、COBOLのような「お作法」で縛り付ける言語とは異なり、自由度が極めて高い。しかし、その自由度は「マルチタスク環境」や「CICS」といったシビアな舞台では、一歩間違えればメモリ破壊という名の地獄への入り口となる。
今日は、特にCICS環境やマルチスレッド環境における「REENTRANT(再入可能)」コードの設計について、現場の知見を叩き込んでいく。これが理解できていないと、複数のトランザクションが同時に動いた瞬間にデータが化けるという、最も精神を削るデバッグ案件に追われることになるからな。
—
1. なぜ「REENTRANT」が必要なのか?
CICSやマルチスレッド環境において、一つのプログラムコードは複数のユーザー(タスク)によって同時に共有される。もし、プログラムの中に「静的ストレージ(STATIC変数)」を置いて、そこに作業中のデータを保持しようとすればどうなるか?
Aさんのトランザクションが書き込んだ値が、実行中にBさんのトランザクションによって上書きされる。これが「データ競合」だ。これを防ぐ唯一の解が、「プログラムを再入可能(REENTRANT)にする」ことだ。
基本ルール:STATICを捨て、AUTOMATICを愛せ
PL/Iのデフォルトのストレージクラスを理解しているか?
- AUTOMATIC: プロシージャが呼び出されるたびにスタック上に確保される。これが再入可能性の鍵だ。
- STATIC: プログラム実行中、常に同じメモリ番地を占有する。これが再入可能性の敵だ。
REENTRANTを宣言するということは、「このコードは自分自身の静的領域には何も書き込まないし、依存もしない」とシステムに誓約書を出すようなものだ。
—
2. 実践的なコーディング例:REENTRANTな構造
以下のコードを見てほしい。CICS環境を想定した、ある種の標準的なアプローチだ。
1
/ ————————————————————- /
/ プログラム名: DEMOREENT /
/ 概要: 再入可能(REENTRANT)なPL/Iプログラムの構造例 /
/ ————————————————————- /
DEMOREENT: PROCEDURE OPTIONS(MAIN, REENTRANT);
/ ビルトイン関数の宣言は明示的に行うのが現場の鉄則 /
DCL SUBSTR BUILTIN;
DCL LENGTH BUILTIN;
/
- [ポイント]
- ここでSTATIC宣言をしてはならない。
- 自動変数(AUTOMATIC)はスタック上に生成されるため、
- 複数のタスクが並行動作しても競合しない。
/
DCL WORK_AREA_CHAR CHAR(80) AUTOMATIC;
DCL RC FIXED BIN(31) AUTOMATIC;
/
- ONユニットの制御フロー
- 異常終了を捕捉し、制御を安全に終了させる
/
ON ERROR BEGIN;
PUT SKIP LIST(‘予期せぬエラーが発生しました。ログを調査してください。’);
SIGNAL FINISH;
END;
/
- VSAMアクセスやファイル操作もこのAUTOMATIC変数経由で行う。
- 静的な作業領域は厳禁だ。
/
WORK_AREA_CHAR = ‘処理開始’;
/
- メイン処理ロジック
- ここに業務ロジックを記述する
/
CALL PROCESS_DATA(WORK_AREA_CHAR);
RETURN;
/ 内部サブプロシージャも同様に再入可能にする /
PROCESS_DATA: PROCEDURE(IO_DATA);
DCL IO_DATA CHAR(80) PARM;
/ … 処理ロジック … /
END PROCESS_DATA;
END DEMOREENT;
—
3. 現場で生き残るための「警告」
静的ストレージは「読み取り専用」と心得る
どうしても定数テーブル(ルックアップテーブルなど)をSTATICで持ちたい場合があるだろう。その場合は、`DCL MY_TABLE CHAR(100) STATIC INIT(…)` と宣言し、絶対に実行時に値を書き換えない(Read-Onlyとして扱う)こと。書き換える必要があるなら、それはSTATICに置くべきではない。
ONユニットの罠
`ON ERROR`や`ON ENDFILE`といったONユニットは、再入可能なコード内では特に注意が必要だ。ONユニット内で使用するフラグ変数なども、必ずAUTOMATICとして管理すること。グローバルなフラグで状態制御を行おうとすると、高負荷時に必ず障害が再発する。
VSAMアクセスと再入可能性
VSAMを扱う際は、ACB(Access Control Block)やRPL(Request Parameter List)をどこに配置するかが重要になる。これらをプログラム内にハードコードしたSTATIC領域に置くと再入不可能になる。
現場では、「GETMAIN」命令を使って、実行時に必要なメモリ領域を動的に獲得するのが定石だ。獲得したメモリのポインタを`BASED`変数としてマッピングすることで、各タスクが自分専用の作業領域を持つことができる。
—
最後に:アーキテクトからの助言
「動けばいい」というコードは、単一バッチ環境なら許されるかもしれない。だが、現代のメインフレーム運用において、再入可能性を軽視したコードは時限爆弾だ。
マイグレーションや保守の現場で、もしあなたが「何故か特定条件下でしか再現しない謎のデータ化け」に遭遇したら、まず疑うべきは「STATIC領域の不適切な書き込み」である可能性が極めて高い。
コードを書くとき、常に「この変数は今、他のタスクから覗かれても大丈夫か?」と自問自答してほしい。その視点こそが、ベテランと駆け出しを分かつ境界線だ。
何か具体的な実装で詰まっている箇所があれば、いつでも相談してくれ。PL/Iの深淵はまだまだ深いぞ。

コメント