CL

175. 呼出しスタック指定のメッセージ送信

SNDPGMMSG や API: QMHSNDPM によるメッセージ送信は通常は
TOMSGQ(*PRV)としてひとつ上の親スタック(=呼出し元)に送信することが
普通であるが呼出しスタックを明示的に指定して
メッセージを送ることもできる。
ここではその呼出しスタックの名前を指定するメッセージ送信は
どのような場合に必要となるのかを例を挙げて説明する。
この方法は筆者も解決方法として気づくのに結構時間がかってしまった
方法なのでテクニックとして知っておく値打ちはある。
_

[例1 ] 通常のメッセージの送受信

①親プログラムが子プログラムを呼び出して実行する

②子プログラムはメッセージを親プログラムに
 送信して終了する。

  SNDPGMMSG MSG(' 完了しました。 ') TOPGMQ(*PRV) MSGTYPE(*DIAG)

*PRVへの送信とは呼び出し元すなわち親の実行スタックへメッセージを
送信することを意味する。
③親プグラムはこのメッセージを受信して
 受信したメッセージを自分も表示して終了する。

  RCVMSG PGMQ(*SAME) MSGTYPE(*LAST) MSG(&MSG)
  SNDPGMMSG MSG(&MSG) MSGTYPE(*DIAG)

実行スタック*SAMEつまり自分の実行スタックのメッセージ待ち行列を
読んで再表示することを意味している。

[例2] 上記の例1の処理を QCMDEXC を介在させて実行してみよう。

親プログラム

QCMDEXC →(あいだにQCMDEXCが介在する場合)

子プログラム

①親プログラムは QCMDEXC の中に 子プログラムの呼出しを
埋め込んで QCMDEXCで子プログラムを実行する。

②子プログラムはメッセージを親プログラムに
 送信して終了する。

 
SNDPGMMSG MSG(' 完了しました。 ') TOPGMQ(*PRV) MSGTYPE(*DIAG)

ところがこのメッセージの送信先は親プログラムではなく
この場合の親スタックは QCMDEXCであるので

③親プログラムは受信(RCVMSG)で待機しても子プログラムからの
 メッセージは届かない。実行スタック・レベルも異なるし
第一、読もうとするスタックは既に消滅してしまっている。
今までのような親子関係ではなく親孫の関係である。
この時点で QCMDEXC も終了しているのでQCMDEXCのスタックは
消滅しており親プログラムはいくら探しても子プログラムの
メッセージはどこにも残っていないので受け取ることはできない。
 この問題にハマッてしまうとなかなか解決できない。
孫のメッセージをどうやってとるかという問題である。
_

[解決]

この問題を解決するにはQCMDEXC経由で呼び出された子プログラムの
中では

SNDPGMMSG MSG(' 完了しました。 ') TOPGMQ(*PRV) MSGTYPE(*DIAG)

として直接親にメッセージを送るのではなく
親プログラムのスタックを明示的に指定してQCMDEXCのスタックを
飛ばして直接親プログラムのスタックにメッセージを送信することである。

SNDPGMMSG MSG(' 完了しました。 ') TOPGMQ(*PRV (親プログラム名)) MSGTYPE(*DIAG)
呼出 スタック 項目 メッセージ 待行列 :                                    
  関係  . . . . . . . . . . . .   *PRV          *EXT, *PRV, *SAME 
  呼出スタック項目識別コード :                                    
  呼び出しスタック項目  . . . .   OYAPGM                          

のようにして親プログラム名: OYAPGM を直接指定すればよい。
(送信先は *SAMEではなく必ず*PRVも指定すること)
もし親プログラムから呼び出されるのではなく
子プログラムを単独で実行した場合は OYAOGM という実行スタックは存在しないので
エラーになるのではないか?
大丈夫。その場合でも子プログラムは単なる *PRVとしてメッセージ送信されるので
実行時のエラーになることはない。

■ 結論

直親(=ひとつ上のスタクック)にメッセージを送る場合は
SNDPGMMSG TOPGMQ(*PRV) で良いがそれ以上上の親スタックにメッセージを
送信するのであればTOMSG(*PRV (スタック名)) のようにスタック名を
明示的に名指しで指定しなければならない。

このようにスタック指定のメッセージ送信もできることも覚えておくと非常に役に立つ。
_

この応用はPython.400で生成され印刷CLPのの中で

 SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +         
              MSGDTA(&MSGDTA) TOPGMQ(*PRV (PRTPTNCL)) +  
              TOMSGQ(&TOMSGQ) MSGTYPE(*ESCAPE)           

のように使用されている。