日本-日本語

製品  >  ソフトウェア  >  OpenVMS  >  マニュアル

OpenVMS マニュアル


≫ 

OpenVMS V8.3
ライブラリ

タイトルページ
目次
まえがき
第 1 章:移行プロセスの概要
第 2 章:移行方法の選択
第 3 章:アプリケーションの移行
第 4 章:再コンパイルと再リンクの概要
第 5 章:ページ・サイズの拡大に対するアプリケーションの対応
第 6 章:共有データの整合性の維持
第 7 章:アプリケーション・データ宣言の移植性の確認
第 8 章:アプリケーション内の条件処理コードの確認
第 9 章:アプリケーションのトランスレート
第 10 章: ネイティブなイメージとトランスレートされたイメージの間の相互操作性の確認
第 11 章:OpenVMS Alpha コンパイラ
付録 A :アプリケーション評価チェックリスト
用語集
索引
PDF
OpenVMS ホーム
OpenVMS Alpha オペレーティング・システム | HPE 日本

OpenVMS Alpha
オペレーティング・システム
OpenVMS VAX から OpenVMS Alpha へのアプリケーションの移行


目次 索引

たとえば, 例 5-4 に示すVAXプログラムは, 第 5.3.1 項 で作成したセクション・ファイルを既存の仮想アドレス空間にマッピングします。アプリケーションは bufferという名前のバッファを定義します。このバッファのサイズは512バイトであり,これは VAXのページ・サイズを反映しています。プログラムはバッファの1バイト目のアドレスを先頭アドレスとして,また,バッファの最終バイトのアドレスを末尾アドレスとして inadr 引数に渡すことにより,セクションの正確な境界を定義します。

例 5-4 仮想アドレス空間の定義された領域へのセクションのマッピング

#include <ssdef.h> 
#include <stdio.h> 
#include <stsdef.h> 
#include <descrip.h> 
#include <dvidef.h> 
#include <rms.h> 
#include <secdef.h> 
 
struct FAB fab; 
 
char *filename = "maptest.dat"; 
 
char _align(page) buffer[512]; 
 
main( argc, argv ) 
int argc; 
char *argv[]; 
{ 
 
     int    status = 0; 
     long   flags = 0; 
     long   inadr[2]; 
     long   retadr[2]; 
     int    fileChannel; 
 
/********  create disk file to be mapped *************/ 
 
     fab = cc$rms_fab; 
     fab.fab$l_fna = filename; 
     fab.fab$b_fns = strlen( filename ); 
     fab.fab$l_fop = FAB$M_CIF | FAB$M_UFO;  /* must be UFO */ 
 
     status = sys$create( &fab ); 
 
     if( status & STS$M_SUCCESS ) 
        printf("Opened mapfile %s\n",filename); 
     else 
     { 
        printf("Cannot open mapfile %s\n",filename); 
        exit( status ); 
     } 
 
     fileChannel = fab.fab$l_stv; 
 
/**********  create and map the section  ****************/ 
 
     inadr[0] = &buffer[0]; 
     inadr[1] = &buffer[511]; 
 
     printf("inadr[0]=%u,inadr[1]=%u\n",inadr[0],inadr[1]); 
 
     status = SYS$CRMPSC(inadr, /* inadr=address target for map */ 
                         &retadr, /* retadr= what was actually mapped */ 
                               0, /* acmode  */ 
                               0, /* flags */ 
                               0, /* gsdnam, only for global sections */ 
                               0, /* ident, only for global sections */ 
                               0, /* relpag, only for global sections */ 
                     fileChannel, /* returned by SYS$CREATE */ 
                               0, /* pagcnt = size of sect. file used */ 
                               0, /* vbn = first block of file used */ 
                               0, /* prot = default okay */ 
                               0 ); /* page fault cluster size */ 
 
     if( status & STS$M_SUCCESS ) 
     { 
           printf("Map succeeded\n"); 
           printf("retadr[0]=%u,retadr[1]=%u\n",retadr[0],retadr[1]); 
     } 
     else 
     { 
           printf("Map failed\n"); 
           exit( status ); 
     } 
 
} 

例 5-4 に示したプログラムをAlphaシステムで正しく実行するには,次の変更が必要です。

  • inadr 引数に指定するセクションの先頭アドレスがAlphaのページ境界にアラインされることと,指定する末尾アドレスがAlphaページの末尾にアラインされることを確認しなければなりません。

  • Alphaシステムの大きいページをマッピングするときに,隣接データの上に重ね書きされないことを確認しなければなりません。

