IBMオフィシャルz/OS解説サイト

By kamii - Last updated: 月曜日, 12月 8, 2008
米国IBM社のWebサイトに、z/OSの基本スキルについて解説されているページを見つけました。

英文ではありますが、OSのしくみ、IMS、CICSとは何だ?プログラミング言語の紹介、JCLの解説からサンプルJCLなどなど広範囲に渡って、z/OSと関連する分野の基本スキルについて解説されています。
こういうのを見ると、やっぱIBM社はメインフレームに力入ってるじゃん!と改めて思います。メーカー自らの基本スキルの解説は、これからメインフレームに携わる人への大きな福音になります(残念ながら日本語版はありませんでした)。MSP,VOS3の利用者であってもOSとしての基本部分は同じですから参考になります。

「z/OS basic skills information center」


Filed in .z/OS(MVS),MSP,VOS3のしくみ, メインフレーム情報

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

By kamii - Last updated: 金曜日, 12月 5, 2008

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


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

CPOOL BUILDマクロはセル・プールの作成を行い、CPOOL DELETEマクロはセル・プールの削除を行います。このサンプルでは1KBの固定長セル64個分のプールを16MB未満のリージョンに作成します。作成されたプールの識別子がGR0に返ります。この識別子(セル・プールID)は以降のGET,FREE,DELETEの各サービスで使用します。
64個以上のセルが要求された場合は8個単位でプールが拡張されます。(拡張されたプールが未使用となっても解放はなされません、より細かなセルとプールの制御が必要なら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パラメーターは利用できません。

CPOOLはz/OSでのみ利用できます。MSPには同等機能としてBLDCPOOL,GETCELL,FREECEEL,DELCPOOLの各マクロがありますが、プールの作成と削除はキー0・スーパーバイザーモードのプログラムでしか利用できず一般プログラムでの利用を想定していません。VOS3では同等機能が公開されていません。
マルチタスク構造のプログラムで各タスクが同じサブルーチンを頻繁に呼び出すならば、GETMAIN/FREEMAINよりCPOOLでセルを切り出す方がオーバーヘッドが少なくなります。

Filed in 中級編

COBOLから呼ばれるアセンブラールーチン

By kamii - Last updated: 金曜日, 12月 5, 2008

現在ではアセンブラー言語でメインのアプリケーションを作ることはほとんどないものの、COBOLなどで作成されたアプリケーションからサブルーチンとしてのアセンブラープログラムを呼び出すことはよく行われます。COBOLなどの高水準言語プログラムから呼び出されるアセンブラールーチンの作成はさほどむずかしいことではありません。リンケージ規約通りにプログラムを作ればいいのです
しかし逆はかなり面倒です。アセンブラールーチン側で言語処理プログラムの環境を作り上げねばなりません。現実的にアセンブラーでメインのアプリケーションを作り、サブルーチンをCOBOLで作るなどと言うことはまず行われませんからその方法はあえて解説もしません。必要ならコンパイラー(z/OSの場合ならLE)のマニュアルに解説されていますので参照してみてください。


COBOLから呼ばれるサブルーチン例

COBOLから渡されるパラメーターはGR1が示すアドレス・パラメーターリストで受け取ることができます。
CALL文のUSINGで指定された順序でパラメーターが格納された領域アドレスが示されます。サンプルでは3つのパラメーターPARM1,PARM2,PARM3を格納した領域アドレスがGR1で示されるアドレス・パラメーターリストで渡されます。PARM3アドレスを示すワードの先頭ビットは最終パラメーターであることを示すため1にセットされます。PARM1からPARM3領域のアドレスをLM命令でGR2からGR4にそれぞれロードします。
PARM1およびPARM2で渡された値をPARM3領域にエコーバックするのがこのサンプルで行っている処理です。PARM1は8バイトの文字、PARM2はフルワードの整数値で、それぞれをPARM3領域の前半8バイトと後半8バイトに格納します。PARM2はバイナリー値を10進文字に変換して設定します。
もちろんどのパラメーターがどのような形式や長さ、意味を持つかはプログラム間のインタフェースとして予め取り決めておきます。
リンケージ規約やアドレス・パラメーターリストについてはリンケージ規約(サブルーチンを作る)も参照して下さい。


呼び出すCOBOL側のサンプル

呼び出されるアセンブラー・サブルーチンに対応した呼び出す側のCOBOLのサンプルです。
最初の例はアセンブラールーチンもリンケージエディターで静的に結合されたモジュールの呼び出し例で、2番目はリンケージエディターで結合されていない独立したロードモジュールの呼び出し例です。IBMのEnterprise COBOLによるコーディング例です。細かな構文はメーカーが提供するCOBOLコンパイラーによって多少の違いがあるので利用するコンパイラーのマニュアルも参照して下さい。


パラメーターの値渡し

IBMのEnterprise COBOLではパラメーターを値その物で渡すこともできます。CALL文のUSINGパラメーターに「BY VALUE」を指定することでパラメーター領域のアドレスではなく値が渡ります。渡せるパラメーター(値)は2進整数など4バイト以内で渡せるデータに限ります。

Filed in MVS実践アセンブラー・プログラミング

ハウスキーピングあれこれ

By kamii - Last updated: 水曜日, 12月 3, 2008

ハウスキーピング(プログラム冒頭での呼び出し元レジスター内容の保管やベースアドレスの設定処理)の処理はプログラマーによっていろいろな方法が行われるが基本は「リンケージ規約の遵守」です。決まり切った手順でもあるので一度スタイルを決めればずっと使い続けられます。
ここでは私自身が長年使ってきたコーディングのいくつかをサンプルとして紹介します。


オーソドックスなコード

レジスター保管域をハウスキーピングのコードの中に定義した例です。レジスター保管域のように実行中に参照することがないデータ領域にいちいち名前を付けるのも面倒なので私自身は好んで使っていました。
呼び出し元への復帰時にはGR15に復帰コードが設定されているものとしています。


モジュールの先頭にヘッダーを付ける

プログラムの冒頭にヘッダーを付けることはしばしば行われます。名前、アセンブル日付・時刻などはヘッダー情報の代表的なものです。複数のプログラムを結合して1つのロードモジュールにするような場合は各CSECTの名前も入れればダンプリストを見た際に識別しやすくなります。商用プログラムでは製品のバージョンやPTF用のパッチエリア、COPYRIGHT表示なども入れられます。
一般のプログラムは入口点のGR15にはプログラムの先頭アドレスが格納されていますから、ヘッダーの長さだけジャンプする無条件分岐命令を先頭に置いて、続いてヘッダーデータを書きます。GR15を基点にしてヘッダーの長さ+分岐命令の長さを指定してヘッダーを迂回します。
MSPとVOS3では&SYSDATCの代わりに&SYSDATEが使えます。


ヘッダー用マクロを作る

いちいちヘッダーを書くのが面倒、プログラムを分割して開発するがヘッダースタイルは統一したい、と言った場合はヘッダーを生成するマクロ命令を作ると便利です。MACROからMENDで囲まれた部分をMDHDRと言う名前のメンバーで作成します。プログラムではこのMDHDRマクロを書けばアセンブル時にマクロ内で定義したヘッダーデータが展開されます。
ヘッダーマクロのサンプルとそれを使ったサンプルを示します。


オーソドックスなコード(再入可能プログラム)

再入可能(リエントラント構造)プログラムは自分のプログラム内に書き込みデータを持つことができないので、レジスター保管域も定義できません。レジスター保管域をプログラムの外に確保するサンプルです。


GR13をベースレジスターに使う

再入可能である必要がないプログラムではレジスター保管域を示すGR13をベースアドレスにしたプログラムを作成することもできます。サイズが大きくなるプログラムでも、GR13,12,11とベースアドレスに使えるレジスターを1つでも多くすることができます。サンプルではレジスター保管域をプログラムの先頭に置き、GR13とGR12をベースレジスターにしています。
DC 17Fで68バイトしか定義していないのは間違いではありません。保管域の最初のワードはアセンブラー言語では未使用であることを応用しています。


一切のサブルーチンを呼ばないなら

あまりいいサンプルではありませんが、将来に渡っても絶対サブルーチンを呼ばないのならこのようにレジスター保管域を持たなくてもかまいません。OSのAPIはほとんどがSVC呼び出しなのでレジスター保管域を必要としませんが、データセットのアクセスに使うGET/PUTマクロなどAPIによってはGR13がレジスター保管域であることを要求するものもあるので注意します。


リンケージスタックを使う

リンケージスタックはESA/390から利用できる機能です。先頭のBAKR 14,0命令は現PSWの前半ワード内容とGR14の内容で後半ワードを生成した呼び出し元への復帰用PSW、および汎用レジスターとアクセスレジスターをスタックに保管します。最後のPR命令はスタックに保管されたPSWとレジスター2から14が復元されます。結果としてレジスターを復元して呼び出し元に戻ることになります。レジスター15,0,1はPR命令発行時の内容がそのまま渡ります。BAKRはスタックへのPUSH、PRはスタックからのPOPです。内部サブルーチンでもレジスターの保管を気にせずに済むので使うと便利な機能です。
MVSではリンケージスタックの利用は必須ではありませんし、使う使わないの選択は自由なので、自分が呼び出すサブルーチン(OSのAPIを含む)がリンケージスタックを使う保証はありません。そのためGR13には標準のレジスター保管域をポイントする方が間違いありません。この場合呼び出し元保管域のポインターにはアドレスの代わりに’F1SA’の4文字を設定する規約になっています。
現実的にはプログラムは最初に実行される時、OSが用意したレジスター保管域がGR13で渡されるため、GR13を他の目的で使わない限りわざわざ別に用意しなくても問題はおきないでしょう。(例えばQSAMのGET/PUTマクロの利用など)ただしプログラムがABENDした時のダンプには正しいSAトレースが出力されなくなります。自分は呼び出し元の保管域を使用しなくても、呼び出すプログラムのために標準通りの保管域を用意し、互いにチェインする代わりにF1SAを表示するのはレジスター保管域とリンケージスタックを混在させるためのMVSの決まり事なのです。テスト的に作成するプログラムでない限り規約通りに作成する方がいいでしょう。

リンケージスタックはMVS(z/OS)では当たり前に使える機能ですが、MSPとVOS3では注意が必要です。MSPではMAFと呼ばれる追加のハードウェア機構が必要で、VOS3ではIPLパラメーターにクロスメモリー機能を有効にするパラメーター(マニュアル記載なし?)が必要です。利用できない環境であれば、BAKR命令がS0DxのコードでABENDします。その場合はメーカーの担当SEに問い合わせてみて下さい。

Filed in MVS実践アセンブラー・プログラミング

ファイルシステム-1

By kamii - Last updated: 月曜日, 12月 1, 2008

MVSのファイルシステムの最も大きな特徴はファイル(データセット)は構造化されたレコードを持つ点です。WindowsやUnixのファイルシステムとはあらゆる点で異なります。ファイルそのものの構造について比べると、Windowsなどではファイル自体は可変長の大きさを持ち、ファイルの大きさはデータ量によって増減します。ファイルの中がどのような形式でフォーマットされているかはOSは関与しません。OSから見れば構造化されていない連続したストリーム・データの集合です。MVSで言えばRECFM=U・BLKSIZE=32760のデータセットが最も近いでしょう。
反面MVSではRECFM=U形式のデータセットはアプリケーション・データに使われることはほとんどありません。基本的にデータはレコードによってまとめられ、レコード単位にファイルが構成されます。データの集合がレコード、レコードの集合がブロック、ブロックの集合がデータセットです。ブロックはディスクやテープに記録される時の単位でもあることから物理レコードとも呼ばれます。

----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8
<- Name           -><- Address                  -><- Phone ->

レコードにはこんな感じでデータが並べられます。メインフレーム・コンピューターの原点がパンチカード・システムあったことから、アプリケーション・データは古くからこのように業務処理で使うデータが1つのレコードに並べられ、それを複数集めて処理データを構成するファイル(データセット)を作りました。パンチカードの名残ではデータセットはRECFM=F,BLKSIZE=LRECL=80の1形式しかありませんが、現在のMVSではRECFM=F[B]|V[B]|U,BLKSIZE|LRECL=1?32760の範囲で、さまざまな組み合わせによって構成されます。

----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8
Block-1
<- Record-1       -><-                          -><-       ->
<- Record-2       -><-                          -><-       ->
<- Record-3       -><-                          -><-       ->
<- Record-4       -><-                          -><-       ->
<- Record-5       -><-                          -><-       ->
<- Record-6       -><-                          -><-       ->
<- Record-7       -><-                          -><-       ->
<- Record-8       -><-                          -><-       ->
<- Record-9       -><-                          -><-       ->
<- Record-10      -><-                          -><-       ->

Block-2
<- Record-11      -><-                          -><-       ->
<- Record-12      -><-                          -><-       ->
<- Record-13      -><-                          -><-       ->
<- Record-14      -><-                          -><-       ->
<- Record-15      -><-                          -><-       ->
<- Record-16      -><-                          -><-       ->
<- Record-17      -><-                          -><-       ->
<- Record-18      -><-                          -><-       ->
<- Record-19      -><-                          -><-       ->
<- Record-20      -><-                          -><-       ->
   :
   :
レコードをいくつかまとめたものがブロック。
この例では10レコードをまとめてブロックにしている。
レコード長を72バイトとした場合、BLKSIZE=720,LRECL=72となる。
ディスクやテープには720バイト単位でデータが記録される。

レコード形式(RECFM)、ブロック長(BLKSIZE)およびレコード長(LRECL)はデータセットの物理的な構造を示した属性ですが、レコードの配列の種類を示すデータセット編成(DSORG)と呼ばれるものが別にあります。代表的なものが順次編成(PS)と区分編成(PDS,PO)およびVSAMです。他にも直接編成(DA)、索引順次編成(IS)データセットもありますが、現在ではVSAMまたはデータベース・システムに取って代わられ、互換目的以外で使われることはありません。新たに学ぶ必要もないでしょう。
データセットをアクセスするためのAPIはアクセス法と呼ばれ、データセット編成毎に用意されます。MVSが標準で提供するもの以外にもデータベース・システム(DB2,IMS/DB,AIM/DB,ADABASなど)やライブラリー管理システム(CA-LIBRARIAN,CA-PANVALETなど)がメーカーだけでなくISVからもソフウェア製品が提供されています。
しかしどのような編成のデータセットやデータベース・システムであっても、ディスク上はいずれかのRECFMとBLKSIZE,LRECLを持つブロックの集合体です。レコード形式やデータセット編成については「データセットの種類とアクセス法」に解説があります。

MVSのファイルシステムではOSもデータセットのレコード形式や長さを意識してアクセスの制御を行います。データのアクセス単位がデータの構造によって変わるためです。アクセス法によってレコード単位、ブロック単位など何種類かに分かれます。このあたりが他のプラットフォームに慣れた人には複雑に見える点でしょう。元々の発想点が1行80文字の紙カードから来ていて、文字単位ではなくカード単位での(何文字読んだ?ではなく何枚読んだ?)処理が原点だからです。


編成(アクセス法)別に見たデータセットの特徴

上段ほど新しいアクセス法です。最も下段にあるEXCPはチャネルプログラムを直接使う方法ですが、アプリケーションがこれを使うことはまずありません。さらに下段(BIOSコール)もありますがここでは省きます。下段に行くほどデータセットの物理的な構造と、ハードウェア特性がわかっていないとアクセスできません。EXCPの場合はデータセットの物理構造だけでなく、ディスクやテープ装置自体のデータ記録方法も知っている必要があります。
QSAMあたりにくると論理レコード単位のアクセスができるようになり、物理的な構造からかなり解放されます。COBOLやPL/I言語でのファイルアクセスもQSAMあるいはVSAMを通じて行われます。VSAMからはデータセットの物理的な構造とプログラムが扱うデータ構造は1対1に対応しなくなってきます。VSAMはその名の通りデバイスに依存しない仮想のファイルを実現するものです。VSAMをさらに発展させたものがデータベースです。データベースの物理的な器であるMVSデータセットはVSAMあるいは順次編成データセットがよく使われます。プログラムが扱うレコードはデータベース・システムが提供する機能に基づきメモリー内にマッピングされ、物理的な構造にはまったく関わる必要がありません。
PDSEはMVSが提供する拡張区分編成データセットですが、その物理的な実体は4096バイト固定長レコードの順次データセットです。プログラム上は従来の区分データセット同様にRECFM,BLKSIZE,LRECLを持ちますがあくまでも仮想のもので従来と同じアクセス法(BPAM,QSAM)でアクセスできる互換性があります。もちろんプログラムは物理的構造である4KB固定長レコードを意識する必要はまったくありません。

難易度についてはアセンブラー言語によるプログラミングが必要かどうか、よりハードウェア寄りの知識がいるかどうかで付けてみました。同じ構造のデータなら一般的には高水準なアクセス法(より抽象的、仮想的)ほどプログラミングもやさしくなります。ただし高水準なアクセス法ほど機能も豊富になりますので、それらも含めて使いこなそうとすればやさしいプログラミングだけでは済みませんし、データ設計もきちんと行わなければなりません。そう言う意味では難易度の幅は広くなります。

Filed in .z/OS(MVS),MSP,VOS3のしくみ

シンプルISPFメニューとクイック起動

By kamii - Last updated: 金曜日, 11月 28, 2008
(このトピックはz/OS限定です)

デフォルトで導入されたISPFをそのまま利用してもいいのですが、普段からよく利用するツールなので使いやすいようにメニューパネルをカスタマイズすることもできます。
デフォルトで導入されたISPF起動CLISTでISPFを起動したとき、ISPFメニューの前にISMF、IPCS、RACF、DITTO、SMP/Eなどのアドミニストレーターのシステム保守用ツールも起動できる「CUSTOMPAC MASTER APPLICATION MENU」パネルが表示されるようになっていると、PDFやSDSFはそのパネルから改めて選択し直すことになります。普段使うのがISPF/PDFとSDSFなら直接PDFメニューパネルを表示して、SDSFもそこから選択できると便利です。

アドミニストレーター用のシステム保守ツールも使える「CUSTOMPAC MASTER APPLICATION MENU」は、PDFとSDSFの起動に必要なデータセットだけでなく、数多くのプロダクトのデータセットをCLIST内で割り当てるため、起動に時間が掛かります。
普段の作業に必要なければ、使うツールに限定したCLISTやパネルを使えば資源の節約やセキュリティー面でも有益です。


ISPF起動用CLISTの作成

ISPFのデフォルトPOM(Primary Option Menu)パネルである、ISR@PRIMを使用し、最低限必要なISPFデータセットを割り振り、ISPFを起動するCLISTサンプルです。
MY.CLISTおよびMY.PANELはユーザー専用のCLIST、PANEL定義体を格納するデータセットです。必要に応じてデータセットを追加するか、不要であれば削除します。
このCLISTではISPFプロファイルは、新規データセットをダイナミックにアロケートしないで、すでに作成済みである、としています。SET &PROFDSN = ISPF.&SYSUID..ISPPROF の箇所で自分のISPFプロファイル・データセット名がセットされるように修正します。


カスタマイズしたパネルでISPFを起動する

作成したCLISTをデータセットMY.CLISTに、メンバー名MYPDFで入れたものとします。
TSOに再ログオンして、READYプロンプトから「EX ‘MY.CLIST(MYPDF)’」で修正したパネルを使ったISPFが起動します。z/OSでは、デフォルトのISPFメニューパネル(ISR@PRIM)にはSDSFが「S」で追加されているので、PDFの各パネルから=SでSDSFを直接起動できます。ISPFを終了してREADYプロンプトへ戻った後、再度ISPFを起動する時は単に「MYPDF」と打てばISPFを起動できます。MYPDF内でSYSPROCにMY.CLISTを追加して再アロケーションしているからです。

初回のEXコマンドが面倒なら、TSOのログオンプロシージャのSYSPROC DD文に、「MY.CLIST」を追加します。




英語パネルのISPF

筆者の好みではありますが、日本語パネルは字が大きく、どうもごちゃごちゃした感じですっきりしません。覚えてしまえば、パネル上の決まり切ったガイダンスなど日本語である必要はないので、パネルのみ英語版を使うのもいいと思います。英語パネルはすっきりした感じに見えますが、どうでしょうか?
英語パネルを使っても、端末エミュレーターが日本語をサポートしていれば、エディターやブラウザーで日本語を表示・入力することは可能です。

英語パネルを使う場合は、前述のサンプルCLISTでデータセットの最後3文字がJPNになっているところをENUに変更します。

ISPFプライマリーメニューパネルの修正

POMパネルにSDSFが組み込まれていなければ、パネル定義体を修正して追加します。

英語版のデフォルトPOMパネルは、ISP.SISPPENUのISR@PRIMです。これを任意のデータセットにコピーして上記のように修正します。サンプルのCLISTであれば、「MY.PANEL」にコピーして、そちらを修正します。この修正はPOMパネルからSDSFを起動できるようにするためのものです。「<=== ADD for SDSF」で示した行を追加します。最初の追加部分は新たな行を挿入するのではなく、6 Command または 7 Dialog Test の行をリピートして修正するようにします。これはその行に表示・入力できないバイナリーデータが使われているためです。
普段使わない機能はメニューからはずせばよりシンプルになりますが、速さの面ではほとんど関係ありません。他のISV製品などのツール類も含めて1メニューパネルに収めたいような時は、使わなくてもかまわない機能をはずすのもいいでしょう。サンプルではSDSFに「SD」を割り当てましたが、日本語パネルと同じ「S」でももちろんかまいません。
ISV製品のプログラムやパネルも、同様の方法で追加できます。

Filed in CLIST(コマンドプロシージャ)とISPFダイアログ, ISPFとSDSFのちょっと得する使い方

09.1プログラムをスーパーバイザー・モードに切り替える(MODESET)

By kamii - Last updated: 水曜日, 11月 26, 2008

一般のアプリケーション・プログラムではほとんど必要ありませんが、システム・プログラムでは処理によっては監視プログラム(スーパーバイザー)モードに切り替える必要が生じます。例えば監視プログラム状態を要求するAPIの使用(MGCRなど)、特権命令の使用などです。
このような場合、プログラムはAPIによって自分自身の走行モードを問題プログラム状態から監視プログラム状態に変更することができます。

スーパーバイザー・モードとAPF許可を混同しないで下さい。スーパーバイザー・モードは特権命令が利用できるCPU上の特別な実行モードですが、APF許可はMVSにシステム・プログラム用機能の利用が許可されたプログラムであって、PSWの走行モードとは関係ありません。APF許可プログラムであっても特別な設定(PPT登録)がされない限り、MVSは問題プログラム状態でプログラムを実行します。なおシステム・プログラミング用機能であってもほとんどのAPIはAPF許可さえあれば良く、監視プログラム状態を要求するものはごく1部です。マニュアルをよく読んで不必要なモードチェンジをしないようにします。


プログラムを監視プログラムモード(スーパーバイザーモード)に切り替える

MODESETマクロはプログラムの走行モードを切り替えます。当然APF許可されたプログラムでなければ使用できません。MODEパラメーターで走行モードを、KEYパラメーターでPSWキーを変更できます。MODE=SUPは監視プログラム・モードへ切り替え、MODE=PROBで元の問題プログラム・モードに戻します。同時にPSWキーを変更する時は、KEY=ZEROでPSWキーを0に、KEY=NZEROでPSWキーを元のキーに戻します。キーを変更する必要がなければモードのみを変更しましょう。スーパーバイザーモードだからキーも0にする、と理解しているプログラマーもいますが、それは正しいことではありません。元のPSWキーのままで問題ないロジックは無用にキーを変えてはなりません。


PSWの記憶保護キーを変更する

OSの出口ルーチンなどではその多くが監視プログラム状態のまま呼び出されます。このようなプログラムでは特権命令を使わないからと言ってわざわざ問題プログラム状態に変える必要はありません。むしろモードの不用意な変更は致命的なエラーを引き起こします。ただし処理によってはPSWキーを変更する場合もあり得ます。このような時KEYパラメーターを指定したMODESETマクロを使ってはなりません。最初から監視プログラム状態で動くプログラムの場合はSPKA命令を使用してPSWキーを変更します。
オペランドに新しいキーを即値またはキー値を格納したレジスターで指定し、サンプルのようにコーディングします。出口ルーチンなどでは最初に制御が渡されたときのキーはマニュアルに明記されていますから、その値に戻してもいいですし、IPK命令で現在のPSWキー値を保存してもいいでしょう。IPK命令は無条件にGR2の下位バイトにキーの値をセットしてしまいます。そのレジスターを使ってSPKA命令を出せば元のキーに戻せます。GR0でなければGR2以外のレジスターにコピーして使ってもかまいません。

Filed in 中級編

08.1TSO端末との通信(TPUTとTGET)

By kamii - Last updated: 水曜日, 11月 26, 2008

MVSにおけるアプリケーション・プログラムの基本はバッチ処理ですが、端末と直接会話できるオンライン処理もポピュラーな利用方法です。基幹業務システムに使うプログラムはCICSやIMSなどを使って動かしますが、簡単な処理や非定型なものはTSOが便利です。ここではTSO端末への簡単なI/O方法(送受信処理)を紹介します。MSPとVOS3にも共通な方法です。


QSAMによるTSO端末I/Oプログラム

別のカテゴリー「TSOで動作する簡単なコマンドライン版プログラムの作り方」でも紹介したQSAMによる方法です。SYSPRINTが端末への出力、SYSINが端末からの入力になります。MVSとMSPではこのDD名でLOGONプロシージャーに割り当てられていますからDD名を合わせればそのまま使えます。
サンプルのようにSYSPRINTとSYSINをそれぞれOUTPUTモード、INPUTモードでOPENします。端末へメッセージを送信するにはPUTマクロを、端末からデータを受信するにはGETマクロを発行します。PUTマクロはメッセージの送信がキューイングされれば完了するので、実際にはすぐに戻ってきます。GETマクロは端末でキー入力が行われるまで待ち状態になります。端末で「/*」の2文字が入力されるとEODと見なされ、DCBで指定したEODADルーチンが実行されます。EODADを使わず任意の文字列を入力終了の判定に使ってもかまいません。処理が終了したらSYSPRINTとSYSINをCLOSEします。
サンプルでは簡単にするために固定長レコードを使っていますが、メッセージ領域を節約するならRECFM=VBで可変長レコード形式にしてもかまいません。


TSOプログラミングAPIによるTSO端末I/Oプログラム?

最初のサンプルと同じことをQSAMではなくTSOのプログラミングAPIであるTPUTマクロとTGETマクロに置換えたものです。TSOでのみ動かすプログラムならTPUT,TGETの方がすっきりしますが、QSAMを使えばバッチ、TSO両方でも実行できるメリットがあります。
TPUT/TGETではメッセージ領域のアドレスと長さを指定します。TGETでは実際にメッセージ領域に格納されたデータ長がGR1に返されます。サンプルでは省略していますがTPUTもTGETも復帰コードを返しますので本来ならば正しくチェックすべきです。QSAMと違って/*入力でのEOD処理はされませんから自分で入力データを判定して同様のことを行っています。TPUT/TGETは可変長データの取り扱いになりますが、RECFM=VB指定のQSAMアクセスと異なりRDWを必要としません。


TSOプログラミングAPIによるTSO端末I/Oプログラム?

少しだけ込み入った処理を加えます。プロンプトの「COMMAND READY >>」の直後にデータを入力できるようにして、入力に使ったキーの種類(アテンションID)をエコーするようにしたものです。TPUTマクロでのASISオプションはメッセージを自動改行しないようにします。TGETマクロでのASISオプションは端末からの入力データを制御コード付きのままプログラムに渡します。

TPUTでコマンドプロンプト・メッセージを送った後、ASIS指定のTGETで入力を待ち合わせます。1バイトのみ読み込んでいるのはどのキーでデータを入力したのかを得るためです。ENTERキーであればx7D、PF1?PF9キーであればxF1?xF9、PF10?PF12キーであればx7A?x7Cとなります。次のTGETで入力された文字列を読み込んでいます。エコーするメッセージの先頭には入力に使われたAID文字を表示するようにしています。
/*の入力またはPF3キー押下であれば処理を終了します。CLRの入力またはPF12キー押下であれば画面をクリアーします。画面のクリアーは端末画面(3270)のデータストリーム・制御コードを直接定義して行っています。データストリームの解説はここでは行いませんが、CLRDATAに定義したコードが画面消去用のデータです。(先頭のx27を除く)これをFULLSCRオプションのTPUTで送信します。FULLSCRオプションを使う時はデータストリームの先頭にx27を付加する決まり事になっています。

TPUTおよびTGETはMVSのAPIではなくTSOのAPIです。
マクロの詳細はTSOのプログラミング・マニュアルを参照して下さい。

Filed in .基礎編

07.1非同期事象の待ち合わせと通知(WAITとPOST)

By kamii - Last updated: 火曜日, 11月 25, 2008

システムプログラムでは「いつ来るかわからない」「いつ終わるかわからない」と言った事象(イベント)を待ち合わせることは多々あります。メインフレームでもイベントが発生・終了するまで、来たか?来たか?、終わったか?終わったか?、とループしてタイミングを合わせる方法がありますが、一般のプログラムでは使いません。OSであってもループによるタイミング合わせは本当に必要な所だけに限定して使っています。
MVSはイベントの完了の待ち合わせにWAIT、イベントの完了の通知にはPOSTと言うサービスを提供しています。プログラムはこのサービスを使うことで、ループなどしなくても、必要なイベントの発生や終了のタイミングを合わせることができます。

上に挙げたこれらの例も、いつ発生するかわからない事柄です。インターバルタイマーに関しては例えば10秒後と言う時間はわかっていても、いつが10秒後なのかわかりません。人間は時計を見ながら10秒後を知ることができますが、これはループと同じです。オペレーターコマンドや端末の受信データはわかりやすいでしょう。いつコマンドが入力されるか、いつ実行(エンター)キーが押されるかは人間様次第です。I/O動作の完了やJCLのサブミットの待ち合わせはOSに取っての待ち合わせ事象の1つです。チャネルで実行されたI/Oはいつ完了するかわかりません。JCLは人間がコマンドやパネルでサブミット操作を行いますが、OSにしてみれば、それがいつ行われるかまったく予測できません。
これらのようにいつ起きるかわからない事を非同期事象(asynchronous event)と呼びます。バッチ処理用のアプリケーション・プログラムを作るだけではなかなかわかりにくいのですが、MVSは基本的にイベント駆動型のソフトウェアです。さまざまな非同期事象の発生を待ち受け、それに応じた処理をディスパッチします。このサイクルを延々と繰り返して行くわけです。


タイマーによるインターバル時間の経過を待ち合わせる(WAIT)

WAITマクロはイベントの完了を待ち合わせます。WAITマクロではどのイベントかを識別するため、ECBと言う1ワードの領域を使用します。ECBの先頭のビット0をWAITビット、ビット1をPOSTビットと呼びます。WAITマクロを発行するためにはECBを用意し、ビット0をクリアーしておかなければなりません。サンプルではビット0のクリアーではなくMVIでバイト毎クリアーしていますが、これも一般的な方法で非同期事象の開始前であることがはっきりしている時は、その時点ではこのECBにPOSTするプログラムは存在しないためPOSTビットも含めて0クリアーしてかまいません。XC命令でワード毎クリアーしてもかまいません。
イベントの識別と言ってもややこしい規約があるわけではなく、単に待ちになる側と、完了を伝える側でどこにECBがあるかがわかっていればいいのです。複数のイベントを並行して取り扱うような場合、それぞれのイベントをどのECBを使って待ち合わせるかを取り決める、と言うことです。一般的にはWAITする前にECBのアドレスを、実際に非同期事象を実行する側のプログラム(POSTする側)に何らかの手段で伝えます。

WAITマクロを発行するとプログラム(タスク)は指定したECBにPOSTがなされるまで、スーパーバイザー(WAITルーチン)の中で待ち状態となります。ECBのWAITビットは1にされ、WAIT中プログラムを識別するトークン(RBアドレス)が下位3バイトに格納されます。

ECBをどこでクリアーするかは重要なことです。待ち合わせる事象が開始する前にクリアーするのが原則です。タイマーならSTIMER発行前、オペレータ応答の受け取りならWTOR発行前、データの受信ならRECEIVE要求の前です。イベントを開始させてしまってからクリアーするとタイミングによってはイベントをロストさせてしまいます。
イベントによってはWAITしようとする時点で既にPOSTされている場合もあり得ます。すでにPOST済みのECBを指定してWAITマクロを発行しても問題ありません。実際にWAITせずにすぐに発行元プログラムに戻ってきます。しかしWAITビットが1になっているECB(WAIT中ECB)を指定するとプログラムはABENDさせられます。

これは誤ったECBクリアーの例です。STIMETRマクロで指定する時刻や間隔時間にもよりますが、99%は正しく動くでしょう。しかし指定した時刻が15:00丁度である時、STIMETRマクロが15時に限りなく近い15時前での発行であった場合、STIMERマクロから復帰した時点でWKUPECBにはすでにPOSTがなされているかも知れません。指定した間隔時間が1/10秒などと言う極端に短い時間である時も、STIMERマクロから復帰した時点で実時間で1/10秒は過ぎてしまっているかも知れません。
ロジックでは無条件にECBをクリアーしていますから、その場合永遠にPOSTされないWAITに入ってしまいます。これがイベントのロストです。WAIT発行前にPOSTビットをテストして1であればWAITを迂回するロジックもありですが、この例に関して言えばそんなことをするよりはECBのクリアーをSTIMETRマクロの発行前に行えばよいのです。非同期事象はその名の通り非同期ですから指定したイベントがいつ完了するかは予測できませんが、この例では自分がSTIMERを出さない限り時間計測と言う非同期イベントは起き得ないのでPOSTされることもありません。そのきっかけとなるSTIMERマクロの前でECBをクリアーできます。


タイマーによるインターバル時間の経過を通知する(POST)

POSTマクロはWAITの逆でイベントの完了を通知します。指定したECBにPOSTビットを設定し、WAIT中のプログラムがあれば待ち状態を解きます。この時ECBのビット2?31に任意のPOSTコードを設定することもできます。省略すればビット2?31は0にクリアーされます。POSTする側は相手がWAITしているかどうかを考える必要はありません。
このサンプルはSTIMERマクロによるインターバル時間の経過の待ち合わせと通知の例です。STIMERマクロを出した後のWAITマクロによってプログラムのタスクは待ち状態になります。10秒経過するとTIMREXITルーチンが実行されます。タスクが止まっている状態でも割り込んで実行されます。このようなプログラムを非同期出口ルーチンと言います。MVSでは長時間掛かるサービスやいつ完了するか予測できないサービスの完了を通知するために非同期出口ルーチンが使われるものがいくつかあります。

WAIT/POSTはマルチタスクのプログラムで使うもの、と言うイメージがありますが、シングルタスクのプログラムでも使用するAPIによってはWAIT/POSTによる待ち合わせと通知の処理が必要になります。


複数のイベントを待ち合わせる(ECBLIST)

複数の非同期イベントを取り扱うプログラムでは、いずれかのイベントが完了したら通知してもらうようにすることもできます。サンプルでは複数のECBの内、どれか1つが完了したら通知してもらう例です。これはマルチイベント・シングルウェイトです。複数個のECBが完了したら通知してもらうようにすることも(マルチイベント・マルチウェイト)、すべてのECBが完了したら通知してもらうようにすることも(マルチイベント・オールウェイト)できます。ただしマルチウェイトの場合どのECBから完了したかはわかりません。シングルウェイトであってもWAITが解けた後に別のECBにもPOSTされることがあり得ます。同様にどのECBから終わったかはわかりません。どちらの場合であってもどのECBのイベントが終わったかは、プログラムが自分でPOSTビットの立っているECBを探す必要があります。
なおマルチイベントではWAITから復帰した後、POSTビットとPOSTコードはPOSTされたECBにのみ設定されています。POSTされたECBを含めすべてのECBのWAITビットは0になっていますが、POSTされなかったECBのPOSTコード部にはRBアドレスが設定されたままになっていることに注意してください。MVS側はECBにRBアドレスが設定されたままで再びWAITが出されても支障ありませんが、POSTされなかったECBはECBワード自体が0(あるいはWAIT発行時の内容)になっているものと期待してロジックを作ると正しく動きません。

Filed in .基礎編

09.REXX 組み込み関数

By takao - Last updated: 火曜日, 11月 25, 2008
REXXは大量の組み込み関数で、プログラマーの負担を減らそうとしています。関数ライブラリーはREXXでも作れますし、多くのプロダクトが提供していたりもします。
ここでは、個々の関数について、マニュアルのような解説はしません(できません)。適当に分類してみたので、「あー、こんな関数があるのね」と頭に留めておいて、必要な都度、マニュアルを調べてください。

文字列
* ABBREV (Abbreviation)
* CENTER/CENTRE
* COMPARE
* COPIES
* DBxx (Double-Byte Character Set Functions)
* DELSTR (Delete String)
* DELWORD (Delete Word)
* FORMAT
* INSERT
* LASTPOS (Last Position)
* LEFT
* LENGTH
* OVERLAY
* POS (Position)
* REVERSE
* RIGHT
* SPACE
* STRIP
* SUBSTR (Substring)
* SUBWORD
* TRANSLATE
* TRUNC (Truncate)
* WORD
* WORDINDEX
* WORDLENGTH
* WORDPOS (Word Position)
* WORDS
* VERIFY
* XRANGE (Hexadecimal Range)
制御
* ADDRESS
* ARG (Argument)
* CHARIN (Character Input)
* CHAROUT (Character Output)
* DIGITS
* LINEIN (Line Input)
* LINEOUT (Line Output)
演算
* ABS (Absolute Value)
* BITAND (Bit by Bit AND)
* BITOR (Bit by Bit OR)
* BITXOR (Bit by Bit Exclusive OR)
* B2X (Binary to Hexadecimal)
* C2D (Character to Decimal)
* C2X (Character to Hexadecimal)
* D2C (Decimal to Character)
* D2X (Decimal to Hexadecimal)
* MAX (Maximum)
* MIN (Minimum)
* RANDOM
* X2B (Hexadecimal to Binary)
* X2C (Hexadecimal to Character)
* X2D (Hexadecimal to Decimal)

検査
* CHARS (Characters Remaining)
* CONDITION
* DATATYPE
* DATE
* ERRORTEXT
* FORM
* FUZZ
* LINES (Lines Remaining)
* QUEUED
* SIGN
* SOURCELINE
* STREAM
* SYMBOL
* TIME
* TRACE
* VALUE
Filed in REXX入門

06.2CSECT名でプログラムのローディングを行う

By kamii - Last updated: 月曜日, 11月 24, 2008

LOADマクロでのローディングや、LINKマクロでの呼び出し時にEP/EPLOCで指定できる名前はロードモジュールのメンバー名です。CSECT名でのローディングや呼び出しはできません。動的構造のプログラムでCSECT名を使ってモジュールにアクセスするには少し工夫が必要です。


ロードモジュールの先頭にアドレスポインターフィールドを作る

いろいろなプログラムで使うさまざまな共通サブルーチンを1つのロードモジュールにまとめあげたライブラリーモジュールを作る場合、バインダーで連携編集されるモジュールのすべてのCSECTに先だってサンプルのようなV型アドレス定数(VCON)のフィールドを作ります。ここの部分のCSECTはなくてもかまいませんが、わかりやすくするためにもロードモジュールと同じ名前などでCSECTの定義をしておきましょう。結合したCSECT名を指定したVCONを必要なだけ並べます。最初のCSECTの前に定義してもいいですが、サブルーチンの数が多くきちんと管理するならば、VCONだけのソースメンバーを作った方がいいでしょう。

サンプルのJCLでバインドすれば、バインドされたロードモジュール名をCOMMSUBRとした場合、LOADマクロでロードされたCOMMSUBRの入口点アドレスがサンプルのCOMMVCON CSECTになります。先頭から+0番地の1ワードがSUBRTN1のアドレスが入ったポインターになり、先頭から+4番地の1ワードがSUBRTN2のアドレスが入ったポインターになります。SUBRTN2を呼ぶ場合はCOMMSUBRの先頭+4番地の内容をロードすればそれがSUBRTN2の入口点アドレスです。直接SUBRTN2の名前でLOADすることはできませんが、ロードしたモジュール内ののCSECTの位置はこのような方法で求めることができます。
このようなVまたはA型アドレス定数で他のモジュールやデータ・テーブル領域などをポイントするポインターフィールドの集合を「ベクターテーブル」と呼びます。


ロードモジュールにCSECT名のALIASを付ける

最初の方法と異なりLOADマクロで直接CSECT名を指定できるようにする方法です。バインダーのALIAS(別名)機能でロードモジュールに別名を付けます。ALIAS制御文にCSECT名を指定すれば、それがそのまま別名になります。この例ではロードモジュール・ライブラリー内にはCOMMSUBR主メンバー名の他にSUBRTN1,SUBRTN2,SUBRTN3の副メンバー名が作成されます。

プログラムがLOADマクロのEP/EPLOCでSUBRTN2を指定すれば、ロードモジュール自体はCOMMSUBRがローディングされますが、入口点アドレスにはSUBRTN2のCSECTアドレスが通知されます。特定のCSECT部分だけを抜き出してロードすることはできませんが、指定したCSECTのアドレスを通知してもらうことはできます。なおGR1で通知されるモジュール・レングスもロードモジュール全体の長さであって、CSECT部分の長さではありません。

Filed in 中級編

06.1プログラムのローディングと実行(LOAD,LINKとXCTL)

By kamii - Last updated: 月曜日, 11月 24, 2008

プログラムのローディングと実行は、一般のプログラムでも身近な機能です。規模の大きなプログラムでは複数のモジュールに分割して開発・管理・保守が行われます。複数のモジュールで構成されるプログラムの処理に関するMVSの機能を解説します。


MVSにおけるプログラムの構造


再入可能(リエントラント)プログラム

単純構造や動的構造に関係なくプログラム・デザインに関するもので、複数のタスクで同時に実行できるプログラムのことです。リエントラント(reentrant)構造プログラムとも呼ばれます。プログラムが処理に使うデータの内、更新を伴うものをプログラム内部に置いていない設計になっているものです。端的な例がレジスター保管域です。レジスター保管域をプログラム内に置いたプログラムが同時に複数のタスクで実行されると、タスク1がそのプログラムでサブルーチンAを呼び出し、そのサブルーチンが実行中に、タスク2でも同じプログラムが実行されサブルーチンAが呼び出されると、最初に呼び出されたタスク1のレジスター保管域は後から呼び出されたタスク2のサブルーチンAによって上書きされてしまいます。そうなるとタスク1で最初に呼び出されたサブルーチンAは元の呼び出し元に正しく戻れなくなってしまいます。
これは同じ領域にローディングされているプログラムを複数のタスクで共有使用する場合の問題です。同じプログラムのコピーをタスク毎に使えばこのような問題は解決しますが、メモリーの利用効率やパフォーマンスの観点で劣ってしまいます。特にあらゆるプログラムから頻繁に利用されるシステムの共通機能ルーチンのようなものでは顕著です。そこでこのような問題を解決するために、レジスター保管域など書き込みされるデータ領域をプログラムの外に置き、タスク毎にGETMAINして使用すればデータ領域は他のタスクによって壊されることがなくなります。プログラムの命令コード部分と書き込みされるデータ領域を分けた設計になっているプログラム・モジュールを再入可能プログラム、再入可能モジュールと呼びます。

なお再入可能プログラムのように複数のタスクで同時に使用することはできないものの、データ領域をプログラムの先頭で初期化するような処理を持ち、順番に1タスクずつなら同じ領域のプログラムを実行することができるものは逐次再使用可能(reusable)プログラムと呼びます。



単純構造プログラムにおけるサブルーチンの呼び出し

単純構造プログラムではサブルーチン(他のモジュール)はCPU命令で直接呼び出すことができます。リンケージ規約に則ればGR15に呼び出すモジュールの入口点アドレス、GR14に戻りアドレスを格納して、入口点アドレスへ分岐します。BASR(BALR)命令をサンプルのようにコーディングすればいいのです。サンプルではGR1にパラメーター・アドレスをセットしています。パラメーターはアドレスパラメーター・リスト形式で渡していますが、呼び出す側と呼び出される側で合意すればどんな形式で渡してもかまいません。アドレスパラメーター・リスト方式はパラメーター数が少ないときは面倒ですが汎用的な方法なので、他の言語で作成されたプログラムとリンケージを取るような場合にも適しています。

2番目のサンプルは最初のサンプルとまったく同じことを、CALLマクロ命令を使って行うものです。呼び出すモジュールの入口点アドレスフィールドやパラメーターリストなどはCALLマクロの中で自動生成されます。CALLマクロはスーパーバイザーのサービスを呼び出すAPIではなく、機能に対応するCPU命令列をプログラマーに代わり生成するものです。COBOL言語を主に使うプログラマーには比較的理解しやすい方法です。
最初に呼び出すプログラムの入口点名(CSECT名)の名前または入口点アドレスを格納したレジスター番号(15)を指定し、続いてプログラムへ渡すパラメーターが格納されている領域の名前を()括弧でくくって指定します。VLはパラメーター・リスト上の最後のパラメーターを示すエントリーの先頭ビットを1にするパラメーターです。最終パラメーターのエントリーの先頭ビットを1にする必要があるかどうかは、プログラムの呼び出しインターフェースによって決まります。

3番目は呼び出されるプログラムで利用できる関連マクロを紹介します。SAVEマクロはプログラムの先頭で呼び出し元のレジスターを保管する命令を展開します。ただし自プログラムのレジスター保管域の定義や呼び出し元プログラムのレジスター保管域とのチェインを行う命令は生成されません。サンプルでは省略していますが、必要な処理は自ら行わねばなりません。
サンプルのように,,*を追加指定すると、CSECT名をプログラム中に埋め込みます。これはプログラム・ヘッダーあるいはeye catcherとも呼ばれ複数のCSECTで構成されるプログラムのダンプを見るときに、どのモジュールかを判別しやすくするために行われるものです。規模の大きなプログラムや商用プログラムでは、さまざまな情報を持つヘッダーが作られることも多く、プログラム・デザインの1つでもあります。
RETURNはSAVEマクロの逆で呼び出し元レジスターを保管域から復元して、呼び出し元へ復帰する命令を展開します。
CALL、SAVEおよびRETURNはサブルーチンを呼び出したり、プログラムのハウスキーピング処理を行うためのアシストマクロですが、必ずしも使わなければならないものではありません。特にSAVEとRETURNマクロは自分で直接命令を書いてもさほど違いはありませんが、一般的にはよく利用されていますから、使い方を知っていれば、他の人が書いたプログラムを追う場合などで役に立ちます。


動的構造プログラムにおけるモジュールのローディング

動的構造のプログラムでは呼び出すモジュールは各々が独立したメンバーになっているため、CPU命令だけでは呼び出すことができません。呼び出す前にLOADマクロを使ってあらかじめリージョン内にローディングしておきます。ローディングされたモジュールの入口点アドレスはGR0に返されます。モジュールがローディングされた後は、単純構造のプログラム同様にBASR命令やCALLマクロで呼び出すことができます。使用し終わったローディング済みモジュールはDELETEマクロでリージョン内から消去します。(再入可能あるいは再使用可能なモジュールは呼び出しの都度でなく、これ以上呼び出す必要がなくなった時点でDELETEすればよい)
サンプルではPLISTをCALLマクロのリスト形式を使って定義しています。DC A(name)命令の代わりに利用したものです。

2番目は動的リンクの例です。この動的リンクはアプリケーション自らがやっており、MSPがアシストする動的リンク構造ではありません。どのOSにも共通に利用できる方法です。LOADマクロを出す前にサブルーチンの入口点アドレスをテストします。0でなければすでにローディング済みなのでLOADは迂回します。0ならば初回なのでLOADマクロを発行してローディングします。モジュール名は名前を直接指定するのではなく、EPLOCパラメーターで名前を格納した領域アドレスを指定する方法を使っています。ERRETパラメーターはローディングに失敗した場合に実行されるルーチンのアドレスです。失敗するとここで指定したラベル箇所(アドレス)に飛び込んできます。ERRETを指定しないとローディングに失敗した場合プログラムはAEBNDします。ERRETルーチンに飛び込んできた時のGR1にはABENDコードが入っています。


動的構造プログラムにおけるサブルーチンの実行

LINKマクロはモジュールをローディングして呼び出します。CALLマクロの動的構造プログラム版と言ってもいいでしょう。LOADマクロはロードモジュールをメモリーにローディングするだけですが、LINKマクロはローディング+呼び出し、となります。呼び出すプログラムの処理が終わるとロードモジュールはメモリーから消去されます。
PARAMパラメーターは呼び出すプログラムに渡すパラメーターを指定します。CALLマクロにおけるパラメーター渡しと同様の指定を行います。VL=1もCALLマクロのVLパラメーターと同じ意味です。

2番目の例はLOADマクロ発行後にLINKマクロを発行する例です。このLINKではその前にLOADを発行していますのでモジュールは改めてローディングされません。ロード済みモジュールが使われます。しかし3番目の例では注意が必要です。2回目のLINKマクロではモジュールが改めてローディングされてしまいます。そして呼び出したプログラムが終了し、LINKマクロの処理が終了すると改めてロードされたモジュールのみが消去されます。このような動きは呼び出すモジュールがRENT,REUSのどちらの属性も持たない場合に起きます。モジュールにRENT,REUSいずれかの属性があればローディング済みのモジュールは共用されます。またREUS属性のモジュールは複数のタスクで同時に実行できないので、複数のタスクからLINKが発行されると、先にLINKマクロを発行したタスクでのモジュールの処理が終了するまで、他のタスクのLINKはスーパーバイザー内で待たされます。この待ち合わせにはENQは使用されていませんので、REUS属性のモジュールをLINKマクロとBASR等による直接CALLを混在して呼び出すことは危険です。LINKマクロに統一する方が間違いありません。

REUSモジュールでなければLOADとCALLの組み合わせがパフォーマンスの面でも優れています。実戦では本当の意味での逐次再使用可能モジュールをプログラムとして作ることは稀です。バッチ処理のようにシングルタスクのプログラムならREUSもRENTも必要ありませんし。マルチタスクならば再入可能プログラムの方が一般的です。わざわざ同時並行での実行を目的にタスクを分けているのに排他制御されてしまうREUSモジュールを作ることは設計に矛盾が起きてしまいます。REUSモジュールはどちらかと言えば、プログラムそのものよりはプログラムで使用するテーブルデータなどを作るために使われる方が多いでしょう。名前がわかっていればLOADマクロによって入口点アドレスが求められます。REUSならば複数のタスクでLOADされても空間内での初回のLOAD時のみディスクからモジュールがロードされ、2回目以降は同じアドレスが通知されます。なお1つのロードモジュールをDELETEせずにLOADマクロを出せる上限回数は32767です。これは知っておくべき事です。


動的構造プログラムにおける他プログラムへの実行切り替え

XCTLマクロはLINKと異なり、呼び出したプログラムが終了しても自分に戻ってきません。呼び出したプログラムが終了した後は、自分ではなく自分を呼び出した親モジュールに直接戻ります。サブルーチンの処理が長く複数のモジュールに分割する場合や、機能に応じて処理モジュールを分割する場合などに利用できます。XCTLを発行するとEP/EPLOCで指定したモジュールに制御が渡った時点で自分自身のモジュールは他のタスクで使用中でなければ消去されます。(r1,r2)パラメーターで自分が呼び出されたときのレジスターを復元することができます。r1は2以上、r2は12以下で連続した範囲のレジスターがXCTLマクロ発行時点のGR13が示すレジスター保管域から復元されます。GR1は復元できないのでXCTLマクロ発行前に必要な値をセットします。GR0は引き継ぐことができません(実際に大丈夫だとしても保証されているわけではない)。GR13は自分を呼び出した親モジュール(呼び出し元)の保管域をポイントしておきます。


プログラムの終了(SVC 3:EXIT SVC)

マニュアルには載っていませんが、プログラムの終了はSVC 3によって行われます。リンケージ規約ではGR14が呼び出し元への戻りアドレスを示しますが、JCLのEXEC文のPGMパラメーターで指定され実行されたロードモジュールやLINK/XCTLマクロによって呼び出されたロードモジュールの入口点では、GR14が示す戻りアドレスはOSのコントロールブロックCVT内にあるSVC 3命令をポイントしています。なのでBR 14命令で戻る代わりにSVC 3命令を直接コーディングすることもできます。ただしBASR(BALR)命令で呼び出されたプログラムはSVC 3を使ってはなりません。呼び出し元へ戻らずにプログラムは終了してしまいます。BR14かSVC3かを考えて使い分けるのは現実的ではありませんので、基本通りBR 14でいいのですが、スーパーバイザーを経由して呼び出されたモジュールは戻る際もスーパーバイザーを経由する必要があります。戻るときはマクロではなくBR命令で戻っていますが、実際には分岐先にあるSVC 3命令が実行されてEXIT SVCが呼び出されスーパーバイザーを経由して呼び出し元へ戻っているのです。

サンプルはSVC 3命令でプログラムを終了させるものです。呼び出し元に戻った時のレジスターはSVC 3命令発行時の内容と同じです。プログラムを終了する場合はレジスターを復元しなくてもMVSがおかしくなるようなことはありませんが、LINKやXCTLマクロで呼ばれた場合、レジスターをきちんと復元しないと、戻った後で呼び出し元は正しく動くことができません。

Filed in .基礎編

05.2ダンプの書き出しとトレースの記録(SNAPとGTRACE)

By kamii - Last updated: 金曜日, 11月 21, 2008

プログラム(リージョン)のダンプを取得するにはDUMPオプション指定のABENDマクロを発行する方法があります。しかしABENDマクロではプログラムの実行はそこで終わってしまいます。プログラムを終わらせずにダンプを取るには自らストレージの内容を編集してデータセット(SYSOUT)に書き出すこともできますが、SNAPサービスを使えば簡単にダンプを取ることができます。またダンプはエラーが起きた時点でのスポットな診断情報ですが、エラーの内容によっては、プログラムの動きやデータの変化を時系列に記録したい場合があります。これはトレースと呼ばれます。トレースもGTRACEマクロで簡単に記録することができます。


プログラムの状態やストレージの内容をダンプする

SNAPマクロはストレージ・ダンプを取得します。ダンプリストはDCBパラメーターで指定したDD文で定義したデータセットに書き込まれます。サンプルではDD名SNAPDUMPとしていますが任意の名前でかまいません。SNAPマクロ発行前に出力先データセットはあらかじめOPENしておかなければなりません。ダンプの出力が終わったらCLOSEします。DCBはサンプルのように定義します。サンプルでは各マクロ命令のエラーをチェックしていませんが、必要に応じてエラー処理を組み込みます。

1番目のサンプルは自分のプログラム領域をダンプする例です。ただしGETMAINした領域はダンプされません。GETMAINした領域のダンプが必要な場合は、PDATAパラメーターにSPLSを追加します。
2番目のサンプルは自分のプログラム領域を含めリージョン全体をダンプする例です。OSのコントロールブロックはフォーマットされるだけでなく、割り当てられている領域自体も出力されます。SDATAおよびPDATAパラメーターはMVSの例です。MSPとVOS3では若干異なるのでマニュアルで確認して下さい。
3番目のサンプルは指定したストレージ領域をダンプする例です。ダンプしたい領域の開始および終了アドレスを指定しています。
4番目のサンプルも指定したストレージ領域をダンプする例です。ダンプしたい領域の開始および終了アドレスをパラメーターではなく、リストで指定しています。リストはダンプしたい領域の開始・終了アドレスのペアーを複数個並べたものです。(ラベルSTORLIST)この例では3つの領域をダンプするので開始・終了アドレス×3で6ワードを使います。SNAPルーチンが最後のエントリーを判別するため、最終エントリーの終了アドレスの先頭ビットを1に設定します。MVSではSTRHDRパラメーターでダンプする領域に対応する見出し文字列を指定することもできます。見出しは1バイトの長さ+タイトル文字列で構成されます。

OSのスーパーバイザー・ルーチンや出口ルーチンなどでダンプを取る場合は、SNAPマクロではなく、SDUMPマクロを使いSYS1.DUMPnnデータセットにSVCダンプを書き出します。システムプログラムであっても起動JCLがあればDD文が定義できますから、SNAPマクロは利用されます。しかしOS出口ルーチンのように不特定の空間で動作するものやシステム空間で動作するものはDD文を定義できませんので、SDUMPサービスによるSVCダンプが使われます。SDUMPマクロはAPF許可プログラムやスーパーバイザーモードのプログラムでなければ利用できません。


GTFにトレースレコードを書き込む

GTRACEマクロはGTFトレースデータセットに、ユーザートレースレコードを書き込みます。OPENもCLOSEもDCBも必要ありませんし、ある意味QSAMより簡単です。書き込み可能なデータの長さはOSによって異なります。(サンプルコードを見て下さい)VOS3では正式なマクロ名はETRACEですが、GTRACEでも利用できます。

トレースレコードを書き込むにはEID(EVENT ID)を決める必要があります。ユーザープログラムでは0?1023が指定できます。特に規約などがなければ1023でいいでしょう。FIDと言う、レコードを編集するときの識別番号(編集するプログラムを決める識別子)もありますが省略してかまいません。(FID=0とする)この場合IPCSやPRDMPでフォーマットする際、レコード内容はダンプ形式に編集されます。文字で構成されたレコードなら、わざわざOSのユーティリティでフォーマットしなくても、GENERでSYSOUTにコピーしても判別することができます。
正しく書き込めればGR15に復帰コード0が返ります。復帰コード4はGTFが起動されていないことを示します。8以上は基本的にパラメーターエラーです。復帰コードが32の場合、書き込むデータがページアウトされていたことを示します。これを防止するにはパラメーターPAGEIN=YESを指定します。(MVSとVOS3のみ)トレースデータ領域がページアウトされていた場合、ページインして書き込めるまでリトライします。絶対にロストしたくないレコードならPAGEIN=YESを指定します。よほどページングがヘビーなシステムでなければGTRACEを発行する前に書き込むデータを作るか触るかしておけば大丈夫でしょうが、気になる方は指定して下さい。マクロの展開形を見ればわかりますが、復帰コードが32ならデータ領域を一旦参照して(ページインされる)から書き込みをリトライします。

GTFにレコードを書くのは実は簡単です。MC命令で直接書き込むことができます。(実際はプログラム割込み:モニターイベントを起こし、割込みハンドラー経由でGTF空間にトレース書き込みを依頼する)わざわざGTRACEマクロを使わなくても直接CPU命令で行ってもかまいません。2番目のサンプルがGTRACEを使わず直接命令で行うものです。問題プログラム状態で利用できます。MVSではGTRACEマクロはAPF許可プログラム用のAPIマニュアルに記載されていますが、実際はAPF許可は不要です。
GTFの起動方法は以下にサンプルを示します。USR=3FFの3FFはEID=1023の16進数指定です。GTFに関してはマニュアルあるいはGTFトレースの採取とフォーマットを参照して下さい。

Filed in .基礎編

08.REXX自身の制御

By takao - Last updated: 金曜日, 11月 21, 2008
今回は、REXX自身への命令について書いてみます。

DROP

後ろに記述した変数を「なかったもの」にしてくれます。大きな配列などを使った後「メモリーが心配だなぁ。」と思ったらやっておきましょう。

INTERPRET

後ろに続く文字列をREXXコマンドとして処理します。

NUMERIC

NUMERIC DIGITS 式

この指定は、数値計算の桁数を指定します。とてもありがたい機能で、電卓だとすぐにべき乗表示になるところをメモリーの許す限り、整数演算してくれます。

NUMERIC FORM

これは、キーワードだけでNUMERIC FORM SCIENTIFIC,またはNUMERIC FORM ENGINEERINGを指定します。ENGINEERINGは、「10の累乗が必ず3の倍数になる」形式だそうです。

NUMERIC FUZZ 式

式の桁だけ数値比較で桁を無視します。

OPTIONS

この指定はプログラムの最初にしましょう。
OPTIONS ETMODEと指定すると、文字列やコメントがDBCSを含むという処理をします。逆にDBCS文字列かどうかを無視する場合、OPTIONS NOETMODEと指定します。
OPTONS EXMODEは、命令、演算子、関数においてDBCS文字列として処理します。OPTIONS NOEXMODEとすると、すべてをバイト単位で処理します。

TRACE

デバッグのトレースです。後ろには、
All – すべてを実行前にトレース
Commands – コマンドを実行前にトレース
Error – 実行の結果、エラーを起こしたコマンドについて表示
Failure – 障害発生したコマンドがあれば、表示
Intermediates – 式の結果、中間結果、置換された名前なども表示
Labels – 実行中、通過したラベルをトレース
Normal – 負の戻りコードだけを出力(これがデフォルト)
Results – すべての式の評価結果を表示します。トレースする際には、これが期待にこたえると思います。
Scan – 実行はせずにトレースするので、シンタックスチェックに近いです。
? – デバッグが対話式になります。

以上で、いわゆるREXXコマンドについてはひととおり説明をしました。
Filed in REXX入門

ロードモジュールの情報を得る(AMBLIST)

By kamii - Last updated: 金曜日, 11月 21, 2008

AMBLISTユーティリティはロードモジュールの属性や内容を編集して出力します。アドレスモード、入口点の位置、リエントラントなのか、APF許可を必要とするか、などのモジュール属性とどのようなモジュール(CSECT)によって構成されているかのマップとクロスリファレンス情報、いつコンパイル(アセンブル)されいつリンケージされたか、どのようなプログラム修正が適用されているか、などの識別レコード情報、さらにロードモジュール内容(命令コードとデータ)を出力することもできます。

AMBLISTユーティリティJCLサンプル

LISTLOADはロードモジュールのマップ情報とレコード内容を出力します。OUTPUTパラメーターでXREFを指定した時は、ロードモジュール属性とマップおよびクロスリファレンス情報を、OUTPUTパラメーターでMODLISTを指定した時は、ロードモジュール属性とレコード内容を編集して出力します。BOTHは両方の出力です。
LISTIDRはロードモジュールのIDRレコードを編集して出力します。モジュールの翻訳日、作成日、適用されているプログラム修正名を知ることができます。
LISTLPAはLPAに展開されているロードモジュールの名前、アドレスと大きさ、入口点をマップしたリストを出力します。

Filed in ありがたいサンプルJCL

SMFデータセットのアンロード(IFASMFDP)

By kamii - Last updated: 金曜日, 11月 21, 2008

SMFデータセットのアンロードJCLサンプル

SMFデータセットを順次データセットにアンロードします。SMFデータセット内のすべてのレコードがアンロードされます。TYPE(0:255)
入力元SMFデータセットの内容はクリアーせずにそのまま残します。ACTIVEなSMFデータセットでもアンロードは可能です。日付や時刻でアンロードするレコードを絞り込むこともできます。日付ならMVSではDATE(2008001,2008031)、MSPではDATE(080101,080131)のように制御文に追加します。
MSPではプログラム名はKDKSMFDPとなります。なおVOS3ではまったくJCLが異なりますのでSMSのマニュアルを参照して下さい。


アンロードするレコードを、レコード・タイプで選択し出力先データセットを振り分けることもできます。その場合はOUTDD制御文を複数個定義し、レコード・タイプに対応した出力先DD名を指定します。
サンプルではレコード・タイプ30をWORK.SMFMANX.UNLOAD.REC30へ、レコード・タイプ60番台をWORK.SMFMANX.UNLOAD.REC60へアンロードします。


Filed in ありがたいサンプルJCL

ありがたいOSコマンド集(SLIPコマンド)

By kamii - Last updated: 木曜日, 11月 20, 2008

SLIPコマンド設定状況の表示


SLIPコマンド・サンプル集


複数のメモリー範囲にSAトラップを掛ける例

Filed in システムプログラマーのための手引きいろいろ

TSO/TESTコマンドによるデバッグ

By kamii - Last updated: 木曜日, 11月 20, 2008

TSOのTESTコマンドはMVSにおける標準デバッガーです。WindowsやUnixのビジュアル開発ツールのような多機能なデバッガーではありませんが、アセンブラー言語のプログラムのちょっとしたデバッグには結構役に立ちます。レジスターやメモリー領域の表示、ブレークポイントの設定など基本的なデバッグができます。
※TESTコマンドはISPFのコマンドシェル・パネル(オプション6)では実行できません。ネイティブなTSOコマンドプロンプトから実行します。


TESTコマンドを使ってプログラムを起動する

TESTコマンドで実行したいプログラムを、’格納されているロードモジュールライブラリー(メンバー名)’で指定します。起動後、プログラムは入口点(先頭の命令)でブレークした状態になり、TESTのサブコマンド入力待ちになります。


サブコマンド(プログラムを実行する)

GOコマンドはブレークしている場所からプログラムの実行を行います。次のブレークポイントを見つけるか途中でABENDするとそこで停止します。最後の命令を実行するとプログラムは終了します。WHEREコマンドで現在どこでブレークしているかがわかります。ENDコマンドでTESTコマンドを終了します。
プログラムの中でWTOマクロを使っている場合、メッセージはコンソールだけでなくTSO端末にもエコーされます。


サブコマンド(レジスターやメモリー内容を表示する)

LISTMAPは仮想記憶の割り当て状態のサマリーを表示します。プログラム自身がGETMAINしていなくても、TSOおよびTESTコマンドが制御のために割り当てた領域も含まれます。LISTPSWは現在のPSW内容を編集して表示します。

LISTコマンドはレジスターやメモリー領域の内容を表示します。
1Rはレジスター1の内容を、0R:15Rは全てのレジスターの内容を表示します。メモリーの内容はアドレスまたはラベル名で表示できます。アドレスは16進数で指定し末尾に.(ピリオド)を付けます。LENGTHパラメーターで長さを指定できます。省略すると4バイトだけしか表示されません。XCは表示タイプで16進数(HEX)と文字(CHAR)の両方が表示されるダンプ形式です。LENGTHパラメーターに代えてアドレスとアドレスを:(コロン)で繋げば、そのアドレス範囲のメモリー内容を表示できます。メンバー名.CSECT名とすればプログラムの先頭から表示できます。+xxxxのようにプログラムの先頭からの相対アドレスで表示することもできます。この場合は末尾にピリオドは付けません。
ラベル名はソースプログラム内に書いたラベル名です。ラベル名を使う場合はアセンブルおよびバインド(リンクエディット)両方のパラメーターにTESTオプションを指定する必要があります。TESTオプションによってソースプログラム中のラベル名などのシンボル情報がオブジェクトとロードモジュールに出力されます。

アドレスは直接指定の他にレジスターを使った間接アドレスでも指定できます。12R%のようにRの後ろに%を置くと、そのレジスターの内容をアドレスとするメモリーの内容を表示します。


サブコマンド(レジスターやメモリー内容を変更する)

レジスターやメモリーの内容は表示するだけでなく、変更することもできます。もちろん変更できるのは自分のプログラムまたはGETMAINした領域です。割り当てられている領域はLISTMAPコマンドで確認できます。
nR=X’xxxxxxxx’とすれば、n番レジスターに値xxxxxxxxをロードします。+20=はプログラムの先頭からx20バイト離れたアドレス、20EF4.=はx20EF4番地のアドレスのメモリー内容を変更することになります。デバッグ中にレジスターやメモリーの内容を変えてプログラムの動きがどう変わるかを確認することができます。


ブレークポイントの設定

ブレークポイントはATで設定できます。ブレークする場所をラベル名、プログラムの先頭からの相対アドレスで指定できます。Cパラメーターは通過回数カウンター値です。3と指定すれば3回目にそこを通過する時ブレークします。ここでカウンターがリセットされるのでループが続くと、さらに3回目の通過で再びブレークします。つまり3,6,9と3の倍数回目で止まります。2であれば偶数回数目、10であれば10,20,30回目になります。Cパラメーターを使うとループの中にブレークポイントを設定する時、いちいちプログラムが止まらなくなるのでデバッグ効率が上がります。なおブレークは設定できますが、1命令ずつ止めるステップ実行はできないので、必要に応じてブレークポイントを細かく設定します。
ブレークする箇所の後ろに、ブレークと同時に実行するコマンドを指定することもできます。2番目のサンプルではブレークしたら同時にその時点のPSWとレジスター0から15の内容を表示します。

TESTコマンドはブレークする箇所にSVC 97と言う命令(x0A61)を埋め込みます。そのため命令コードやオペランドそのものをデータとして処理しているようなプログラムは正しく動かなくなりますから注意が必要です。

太字箇所が命令オペランドがデータとして参照されているものです。サンプルのようにWAITマクロを書いてアセンブルして見ればよりわかりやすいでしょう。

Filed in S/370アセンブラー講座

05.1プログラムをABENDさせる(ABEND)

By kamii - Last updated: 木曜日, 11月 20, 2008

実行中にデータやパラメーターの誤りを見つけた時、自ら論理の矛盾やデータの不整合がわかった時、プログラム自ら途中で処理を止めて実行を中止することがあります。原因や理由が明確ならばメッセージやログデータによってそれを指摘した上で完了コードを設定して終了することもできます。しかしエラーが起きたことはわかったが、原因や理由はわからない場合、プログラムは自分自身を異常終了させるようOSに要求することができます。アベンドすべきかノーマルエンドすべきかの基準はありませんので、デザイナーが自由に決められます。わからなければ他のソフトウェアがどうしているかなどを参考にするのもいいでしょう。


プログラムをABENDさせる?

ABENDマクロはプログラムの異常終了を行います。ABENDマクロはほとんどが定位置パラメーターです。1番目のパラメーターは完了コード(ABENDコード)を指定します。2番目がダンプを出力するかどうか、3番目がサブタスクがABENDマクロを発行する時、自タスクだけがABENDするのかジョブステップ全体をABENDさせるかの指定です。シングルタスクのプログラムではどのみちステップは終了します。

最初の例は完了コードU0001でABENDさせます。2番目の例は完了コードをレジスターに入れて指定しています。ABEND時にダンプの出力を行います。プログラムを実行するJCLにはSYSUDUMP,SYSABENDあるいはSYSMDUMP DD文の定義が必要です。ABENDマクロによるダンプ要求ではダンプの出力先データセットをあらかじめOPENしておく必要はありません。3番目の例はダンプは出力せずにジョブステップごと終了させます。ダンプを出力するならDUMP,STEPと指定できます。

ABENDコードは0?4095が指定でき、Unnnnの形式で表示されます。Sxxx形式のコードを指定することもできますが、MVSのABENDコードと混同するので特別な理由が無い限りシステムABENDコードは使わない方がいいでしょう。



プログラムをABENDさせる?

ABENDマクロを使わないで、プログラム割込みによる方法です。
システムプログラムではしばしばわざと誤った命令を実行してABENDさせる方法が採られます。最初の例は奇数レジスターを指定した除算です。DR R1,R1と書くのと同じですが、アセンブラーが構文チェックをするのでDC命令で命令コードを直接書き込みます。2番目の例はEX命令で自分自身を指します。どちらも意図的に行わない限り起き得ないABENDなので、「何かエラーを見つけてわざとそこでABENDさせたんだな」と言うことを伝えられます。
昔こう言った手法をがあることを知らない頃は「これ書いた奴ってバカじゃないの?」なんて思ったことがありますが、バカなのは私でした。

なお故意によるプログラム割込みでABENDさせる時は、S0C1やS0C4あるいはS0C7,S0C9と言った、本当のバグや誤ったデータによって起きるABENDと混同してしまうコードを使うのは避けましょう。

Filed in .基礎編

ファイル転送を行う(FTPクライアント)

By kamii - Last updated: 水曜日, 11月 19, 2008

FTPクライアント実行JCLサンプル(MVS)

メインフレームではFTPはサーバーとして利用されることが多いですが、FTPクライアントも利用できます。特にバッチのジョブ・ステップとして実行すれば、転送作業を自動化したり、他のステップの処理と連動させたりできますから、覚えれば便利な機能になります。メインフレーム←→PC間で利用する場合、相手側PCにはFTPサーバーが必要です。


FTPクライアント実行JCLサンプル(MSP)

MSPではFTPクライアントを使用するにはアトリビュート・データセットを作成しておく必要があります。このデータセットに接続先のホスト名(IPアドレス)とユーザーID・パスワードをあらかじめ登録しておかなければなりません。TSSセッションで直接使うならアトリビュート・データセットは不要だったかも知れません...


FTPクライアント実行JCLサンプル(VOS3)

VOS3のFTPクライアントのサンプルです。VOS3の方はMVSに近いもの(と言うよりは標準のFTPに)があります。

Filed in ありがたいサンプルJCL