home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1997 March / VPR9703A.ISO / VPR_DATA / DOGA / SOURCES / REND.LZH / READER / VIRTUAL.C < prev    next >
C/C++ Source or Header  |  1995-11-08  |  10KB  |  526 lines

  1. /*
  2.  *        仮想記憶処理関数
  3.  *
  4.  *            1989.12.16
  5.  *            Copyright    T.Kobayashi
  6.  *
  7.  */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12. #define    NDEBUG
  13. #include <assert.h>
  14. #if defined(VIRTUAL) && defined(ONDEMANDMALLOC)
  15. #error "both VIRTUAL and ONDEMANDMALLOC are defined"
  16. #endif
  17.  
  18. #ifdef    VIRTUAL
  19.  
  20. #define EMSDEBUG
  21.  
  22. #ifdef EMS
  23.     #include <signal.h>
  24.     #include "..\ems\ems.h"
  25. #endif
  26.  
  27.  
  28. #include "reader.h"
  29.  
  30. #define    PAGE_NOT_ALLOC    1
  31. #define    FILE_CANT_OPEN    2
  32. #define    FILE_OUT_ERROR    3
  33. #define    ID_ERROR        4
  34. #define    BUS_ERROR        5
  35.  
  36. #define ALLOC_DATA_ID    12345
  37. /*#define    PAGE_UNIT        (2*1024)*/
  38. #define    PAGE_UNIT        (16384)
  39. #define    segseek( seg )    fseek( virfp, (long)((seg)-1) * (long)PAGE_UNIT, 0 )
  40.  
  41. #define    NO_USE        -1
  42. #define    PAGE_SIZE    ( sizeof( PAGE ) + PAGE_UNIT + 2 * sizeof( MMA ) )
  43.  
  44. /*  メモリ管理領域  */
  45. typedef    struct {
  46.         short    id ;
  47.         long    size ;
  48.     }
  49.         MMA ;
  50.  
  51. /*    ページ管理構造体    */
  52. typedef    struct    _PAGE {
  53.         char    *membuf;            /*  メインメモリ上の位置    */
  54.         short    access ;            /*  アクセス頻度            */
  55.         short    lock ;                /*  ページロック            */
  56.         unsigned short    segment ;    /*  セグメント番号            */
  57.     }
  58.         PAGE ;
  59.  
  60. static    PAGE            *page ;        /*  ページ管理領域                */
  61. static    int                pages ;        /*  ページ数                    */
  62. static    FILE            *virfp ;    /*  仮想記憶ファイルポインタ    */
  63. static    Pointer            nextbuf ;    /*  次のアドレス                */
  64. static    unsigned int    lastseg    ;    /* 最新のアクセスセグメント    */
  65. static    PAGE            *lastpage ;    /*  最新のアクセスページ        */
  66. /*    By Taka2    */
  67. #ifdef EMS
  68. static    int                emshandle = 0;
  69. static    int                emsmax;
  70. #endif
  71.  
  72. /*
  73.     proto -s virtual.c > temp
  74. */
  75. static    void    newseg( void );
  76. static    PAGE    *segload( unsigned int );
  77. static    void    inc_access( PAGE* );
  78. static    void    virtualerror( int );
  79.  
  80. #ifdef EMS
  81. void    free_ems(void)
  82. {
  83.     if (emshandle > 0) {
  84.         _ems_DeallocatePages(emshandle);
  85.         emshandle = 0;
  86.     }
  87. }
  88.  
  89. void    free_ems_exit(void)
  90. {
  91.     free_ems();
  92.     exit(1);
  93. }
  94. #endif
  95.  
  96.  
  97. #ifdef V70
  98.     static    int        flag = FALSE ;
  99. #endif
  100. /*    仮想記憶の初期化  */
  101. void    virinit( filename )
  102. char    *filename ;        /*  仮想記憶ファイル名  */
  103. {
  104.     int        i ;
  105. #ifndef V70
  106.     static    int        flag = FALSE ;
  107. #endif
  108.     char far *    pageframe;
  109.     assert( virtualmode );
  110.     assert( flag == FALSE );
  111. #ifdef EMS
  112.     if (toupper(filename[0]) == 'E'
  113.      && toupper(filename[1]) == 'M'
  114.      && toupper(filename[2]) == 'S'
  115.      &&         filename[3]  == '\0') {
  116.         if (_ems_check() == FALSE) {
  117.             virtualerror( FILE_CANT_OPEN );
  118.         }
  119.         atexit(free_ems);
  120.         signal(SIGABRT, free_ems_exit);
  121.         signal(SIGBREAK, free_ems_exit);
  122.         signal(SIGINT, free_ems_exit);
  123.         pageframe = _ems_GetPageFrame();
  124.         emsmax = _ems_GetUnallocatedPage();
  125.         emshandle = _ems_AllocatePages(emsmax);
  126.  
  127.         pages = 4;
  128.  
  129.         fprintf( stderr, "EMS領域を %d ページ確保します。\n", emsmax );
  130.  
  131.         page = memalloc( pages * sizeof( PAGE ) );
  132.         for( i = 0 ; i < pages ; ++i )
  133.         {
  134.             page[i].membuf = pageframe + 16384 * i;
  135.             page[i].access = NO_USE ;
  136.             page[i].lock = 0 ;
  137.         }
  138.         nextbuf = 0L ;
  139.         lastseg = 0xFFFF ;
  140.         lastpage = NULL ;
  141.         newseg();
  142.     } else {
  143. #endif
  144.         flag = TRUE ;
  145.         virfp = fopen( filename, "w+b" );
  146.         if ( virfp == NULL )
  147.             virtualerror( FILE_CANT_OPEN );
  148.  
  149.         pages = (int)( memallsize() / (long)PAGE_SIZE ) ;
  150.         if ( pages <= 3 )
  151.             virtualerror( PAGE_NOT_ALLOC );
  152.  
  153.         fprintf( stderr, "仮想記憶領域を %d ページ確保します。\n", pages );
  154.  
  155.         page = memalloc( pages * sizeof( PAGE ) );
  156.         for( i = 0 ; i < pages ; ++i )
  157.         {
  158.             page[i].membuf = memalloc( PAGE_UNIT );
  159.             page[i].access = NO_USE ;
  160.             page[i].lock = 0 ;
  161.         }
  162.         nextbuf = 0L ;
  163.         lastseg = 0xFFFF ;
  164.         lastpage = NULL ;
  165.         newseg();
  166. #ifdef EMS
  167.     }
  168. #endif
  169. }
  170.  
  171. /*    仮想記憶領域の確保  */
  172. Pointer    viralloc( size )
  173. int        size ;
  174. {
  175.     Pointer            p ;
  176.     unsigned int    off ;
  177.     MMA                *h ;
  178.     assert( nextbuf != 0 );
  179.     assert( 0 < size && size < PAGE_UNIT );
  180.     assert( ( size % 2 ) == 0 );
  181.  
  182.     off = (unsigned int)( nextbuf & 0xFFFF );
  183.     if ( off + size + sizeof( MMA ) > PAGE_UNIT )
  184.         newseg();
  185.  
  186.     /*  メモリ管理領域の設定  */
  187.     p = nextbuf ;
  188.     nextbuf += size + sizeof( MMA ) ;
  189.     h = pointer( p );
  190.     h->id = ALLOC_DATA_ID ;
  191.     h->size = (long)size ;
  192.  
  193.     return( p + sizeof( MMA ) );
  194. }
  195.  
  196. /*    配列の確保    */
  197. Pointer    viraryalloc( count, size )
  198. int        count, size ;
  199. {
  200.     int        i ;
  201.     Pointer    ret ;
  202.  
  203.     assert( count > 0 );
  204.  
  205.     ret = viralloc( size );
  206.     for( i = 1 ; i < count ; ++i )
  207.     {
  208.         viralloc( size );
  209.     }
  210.     return( ret );
  211. }
  212.  
  213. /*  配列の次の要素を得る  */
  214. Pointer    virarynext( p, size )
  215. REGISTER    Pointer    p ;
  216. REGISTER    int        size ;
  217. {
  218.     REGISTER    unsigned int    off ;
  219.  
  220.     off = (int)( p & 0xFFFFL );
  221.     off += size ;
  222.     assert( off < PAGE_UNIT );
  223.  
  224.     if ( off + size + sizeof( MMA ) > PAGE_UNIT )
  225.         return( ( p & 0xFFFF0000L ) + 0x10000L + (long)sizeof( MMA ) );
  226.     else
  227.         return( p + size + (long)sizeof( MMA ) );
  228. }
  229.  
  230. /*    新しいセグメントの確保  */
  231. static    void    newseg()
  232. {
  233.     unsigned int    seg ;
  234. #ifdef EMS
  235.     if (emshandle > 0) {
  236.         seg = (unsigned int)( nextbuf >> 16 ) + 1 ;
  237.         if (seg > emsmax) {
  238.             virtualerror( FILE_OUT_ERROR );
  239.         }
  240.         nextbuf = (Pointer)seg << 16 ;
  241.     } else {
  242. #endif
  243.         seg = (unsigned int)( nextbuf >> 16 ) + 1 ;
  244.         segseek( seg );
  245.         fwrite( page->membuf, 1, PAGE_UNIT, virfp );
  246.         nextbuf = (Pointer)seg << 16 ;
  247. #ifdef EMS
  248.     }
  249. #endif
  250. }
  251.  
  252. /*  セグメントのロード  */
  253. static    PAGE    *segload( seg )
  254. REGISTER    unsigned int    seg ;
  255. {
  256.     REGISTER    int        i, access ;
  257.     REGISTER    PAGE    *p, *ret ;
  258.  
  259.     /*  メインメモリ上にあるかどうか  */
  260.     ret = NULL ;
  261.     access = pages ;
  262.     p = page ;
  263.     for( i = 0 ; i < pages ; ++i )
  264.     {
  265.         if ( p->access >= 0 && seg == p->segment )
  266.         {
  267.             ret = p ;
  268.             break ;
  269.         }
  270.         p ++ ;
  271.     }
  272.  
  273.     if ( ret != NULL )
  274.     {
  275.         assert( ret->access < pages );
  276.         inc_access( ret );
  277.         ret->access = 0 ;
  278.         return( ret );
  279.     }
  280.  
  281.     /*  メインメモリ上にない場合  */
  282.     access = 0 ;
  283.     p = page ;
  284.     for( i = 0 ; i < pages ; ++i )
  285.     {
  286.         if ( p->access == NO_USE )
  287.         {
  288.             ret = p ;
  289.             break ;
  290.         }
  291. #ifdef EMS
  292.     }
  293.     if (i == pages)
  294.     for (p = &(page[0]), i = 0; i < pages; ++i) {
  295. #endif
  296.         if ( p->lock == 0 && p->access > access )
  297.         {
  298.             access = p->access ;
  299.             ret = p ;
  300.         }
  301.         p ++ ;
  302.     }
  303.  
  304.     /*  メインメモリから追い出す  */
  305.     if ( i == pages )
  306.     {
  307.         assert( 0 < access && access <= pages );
  308. #ifdef EMS
  309.         if (emshandle > 0) {
  310. #ifdef EMSDEBUG
  311. printf("Map %3d<-%4d\n", ret-page, seg - 1);
  312. #endif
  313.             _ems_MapHandlePage(emshandle, ret-page, seg - 1);
  314.             inc_access( ret );
  315.         } else {
  316. #endif
  317. /*            fprintf( stderr, "swap %3d -> %3d\xd", ret->segment, seg );*/
  318.             segseek( ret->segment );
  319.             fwrite( ret->membuf, 1, PAGE_UNIT, virfp );
  320.             inc_access( ret );
  321.             segseek( seg );
  322.             fread( ret->membuf, 1, PAGE_UNIT, virfp );
  323. #ifdef EMS
  324.         }
  325. #endif
  326.     }
  327.     else        /* 使っていないページがある    */
  328.     {
  329. #ifdef EMS
  330. #ifdef EMSDEBUG
  331. printf("Map %3d<-%4d\n", ret-page, seg - 1);
  332. #endif
  333.         if (emshandle > 0) {
  334.                 _ems_MapHandlePage(emshandle, ret-page, seg - 1);
  335.         }
  336. #endif
  337.         inc_access( NULL );
  338.     }
  339.  
  340.     /*  メインメモリにロード  */
  341.     ret->access = 0 ;
  342.     ret->segment = seg ;
  343. #ifdef EMS
  344.     if ( emshandle == 0 && ferror( virfp ) )
  345.         virtualerror( FILE_OUT_ERROR );
  346. #else
  347.     if ( ferror( virfp ) )
  348.         virtualerror( FILE_OUT_ERROR );
  349. #endif
  350.     return( ret );
  351. }
  352.  
  353. /*  アクセス頻度の更新  */
  354. static    void    inc_access( p )
  355. REGISTER    PAGE    *p ;
  356. {
  357.     REGISTER    PAGE    *pp ;
  358.     REGISTER    int        access, i ;
  359.  
  360.     if ( p != NULL )
  361.         access = p->access ;
  362.     else
  363.         access = pages ;
  364.     pp = page ;
  365.     for( i = 0 ; i < pages ; ++i )
  366.     {
  367.         if ( pp->access >= 0 && pp->access < access )
  368.             pp->access ++ ;
  369.         pp ++ ;
  370.     }
  371. }
  372.  
  373. /* マーク  */
  374. Pointer    virmark()
  375. {
  376.     return( nextbuf );
  377. }
  378.  
  379. /*  メモリの解放  */
  380. void    virrelease( mark )
  381. Pointer    mark ;
  382. {
  383.     assert( mark <= nextbuf );
  384.     nextbuf = mark ;
  385. }
  386.  
  387. /*    使用領域サイズを返す  */
  388. long    virsize()
  389. {
  390.     long    seg, off ;
  391.  
  392.     seg = nextbuf >> 16 ;
  393.     off = nextbuf & 0xFFFF ;
  394.     return( ( seg - 1 ) * (long)PAGE_UNIT + off );
  395. }
  396.  
  397. /*    ページをロックする    */
  398. int        virlock()
  399. {
  400.     if ( ! virtualmode )
  401.         return( 0 );
  402. #if 0
  403. #ifdef EMSDEBUG
  404. printf("Page lock %d->%d\n", lastpage - page, lastpage->lock+1);
  405. #endif
  406. #endif
  407.     lastpage->lock ++ ;
  408.     return( lastpage - page );
  409. }
  410.  
  411. /*  ページロックを解除する  */
  412. void    virunlock( no )
  413. int        no ;
  414. {
  415.     if ( ! virtualmode )
  416.         return ;
  417. #if 0
  418. #ifdef EMSDEBUG
  419. printf("Page unlock %d->%d\n", no, page[no].lock - 1);
  420. #endif
  421. #endif
  422.  
  423.     assert( page[no].lock > 0 );
  424.     page[no].lock -- ;
  425. }
  426.  
  427. /*    実アドレスを得る    */
  428. void    *virpointer( vp )
  429. REGISTER    Pointer    vp ;
  430. {
  431.     REGISTER    unsigned int    seg, off ;
  432.     if ( ! virtualmode )
  433.         return( (void*)vp );
  434.  
  435.     if ( vp == 0 )
  436.         return( NULL );
  437.     if (vp > ((long)pages<<16)) {
  438.         printf("vp = %08lx\n", vp);
  439.         return vp;
  440.     }
  441.     seg = (unsigned int)( vp >> 16 );
  442.     off = (unsigned int)( vp & 0xFFFF );
  443.  
  444.     assert( vp < nextbuf );
  445.     assert( off < PAGE_UNIT );
  446.  
  447.     if ( lastseg == seg )
  448.         return( lastpage->membuf + off );
  449.  
  450.     lastpage = segload( seg );
  451.     lastseg = seg ;
  452.     return( lastpage->membuf + off );
  453. }
  454.  
  455. /*    領域のチェック    */
  456. int        vircheck( top, refer, flag )
  457. Pointer    top ;
  458. Pointer    refer ;
  459. int        flag ;
  460. {
  461.     MMA        *h ;
  462.  
  463.     if ( ! virtualmode )
  464.         return( memcheck( (char*)top, (char*)refer, flag ) );
  465.  
  466.     assert( flag == 0 );
  467.  
  468.     h = pointer( refer );
  469.     h -- ;
  470.     if ( h->id != ALLOC_DATA_ID )
  471.     {
  472.         virtualerror( ID_ERROR );
  473.         return( FALSE );
  474.     }
  475.     return( TRUE );
  476. }
  477.  
  478. #ifdef V70
  479.     static    exitflag = FALSE ;
  480. #endif
  481. /*    エラーメッセージ出力  */
  482. static    void    virtualerror( n )
  483. int        n ;
  484. {
  485. #ifndef V70
  486.     static    exitflag = FALSE ;
  487. #endif
  488.     char    *msg ;
  489.  
  490.     switch( n )
  491.     {
  492.         case PAGE_NOT_ALLOC :
  493.             msg = "ページ領域を確保できませんでした。" ;
  494.             exitflag = TRUE ;
  495.             break ;
  496.         case FILE_CANT_OPEN :
  497.             msg = "仮想記憶ファイルがオープンできませんでした。" ;
  498.             exitflag = TRUE ;
  499.             break ;
  500.         case FILE_OUT_ERROR :
  501. #ifdef EMS
  502.             if (emshandle > 0) {
  503.                 msg = "EMSのページが足りません。" ;
  504.             } else {
  505.                 msg = "仮想記憶ファイル出力でエラーが発生しました。" ;
  506.             }
  507. #else
  508.             msg = "仮想記憶ファイル出力でエラーが発生しました。" ;
  509. #endif
  510.             perror( "" );
  511.             exitflag = TRUE ;
  512.             break ;
  513.         case ID_ERROR :
  514.             msg = "メモリ管理領域が破壊されました。" ;
  515.             break ;
  516.         case BUS_ERROR :
  517.             msg = "不正なアドレスを参照しようとしています。" ;
  518.             break ;
  519.     }
  520.     fprintf( stderr, "\n\7%s\n\n", msg );
  521.     if ( exitflag )
  522.         exit( 1 );
  523. }
  524.  
  525. #endif    /* VIRTUAL */
  526.