これらの目標を達成するための1つの方法として, SOLITARYプログラム・セクション属性を使用することにより,セクション・データを格納したプログラム・セクションを独自のイメージ・セクションに分離する方法があります。

この例では, bufferという名前のセクションはbufferという名前のプログラム・セクション内に示されています(プログラム・セクションの生成方法は,各プラットフォーム上の言語の種類により異なります。セクションが独自のプログラム・セクションにあることをコンパイラの解説書で確認してください) 。次のリンク操作は,このプログラム・セクションのSOLITARY属性を設定する方法を示しています。


$  LINK MAPTEST, SYS$INPUT/OPT 
PSECT_ATTR=BUFFER,SOLITARY 
[Ctrl/Z]

CPU固有のページ境界の末尾にアラインされる末尾アドレスをセクション・バッファに対して指定するには,実行時にCPU固有のページ・サイズを入手し,その値から1を減算し,その値を使用して配列の最終要素のアドレスを求めます。この値をinadr引数の2番目のロングワードとして渡します(実行時にページ・サイズを判断する方法については, 第 5.4 節 を参照してください)。セクションがマッピングされるバッファの割り当てを変更する必要はありません。

アプリケーションが任意のページ・サイズのAlphaシステムで正しく実行されるようにするには,/BPAGE=16修飾子を指定することにより,リンカがイメージ・セクションを 64KBの境界に強制的にアラインするようにします。実際にマッピングされるメモリの総量は,使用可能なメモリの合計よりはるかに大きくなる可能性があります。使用可能なメモリのサイズは,ページ・カウント( pagcnt )引数の値とセクション・ファイルのサイズのうち,どちらか小さい方の値によって決定されます。セクションの範囲内に含まれないメモリを使用しないようにするには,retadr 引数に戻された値を使用します。

例 5-5 は,Alphaシステムで正しく実行するために 例 5-4 に対して必要なソースの変更を示しています。

例 5-5 上記のサンプル・コードをAlphaシステムで実行するのに必要なソース・コードの変更

#include  <ssdef.h> 
#include  <stdio.h> 
#include  <stsdef.h> 
#include  <string.h> 
#include  <stdlib.h> 
#include  <descrip.h> 
#include  <dvidef.h> 
#include  <rms.h> 
#include  <secdef.h> 
#include  <syidef.h> (1)
 
char buffer[512];  (2)
char *filename = "maptest.dat"; 
struct FAB fab; 
 
long  cpu_pagesize; (3)
 
struct itm {                      /* item list */ 
    short int     buflen;  /* length of buffer in bytes */ 
    short int  item_code;  /* symbolic item code */ 
    long          bufadr;  /* address of return value buffer */ 
    long       retlenadr;  /* address of return value buffer length */ 
  } itmlst[2]; (4)
 
main( argc, argv ) 
int argc; 
char *argv[]; 
{ 
     int    i; 
     int    status = 0; 
     long   flags = SEC$M_EXPREG; 
     long   inadr[2]; 
     long   retadr[2]; 
     int    fileChannel; 
     char  *mapped_section; 
 
/********  create disk file to be mapped *************/ 
 
     fab = cc$rms_fab; 
     fab.fab$l_fna = filename; 
     fab.fab$b_fns = strlen( filename ); 
     fab.fab$l_fop = FAB$M_CIF | FAB$M_UFO;  /* must be UFO */ 
 
     status = sys$create( &fab ); 
 
     if( status & STS$M_SUCCESS ) 
        printf("%s opened\n",filename); 
     else 
     { 
        exit( status ); 
     } 
 
     fileChannel = fab.fab$l_stv; 
 
/**********  obtain the page size at run time  ****************/ 
 
 
     itmlst[0].buflen =  4; 
     itmlst[0].item_code = SYI$_PAGE_SIZE;    
     itmlst[0].bufadr =  &cpu_pagesize;       
     itmlst[0].retlenadr = &cpu_pagesize_len; 
     itmlst[1].buflen = 0; 
     itmlst[1].item_code = 0;  
 
(5)   status = sys$getsyiw( 0, 0, 0, &itmlst, 0, 0, 0 ); 
 
     if( status & STS$M_SUCCESS ) 
     { 
          printf("getsyi succeeds, page size = %d\n",cpu_pagesize); 
     } 
     else 
     { 
          printf("getsyi fails\n"); 
          exit( status ); 
     } 
 
/**********  create and map the section  ****************/ 
 
     inadr[0] = &buffer[0]; 
     inadr[1] = &buffer[cpu_pagesize - 1]; (6) 
 
     printf("address of buffer = %u\n", inadr[0] ); 
 
     status = SYS$CRMPSC(&inadr, /* inadr=address target for map */ 
                        &retadr, /* retadr= what was actually mapped */ 
                              0, /* acmode  */ 
                              0, /* no flags to set  */ 
                              0, /* gsdnam, only for global sections */ 
                              0, /* ident, only for global sections */ 
                              0, /* relpag, only for global sections */ 
                    fileChannel, /* returned by SYS$CREATE */ 
                              0, /* pagcnt = size of sect. file used */ 
                              0, /* vbn = first block of file used */ 
                              0, /* prot = default okay */ 
                              0); /* page fault cluster size */ 
 
     if( status & STS$M_SUCCESS ) 
     { 
          printf("section mapped\n"); 
          printf("start address returned =%u\n",retadr[0]); 
     } 
     else 
     { 
          printf("map failed\n"); 
          exit( status ); 
     } 
} 

