日本-日本語

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

OpenVMS マニュアル


≫ 

OpenVMS
ライブラリ

タイトルページ
目次
まえがき
第 1 章:移行プロセスの概要
第 2 章:移行方法の選択
第 3 章:アプリケーションの移行
第 4 章:再コンパイルと再リンクの概要
第 5 章:ページサイズの拡大に対するアプリケーションの対応
第 6 章:共用データの整合性の維持
第 7 章:アプリケーションデータ宣言の移植性の確認
第 8 章:アプリケーション内の条件処理コードの確認
第 9 章:OpenVMS I64コンパイラ
付録 A :アプリケーション評価チェックリスト
用語集
索引
PDF
OpenVMS ホーム

HP OpenVMS
OpenVMS VAX から OpenVMS I64 への
アプリケーションの移行


目次 索引

たとえば, 例 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 に示したプログラムを I64 システムで正しく実行するには,次の変更が必要です。

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

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

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

この例では, bufferという名前のセクションが, buffer という名前のプログラム・セクション内に示されています。 (プログラム・セクションの生成方法は,各プラットフォーム上のプログラミング言語によって異なります。セクションが個別のプログラム・セクションにあることを確認する方法については,コンパイラのマニュアルを参照してください。) 次のリンク操作は,このプログラム・セクションの SOLITARY 属性を設定する方法を示しています。


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

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

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

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

例 5-5 前の例を I64 システムで実行するのに必要なソース・コードの変更

#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 I64 システムで実行するまで決まらないため, HP C for OpenVMS I64 コンパイラは,_align(page) が指定されているときに,データを I64 の最大ページ・サイズ (64KB) にアラインします。

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

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

  5. $GETSYI システム・サービスに対するこの呼び出しで,実行時にページ・サイズを取得します。

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



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

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

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

注意

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

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

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

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


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

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


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

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

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

I64 システムでサポートされるページ・サイズを確認するには, $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 システムでのアドレス範囲として inadr 引数で指定したページ範囲をワーキング・セット内にロックします。このシステム・サービスは,必要に応じて,アドレスを CPU 固有のページ境界に調整します。

OpenVMS Alpha および I64 では,新しい LIBRTL ルーチン LIB$LOCK_IMAGE が同等の機能を提供します。コードと関連するデータをワーキング・セット内にロックするには, LIB$LOCK_IMAGE および関連するルーチン LIB$UNLOCK_IMAGE を使用することをお勧めします。ワーキング・セット内にイメージをロックする方法についての詳細は,『OpenVMS RTL Library (LIB$) Manual』のこれらのルーチンの説明を参照してください。


目次 索引

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