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


前へ 次へ 目次 索引


5.3.3 定義されたアドレス範囲へのマッピング

アプリケーションで仮想アドレス空間の定義された領域にセクションをマッピングする場合には,ソース・コードを変更しなければならない可能性があります。これは,Alphaシステムでは$CRMPSCおよび$MGBLSCシステム・サービスがVAXシステムと異なる方法で一部の引数を解釈するからです。相違点は次のとおりです。

対処方法

可能な場合には,拡張された仮想アドレス空間にデータがマッピングされるように,アプリケーションを変更してください。アプリケーションがデータをマッピングする方法を変更できない場合には,次のガイドラインに従ってください。

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

これらの目標を達成するための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 例 5-4を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_of_pagelets_to_map + (2*pagelets_per_page)-2)
          pagelets_per_page


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


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

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


前へ 次へ 目次 索引