次のリストの各項目は, 例 5-5 の番号に対応しています。

  1. ヘッダ・ファイルSYIDEF.Hには,$GETSYIシステム・サービスに対する OpenVMSアイテム・コードの定義が登録されています。

  2. バッファは_align(page)ストレージ記述子を使用せずに定義されています。ページ・サイズはOpenVMS Alphaシステムで実行するまで判断できないため, DEC C for OpenVMS Alphaコンパイラは,_align(page)が指定されているときに,データをAlphaの最大ページ・サイズ(64KB)にアラインします。

  3. この構造は,実行時にページ・サイズを入手するために使用される項目リストを定義します。

  4. この変数には,戻されたページ・サイズ値が格納されます。

  5. $GETSYIシステム・サービスに対するこの呼び出しでは,実行時にページ・サイズが入手されます。

  6. バッファの末尾アドレスは,戻されたページ・サイズ値から1を減算することにより指定されます。



5.3.4 オフセットによるセクション・ファイルのマッピング

アプリケーションではセクション・ファイルの一部だけをマッピングできます。その場合には,マッピングを開始するアドレスをセクション・ファイルの先頭からのオフセットとして指定します。このオフセットを指定するには, $CRMPSCシステム・サービスの relpag 引数に対して値を指定します。 relpag 引数の値は,ファイルの先頭を基準にしてマッピングを開始するページ番号を指定します。

$CRMPSCシステム・サービスは互換性を維持するために,VAXシステムと Alphaシステムの両方のシステムにおいて,relpag 引数の値を 512バイト単位で解釈します。しかし,AlphaシステムのCPU固有のページ・サイズは512バイトより大きいため,relpag 引数にオフセットとして指定する値はおそらくCPU固有のページ境界にアラインされません。$CRMPSCシステム・サービスは仮想メモリをCPU固有のページ単位でのみマッピングできます。したがって, Alphaシステムでは,セクション・ファイルのマッピングはオフセット・アドレスを含むCPU固有のページの先頭から開始され,オフセットによって指定されるアドレスから正確に開始されるわけではありません。

注意

ルーチンは,オフセットによって指定されるアドレスを含むCPU固有のページの先頭からマッピングを開始しますが,retadr 引数に戻される先頭アドレスはオフセットによって指定されたアドレスであり,実際にマッピングが開始されたアドレスではありません。

アプリケーションでオフセットからセクション・ファイルにマッピングする場合には, Alphaシステムでマッピングされる余分な仮想メモリ空間を格納できるように, inadr 引数に指定されるアドレス範囲のサイズを拡大する必要があります。指定されるアドレス範囲が小さすぎる場合には,アプリケーションはセクション・ファイルの中で必要な部分全体をマッピングできない可能性があります。これは,マッピングがセクション・ファイルの先頭アドレスから開始されるからです。

たとえば,VAXシステムでセクション・ファイルをマッピングするときに,ブロック番号15から始まる16ブロックをマッピングする場合には,アドレス範囲として 16*512バイトのサイズを inadr 引数に指定し,relpag 引数に対して15を指定できます。これと同じマッピングをAlphaシステムで実行するには,ページ・サイズの違いを考慮しなければなりません。たとえば,8Kバイト・ページ・サイズのAlphaシステムでは,relpag オフセットによって指定されるアドレスは, 図 5-2 に示すように,15ページレットをCPU固有の 1ページに格納できます。Alphaシステムでは,$CRMPSCシステム・サービスはセクション・ファイルのマッピングをCPU固有のページ境界から開始するため, 16番目から30番目までのブロックを正しくマッピングできません。マッピングを正しく実行するには,Alphaシステムで$CRMPSCシステム・サービス(または $MGBLSCシステム・サービス)がマッピングする追加の15ページレットを格納できるようにアドレス範囲のサイズを拡大しなければなりません。このようにサイズを拡大しなかった場合には,指定したセクション・ファイルの中で1ブロックだけしかマッピングされません。 図 5-2 はこの状況を示しています。

図 5-2 オフセットによるマッピングに対してアドレス範囲が与える影響


relpag 引数に指定するアドレス範囲をどれだけ拡大するかを計算する場合には,次の公式を使用すると便利です。この公式は,特定の数のページレットをマッピングするのに充分なCPU固有のページ数を計算します。
( number
pagelets

たとえば,この公式を使用すれば,前の例に指定したアドレス範囲をどれだけ拡大すればよいかを計算できます。次の式では,ページ・サイズは8Kであると仮定しています。したがって,pagelets_per_page は16になります。


16+((2x16)-2)/16=2.87... 

結果をもっとも近い整数に切り捨てることにより,この公式は inadr 引数に指定するアドレス範囲が,CPU固有のページの2ページに対応しなければならないことを示しています。

5.4 ページ・サイズの実行時確認

Alphaシステムでサポートされるページ・サイズを確認するには, $GETSYIシステム・サービスを使用します。 例 5-6 は,このシステム・サービスを使用して実行時にページ・サイズを確認する方法を示しています。

例 5-6 CPU固有のページ・サイズを確認するための$GETSYIシステム・サービスの使用

#include  <ssdef.h> 
#include  <stdio.h> 
#include  <stsdef.h> 
#include  <descrip.h> 
#include  <dvidef.h> 
#include  <rms.h> 
#include  <secdef.h> 
#include  <syidef.h>  /* defines page size item code symbol */ 
 
 
struct itm {               /* define item list                       */ 
    short int     buflen;  /* length in bytes of return value buffer */ 
    short int  item_code;  /* item code                              */ 
    long          bufadr;  /* address of return value buffer         */ 
    long       retlenadr;  /* address of return value length buffer  */ 
  } itmlst[2]; 
 
long  cpu_pagesize; 
long  cpu_pagesize_len; 
 
main( argc, argv ) 
int argc; 
char *argv[]; 
{ 
     int    status = 0; 
 
     itmlst[0].buflen =  4;                /*  page size requires 4 bytes  */ 
     itmlst[0].item_code = SYI$_PAGE_SIZE; /*  page size item code         */ 
     itmlst[0].bufadr =  &cpu_pagesize;    /*  address of ret_val buffer   */ 
     itmlst[0].retlenadr = &cpu_pagesize_len; /* addr of length of ret_val */ 
     itmlst[1].buflen = 0; 
     itmlst[1].item_code = 0;   /* Terminate item list with longword of 0  */ 
 
     status = sys$getsyiw( 0, 0, 0, &itmlst, 0, 0, 0 ); 
 
     if( status & STS$M_SUCCESS ) 
     { 
          printf("getsyi succeeds, page size = %d\n",cpu_pagesize); 
          exit( status ); 
     } 
     else 
     { 
          printf("getsyi fails\n"); 
          exit( status ); 
     } 
} 



5.5 メモリをワーキング・セットとしてロックする操作

$LKWSETシステム・サービスは,VAXシステムでもAlphaシステムでも同様に,アドレス範囲として inadr 引数に指定したページ範囲をワーキング・セットとしてロックします。このシステム・サービスは必要に応じて,アドレスをCPU固有のページ境界に調整します。

しかし,Alpha命令は完全な仮想アドレスを指定できないため,Alphaイメージはプロシージャ記述子に対するポインタを通じて,間接的にプロシージャとデータを参照しなければなりません。プロシージャ記述子には,実際のコード・アドレスも含めて,プロシージャに関する情報が格納されます。プロシージャ記述子とデータに対するこれらのポインタは,リンケージ・セクションと呼ぶ新しいプログラム・セクションに収集されます。

対処方法

Alphaシステムでは,単にコード・セクションをメモリにロックするだけでは性能を向上するのに不十分です。関連するリンケージ・セクションもワーキング・セットとしてロックしなければなりません。

リンケージ・セクションをメモリ内でロックするには,リンケージ・セクションの先頭アドレスと末尾アドレスを判断し,$LKWSETシステム・サービスを呼び出すときに, inadr 引数の値としてこれらのアドレスを指定しなければなりません。


目次 索引

印刷用画面へ
プライバシー 本サイト利用時の合意事項