home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 328_02 / wheap.c < prev    next >
C/C++ Source or Header  |  1991-03-17  |  25KB  |  1,463 lines

  1. /* wheap.c
  2.  *     memory management for handling large blocks of data.
  3.  *    each allocated large block is controlled by an object of type WHEAP.
  4.  *    a block may be stored on expanded mem, DOS RAM, or disk.
  5.  *
  6.  *    the calling routine follows this sequence (details ommitted):
  7.  *        WHEAP *heap_ptr, char far *data_ptr;
  8.  *
  9.  *             heap_ptr = wheap_alloc ();
  10.  *               data_ptr = wheap_access( heap_ptr,...); ... move to RAM
  11.  *                  ... do something using data_ptr
  12.  *        wheap_deaccess ( heap_ptr, ...); ... release back to heap
  13.  *        wheap_free     ( heap_ptr );     ... free from heap.
  14.  *
  15.  *    method: WHEAP block is a double linked list,
  16.  *            most recent W_NEAR heap_top
  17.  *        items added/removed at any time.
  18.  *        at end of program, run through list to free xms and disk
  19.  *
  20.  *        disk items have a separate double linked list to
  21.  *        allow finding 'holes' left by previous wheap_free()
  22.  *
  23.  *
  24.  *
  25.  */
  26.  
  27.  
  28.  
  29.  /*    TURBOC     specific functions (non_ANSI):
  30.   *          open, read, write, close, lseek, mktemp
  31.   *             and definition that start with:
  32.   *          S_I..., O_...,
  33.   *     Microsoft has similar functions.
  34.   *          farmalloc, farfree  microsoft uses halloc()/hfree
  35.   *            (taken care of in msc.h)
  36.   */
  37. #include "wsys.h"
  38.  
  39. #ifndef __TURBOC__
  40.     #include <sys\types.h>
  41.     #include <errno.h>
  42.     #include <direct.h>
  43. #else
  44.     /* Turbo C */
  45.     #include <dir.h>
  46. #endif
  47.  
  48.  
  49. #include <dos.h>
  50. #include <io.h>
  51. #include <fcntl.h>
  52. #include <string.h>
  53. #include <limits.h>
  54. #include <errno.h>
  55. #include <sys\stat.h>
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62. #ifdef W_SMALLHEAP
  63.     /* special option to allow debuggin heap functions
  64.      * if SMALLHEAP is not defined, then the largets heap element is
  65.      * 64K. This prohibits using a source-level debugger 
  66.      * defining SMALLHEAP restricts the largest heap element to 16k,
  67.      * useful only for text-mode testing.
  68.      */
  69.     #undef WHEAP_MAX
  70.     #define WHEAP_MAX  (16*1024)
  71.  
  72. #endif    /* W_SMALLHEAP */
  73.  
  74.  
  75. /* Limitation on how much dos far ram can be used as heap.
  76.  */
  77.        unsigned long wheap_ramlimit = (256L*1024L);
  78. static unsigned long wheap_ramused  = 0L;
  79.  
  80. /* expanded memory mamagenemt
  81.  */
  82. #define  XMS_PG        (16*1024)            /* size of expanded memory page  */
  83. static void far     *xmsbase = NULL;    /* base address of page frame */
  84. static unsigned char xmspresent    = 0;
  85.  
  86.  
  87. static char          dskname[13]    = {0};
  88. static char          dskname_template[13] = "HEAP--XXXXXX";
  89. static unsigned long      hiwater = 0L;    /* high file location yet written*/
  90.  
  91.  
  92. static WHEAP         *current_access = NULL;
  93.  
  94.  
  95.  
  96.     /* flage values for whd_typewrite
  97.      */
  98. #define WHPTP_LO        'l'    /* lowest file ptr  (=dummy)  */
  99. #define WHPTP_HI        'h'    /* hihgest file ptr (=dummy)  */
  100. #define WHPTP_NOTYET    'n'    /* not yet written to disk    */
  101. #define WHPTP_APPEND    'a'    /* append to end of file      */
  102. #define WHPTP_UPDATE    'u'    /* update existing block      */
  103.  
  104.  
  105.  
  106.  
  107. #ifdef __TURBOC__
  108.     /* TURBOC is able to generate forward address refs.
  109.      * so heap_top can be initialized properly
  110.      * but in Microsoft, need to do this in wheap_init
  111.      * because microsoft C can't handle the forward address reference.
  112.      */
  113. static WHEAP  W_NEAR heap_bottom;
  114.  
  115.  
  116. static WHEAP  W_NEAR heap_top =
  117.     {
  118.     NULL,           /* linked list -- _next, _prev */
  119.     &heap_bottom,
  120.  
  121.     WHEAP_MAX,    /* num bytes -in xms systems, # reqrd for dskbase */
  122.     WHP_DSK,    /* flag */
  123.  
  124.     255,        /* priority */
  125.  
  126.     NULL,        /* disk access buffer ptr (xms or ram) */
  127.  
  128.     NULL,        /* double list - dskhi, then dsklo */
  129.     &heap_bottom,
  130.  
  131.     ULONG_MAX,    /* disk position is highest possible */
  132.  
  133.     0,        /* xms handle - set to non-zero if using xms base */
  134.     0,        /* xms npages */
  135.  
  136.     WHPTP_HI,     /* flags this dsk element as the disk high marker */
  137.     0        /* filler     */
  138.  
  139.     };
  140.  
  141. static WHEAP  W_NEAR heap_bottom =
  142.     {
  143.     &heap_top,
  144.     NULL,
  145.  
  146.     0,
  147.     WHP_DSK,
  148.  
  149.     255,
  150.  
  151.     NULL,
  152.  
  153.     &heap_top,
  154.     NULL,
  155.  
  156.     0,        /* lowest disk marker is start of file */
  157.  
  158.     0,
  159.     0,
  160.  
  161.     WHPTP_LO,
  162.     0
  163.  
  164.     };
  165.  
  166. #else
  167.     /* Microsoft C version - can't initialize the double linked list
  168.      * properly, so must do it at run-time.
  169.      */
  170.  
  171. static WHEAP  W_NEAR heap_top =
  172.     {
  173.     NULL,           /* linked list -- _next, _prev */
  174.     NULL,           /* WILL BE INITIALIZED AT RUN TIME */
  175.  
  176.     WHEAP_MAX,      /* num bytes -in xms systems, # reqrd for dskbase */
  177.     WHP_DSK,        /* flag */
  178.  
  179.     255,            /* priority */
  180.  
  181.     NULL,           /* disk access buffer ptr (xms or ram) */
  182.  
  183.     NULL,           /* double list - dskhi, then dsklo */
  184.     NULL,           /* MICROSOFT - initialize at runtime */
  185.  
  186.     ULONG_MAX,      /* disk position is highest possible */
  187.  
  188.     0,              /* xms handle - set to non-zero if using xms base */
  189.     0,              /* xms npages */
  190.  
  191.     WHPTP_HI,       /* flags this dsk element as the disk high marker */
  192.     0               /* filler     */
  193.  
  194.     };
  195.  
  196. static WHEAP  W_NEAR heap_bottom =
  197.     {
  198.     &heap_top,
  199.     NULL,
  200.  
  201.     0,
  202.     WHP_DSK,
  203.  
  204.     255,
  205.  
  206.     NULL,
  207.  
  208.     &heap_top,
  209.     NULL,
  210.  
  211.     0,              /* lowest disk marker is start of file */
  212.  
  213.     0,
  214.     0,
  215.  
  216.     WHPTP_LO,
  217.     0
  218.  
  219.     };
  220.  
  221.  
  222. #endif  /* Microsoft verswion */
  223.  
  224.  
  225.  
  226.  
  227.  
  228.     /*------ XMS subroutines -------*/
  229.  
  230. static void       W_NEAR  xms_check    ( void );
  231.  
  232. static int        W_NEAR     xms_alloc    ( WHEAP *hptr );
  233.  
  234. static void       W_NEAR     xms_access   ( WHEAP *hptr );
  235.  
  236. static void       W_NEAR     xms_free     ( WHEAP *hptr );
  237.  
  238.  
  239.     /*------ DSK subroutines -------*/
  240.  
  241.  
  242. static void       W_NEAR    dsk_findhole ( WHEAP *hptr );
  243.  
  244. static void       W_NEAR  dsk_access   ( WHEAP *hptr, int readwrite );
  245.  
  246. static void       W_NEAR    dsk_deaccess ( WHEAP *hptr, int readwrite );
  247.  
  248. static void       W_NEAR    dsk_free     ( WHEAP *hptr );
  249.  
  250. static void       W_NEAR     dsk_write    ( WHEAP *hptr );
  251.  
  252. static void       W_NEAR     dsk_read     ( WHEAP *hptr );
  253.  
  254.  
  255.  
  256.     /*------ RAM subroutines -------*/
  257.  
  258. static int  W_NEAR    ram_alloc    ( WHEAP *hptr );
  259.  
  260.  
  261.     /*------ memory management routines --------------*/
  262.  
  263. static void W_NEAR    unchain_heap ( WHEAP *hptr );
  264.  
  265.  
  266.  
  267.  
  268.  
  269.     /*--------------------------------*/
  270.  
  271.     /* routines to allow accessing far memory in small model
  272.      */
  273. #undef FAR_DATA_MODEL
  274. #ifdef __LARGE__
  275.     #define FAR_DATA_MODEL
  276. #endif
  277.  
  278. #ifdef __COMPACT__
  279.     #define FAR_DATA_MODEL
  280. #endif
  281.  
  282. #ifdef __HUGE__
  283.     #define FAR_DATA_MODEL
  284. #endif
  285.  
  286. #ifdef FAR_DATA_MODEL
  287.     #define farmemcmp(aa,bb,cc)  memcmp(aa,bb,cc)
  288.     #define farwrite(aa, bb, cc) write (aa,bb,cc)
  289.     #define farread(aa, bb, cc)  read  (aa,bb,cc)
  290.  
  291.  
  292. #else
  293.  
  294.     /* model is small or medium - need a far * equivalent of
  295.      * write, read, memcmp, (note farmemcpy is defined in wsys.h)
  296.      */
  297.  
  298.  
  299.  
  300.     #define BUFSZ    512
  301.  
  302.  
  303.     static int farmemcmp(char far *aa, char far *bb, int n);
  304.     static int farmemcmp(char far *aa, char far *bb, int n)
  305.         {
  306.         int retcode =0;
  307.         int count;
  308.         NORMALIZE (aa);
  309.         NORMALIZE (bb);
  310.  
  311.  
  312.  
  313.         for ( count = 0; count < n; ++count )
  314.             {
  315.             if ( aa[count] < bb[count] )
  316.                 {
  317.                 retcode = -1;
  318.                 break;
  319.                 }
  320.             else
  321.             if ( aa[count] > bb[count] )
  322.                 {
  323.                 retcode = +1;
  324.                 break;
  325.                 }
  326.  
  327.             }
  328.  
  329.  
  330.  
  331.         return (retcode);      /* farmemcmp */
  332.         }
  333.  
  334.  
  335.     static int farwrite (int, void far *, size_t);
  336.     static int farwrite
  337.         (int handle, void far *distant_buff, size_t n)
  338.         {
  339.         char close_buff[BUFSZ];
  340.  
  341.  
  342.         int  total =0;
  343.         int  code;
  344.  
  345.         size_t     write_size = BUFSZ;
  346.  
  347.  
  348.         NORMALIZE(distant_buff);
  349.  
  350.  
  351.         while ( n>0 )
  352.             {
  353.  
  354.             if ( n > BUFSZ )
  355.                 {
  356.                 n -= BUFSZ;
  357.                 }
  358.             else
  359.                 {
  360.                 write_size = n;
  361.                 n = 0;
  362.                 }
  363.  
  364.             farmemcpy ( close_buff, distant_buff, write_size );
  365.  
  366.             code = write ( handle, close_buff, write_size );
  367.  
  368.             if ( code == -1 )
  369.                 {
  370.                 /* error, force exit with -1 return
  371.                  */
  372.                 total = -1;
  373.                 n =0;
  374.                 }
  375.             else
  376.                 {
  377.                 total += code;
  378.                 }
  379.  
  380.  
  381.             (char far *) distant_buff += BUFSZ;
  382.  
  383.  
  384.             }
  385.  
  386.         return (total);    /* farwrite - no, not John Birch */
  387.         }
  388.  
  389.  
  390.     static int farread (int, void far *, size_t);
  391.     static int farread (int filehandle, void far *distant_buff, size_t n)
  392.         {
  393.         char   close_buff[BUFSZ];
  394.  
  395.         int  total =0;
  396.         int  code;
  397.  
  398.         size_t  read_size = BUFSZ;
  399.  
  400.         NORMALIZE(distant_buff);
  401.  
  402.  
  403.         while ( n>0 )
  404.             {
  405.  
  406.             if ( n > BUFSZ )
  407.                 {
  408.                 n -= BUFSZ;
  409.                 }
  410.             else
  411.                 {
  412.                 read_size = n;
  413.                 n = 0;
  414.                 }
  415.  
  416.  
  417.             code =read ( filehandle, close_buff, read_size );
  418.  
  419.  
  420.             if ( code== -1 )
  421.                 {
  422.                 /* error - force exit & return -1*/
  423.                 n = 0;
  424.                 total = -1;
  425.                 }
  426.             else
  427.                 {
  428.                 total += code;
  429.                 farmemcpy ( distant_buff, close_buff, read_size );
  430.                 }
  431.  
  432.             (char far *) distant_buff += BUFSZ;
  433.  
  434.  
  435.             }
  436.  
  437.         return (total);    /* farwrite - no, not John Birch */
  438.  
  439.         }
  440.  
  441.  
  442.  
  443.  
  444.  
  445. #endif        /* end far functions for small model */
  446.  
  447.  
  448.  
  449.  
  450.     /*--------------- XMS routines ------------------*/
  451.  
  452.  
  453.     /* special note: these routines are called during winit()
  454.      * before remainder of window system initialized.
  455.      * Therefor, can't call any w..() funcitons that do i/o.
  456.      */
  457.  
  458.  
  459.  
  460.  
  461. static void W_NEAR    xms_check (void)
  462.     {
  463.  
  464.     char far *xms_name;
  465.     unsigned int seg;
  466.     unsigned char retcode;
  467.  
  468.     PSEUDOREGS
  469.  
  470.     /* get address of xms interrupt handler,
  471.      * check at that address to see if it's the real thing
  472.      */
  473.     _AH = 0x35;    /* subfunction to get interrupt vector */
  474.     _AL = 0x67;    /* XMS interrupt number */
  475.     INTERRUPTX ( 0x21 ); /* call DOS for interrupt vector, uses seg regs */
  476.     seg = _ES;
  477.  
  478.     xms_name = MK_FP ( seg , 0x0A );        /* offset 10 bytes into seg */
  479.  
  480.     /*look for name of EMM driver.
  481.      */
  482.     xmspresent = farmemcmp ( xms_name, "EMMXXXX0", 8 ) ? 0 : 1;
  483.  
  484.  
  485.  
  486.  
  487.  
  488.     /* make sure it's functional
  489.      */
  490.     if ( xmspresent )
  491.         {
  492.         _AH = 0x40;
  493.         INTERRUPT ( 0x67 );
  494.         if ( _AH  != 0 )
  495.             {
  496.             xmspresent = 0;    /* not OK */
  497.             }
  498.         }
  499.  
  500.     /* setup page frame address
  501.      */
  502.     if ( xmspresent )
  503.         {
  504.         _AH = 0x41;
  505.         INTERRUPT ( 0x67 );
  506.         retcode = _AH;
  507.         seg     = _BX;
  508.  
  509.         if ( retcode  != 0 )
  510.             {
  511.             xmspresent = 0;
  512.             }
  513.         else
  514.             {
  515.             xmsbase = MK_FP ( seg, 0);
  516.             }
  517.  
  518.         }
  519.  
  520.  
  521.  
  522.     return;        /* xms_check */
  523.     }
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536. static int W_NEAR     xms_alloc ( WHEAP *hptr )
  537.     {
  538.     int handle, npages, retcode;
  539.  
  540.  
  541.     PSEUDOREGS
  542.  
  543.  
  544.     if ( ! xmspresent )
  545.         {
  546.         return (1);
  547.         }
  548.  
  549.  
  550.  
  551.     /* calc # of pages needed - round up to W_NEARest 16k
  552.      *    note casts to long, in case allocating > 3* WHEAP_MAX
  553.      */
  554.     npages =(unsigned)
  555.             ( ((long)(hptr-> whp_nb) + (long)(XMS_PG -1) ) / XMS_PG );
  556.  
  557.     _BX = npages;
  558.     _AH = 0x43;
  559.     INTERRUPT ( 0x67 );
  560.     retcode = _AH;
  561.     handle  = _DX;
  562.  
  563.  
  564.     if ( retcode == 0 )
  565.         {
  566.         hptr-> whp_handle = handle;
  567.         hptr-> whp_npages = npages;
  568.         hptr-> whp_ram    = xmsbase;
  569.         }
  570.  
  571.  
  572.     return (retcode);    /* 0 = allocated OK */
  573.     }
  574.  
  575.  
  576.  
  577. /* xms_access ()
  578.  *     this routine maps the logical (xms) pages into physical (ram) pages
  579.  *    the number of pages to map is given by the WHEAP object.
  580.  *    the location of the physical pages is given by xmsbase
  581.  */
  582. static void W_NEAR     xms_access   ( WHEAP *hptr )
  583.     {
  584.     int n, nmax, handle;
  585.  
  586.  
  587.     PSEUDOREGS
  588.  
  589.  
  590.  
  591.     handle = hptr->whp_handle;
  592.     nmax   = hptr->whp_npages;
  593.  
  594.     for ( n=0; n<nmax; ++n )
  595.         {
  596.         _DX = handle;
  597.         _BX = n;
  598.         _AL = n;
  599.  
  600.         _AH = 0x44;    /* function to map pages */
  601.         INTERRUPT ( 0x67 );
  602.         }
  603.  
  604.  
  605.     return;        /* xms_map */
  606.     }
  607.  
  608.  
  609.  
  610. static void W_NEAR     xms_free ( WHEAP *hptr )
  611.     {
  612.     int handle;
  613.  
  614.     PSEUDOREGS
  615.  
  616.  
  617.  
  618.     handle = hptr->whp_handle;
  619.  
  620.     _DX = handle;
  621.     _AH = 0x45;    /* release handle */
  622.     INTERRUPT ( 0x67 );
  623.  
  624.  
  625.     return;        /* xms_free */
  626.     }
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.     /*------ DSK subroutines -------*/
  638.  
  639.  
  640.  
  641. static void  W_NEAR    dsk_findhole ( WHEAP *hptr )
  642.     {
  643.     WHEAP  *peg, *next_peg;
  644.  
  645.     unsigned long  hole, holesize, required;
  646.  
  647.  
  648.  
  649.  
  650.  
  651.     /* run up double linked list of allocated disk blocks
  652.      * looking for a 'hole' large enough to hold the block
  653.      */
  654.  
  655.     hole     =0;
  656.     holesize =0;
  657.     required = hptr-> whp_nb;
  658.  
  659.     next_peg = &heap_bottom;
  660.  
  661.     /* the loop terminates when an adequate hole has been found
  662.      * which may not occur until next_peg points to heap_top,
  663.      * which has a position artificially set to ULONG_MAX,
  664.      * so any size block will fit in
  665.      */
  666.     do     {
  667.         peg      = next_peg;
  668.         next_peg = peg-> whp_dskhi;
  669.  
  670.  
  671.         /* new hole = first byte beyond current block
  672.          */
  673.         hole = peg-> whp_position + peg-> whp_nb;
  674.  
  675.         holesize =  (next_peg-> whp_position) - hole;
  676.  
  677.         }
  678.     while (  holesize < required );
  679.  
  680.  
  681.     /* link the new block into the list of allocated disk areas
  682.      */
  683.     hptr ->     whp_dsklo = peg;
  684.     hptr ->      whp_dskhi = next_peg;
  685.  
  686.     peg->       whp_dskhi = hptr;
  687.     next_peg->     whp_dsklo = hptr;
  688.  
  689.  
  690.     hptr->         whp_position = hole;
  691.  
  692.     hptr->         whp_typewrite = WHPTP_NOTYET;    /* not yet written */
  693.  
  694.     return;        /* dsk_findhole */
  695.     }
  696.  
  697.  
  698.  
  699.  
  700.  
  701.  
  702. static void W_NEAR   dsk_access   ( WHEAP *hptr, int readwrite )
  703.     {
  704.  
  705.     hptr-> whp_ram = heap_top.whp_ram;
  706.  
  707.     if ( xmspresent )
  708.         {
  709.         /* using xms as base area for disk access...
  710.          * swap out prev. contents, swap in the disk buffer pages
  711.          */
  712.         xms_access ( &heap_top );
  713.         }
  714.  
  715.  
  716.     if ( readwrite )
  717.         {
  718.         /* need to read data in from disk
  719.          */
  720.  
  721.         dsk_read ( hptr );
  722.         }
  723.  
  724.  
  725.  
  726.     return;        /* dsk_access */
  727.     }
  728.  
  729.  
  730.  
  731.  
  732.  
  733.  
  734. static void  W_NEAR  dsk_deaccess ( WHEAP *hptr,  int readwrite )
  735.     {
  736.  
  737.     if ( readwrite )
  738.         {
  739.         dsk_write (hptr);
  740.         }
  741.  
  742.     hptr-> whp_ram = NULL;
  743.  
  744.     return;
  745.     }
  746.  
  747.  
  748.  
  749. static void W_NEAR    dsk_free  ( WHEAP *hptr )
  750.     {
  751.     WHEAP *pr, *nx;
  752.  
  753.  
  754.     /* remove this block from the list of disk ptrs
  755.      * this creates a 'hole' in the file,
  756.      * which can be reused later
  757.      */
  758.     pr = hptr-> whp_dsklo;
  759.     nx = hptr-> whp_dskhi;
  760.  
  761.     pr-> whp_dskhi  = nx;
  762.     nx-> whp_dsklo = pr;
  763.  
  764.     return;        /* dsk_free */
  765.     }
  766.  
  767.  
  768.  
  769.  
  770.     #define  UPDATE_ACCESS    (O_RDWR | O_BINARY)
  771.  
  772.     #define  APPEND_ACCESS  (O_APPEND | O_RDWR | O_BINARY)
  773.  
  774.     #define  CREATE_ACCESS  (O_CREAT | O_BINARY)
  775.  
  776.     #define  CREATE_MODE    (S_IFREG | S_IREAD | S_IWRITE)
  777.  
  778. static void W_NEAR     dsk_write    ( WHEAP *hptr )
  779.     {
  780.  
  781.     unsigned int access;
  782.     unsigned int mode;
  783.     int filehandle;
  784.  
  785.     unsigned long last_byte;
  786.  
  787.     if ( hptr-> whp_typewrite  == WHPTP_NOTYET )
  788.         {
  789.         dsk_findhole (hptr);
  790.         }
  791.  
  792.  
  793.     last_byte =  hptr->whp_position  + hptr->whp_nb;
  794.  
  795.  
  796.  
  797.     /* need to open the file differently depending on
  798.      * whether this is first time ever,
  799.      *                 updating previous block
  800.      *           or appending new block to file
  801.      */
  802.     if ( hiwater == 0 )
  803.         {
  804.         /* file has not yet been created.
  805.          */
  806.         memcpy ( dskname, dskname_template, sizeof (dskname) );
  807.         mktemp ( dskname );
  808.  
  809.         mode   = CREATE_MODE;
  810.         access = CREATE_ACCESS;
  811.  
  812.         filehandle =open ( dskname, access, mode);
  813.  
  814.         hiwater = last_byte;
  815.         }
  816.     else
  817.         {
  818.         if ( hiwater >= last_byte )
  819.             {
  820.             access =  UPDATE_ACCESS;
  821.             }
  822.         else
  823.             {
  824.             /* Block lies beyond current size of file.
  825.              * next line is in case start of block
  826.              * is within current file but end of block is beyond
  827.              */
  828.             hptr-> whp_position = hiwater;
  829.  
  830.             access = APPEND_ACCESS;
  831.             }
  832.  
  833.         if ( -1== (filehandle = open ( dskname, access ) ))
  834.             {
  835.             werror ('W', "HEAP memory -cant open to read");
  836.             }
  837.  
  838.         if ( access == UPDATE_ACCESS )
  839.             {
  840.  
  841.             if ( -1 ==
  842.                  lseek(filehandle,hptr->whp_position,SEEK_SET) )
  843.                 {
  844.                 werror ('W' , "seek error in heap memory");
  845.                 }
  846.  
  847.  
  848.             }
  849.  
  850.  
  851.         }
  852.  
  853.  
  854.     if ( filehandle == -1 )
  855.         {
  856.         werror ('W', "unable to open heap file on disk");
  857.         }
  858.  
  859.  
  860.     if ( -1== farwrite ( filehandle, hptr->whp_ram, hptr->whp_nb ) )
  861.         {
  862.         werror ('W', "unable to write to heap file");
  863.         }
  864.  
  865.  
  866.     close ( filehandle );
  867.  
  868.     hptr-> whp_typewrite = WHPTP_UPDATE;
  869.  
  870.     if ( hiwater < last_byte )
  871.         {
  872.         hiwater = last_byte;
  873.         }
  874.  
  875.     return;        /* dsk_write */
  876.     }
  877.  
  878.  
  879.  
  880.  
  881.  
  882.  
  883.  
  884. static void W_NEAR     dsk_read     ( WHEAP *hptr )
  885.     {
  886.     int filehandle;
  887.  
  888.     if ( hptr-> whp_typewrite != WHPTP_UPDATE )
  889.         {
  890.         werror ('W', "attempting to access unsaved heap block");
  891.         }
  892.  
  893.  
  894.     if ( -1 == (filehandle = open ( dskname, O_RDONLY ) ) )
  895.         {
  896.         werror ('W', "unable to read from heap file");
  897.         }
  898.  
  899.  
  900.     if ( -1L ==lseek ( filehandle, hptr-> whp_position, SEEK_SET ) )
  901.         {
  902.         werror ('W', "unable to read from heap file");
  903.         }
  904.  
  905.  
  906.  
  907.  
  908.  
  909.  
  910.     if ( -1 ==farread ( filehandle, hptr->whp_ram, hptr-> whp_nb ) )
  911.         {
  912.         werror ('W', "unable to read from heap file");
  913.         }
  914.  
  915.     close ( filehandle );
  916.  
  917.  
  918.     return;        /* dsk_read */
  919.     }
  920.  
  921.  
  922.  
  923.  
  924.  
  925.  
  926.     /*------ RAM subroutines -------*/
  927.  
  928. static int  W_NEAR    ram_alloc ( WHEAP *hptr )
  929.     {
  930.     void far *ptr;
  931.     int       retcode;
  932.     size_t    nbytes;
  933.     unsigned long ram_wanted;
  934.  
  935.     nbytes = hptr-> whp_nb;
  936.     ram_wanted   = wheap_ramused + nbytes;
  937.  
  938.     if  ( ram_wanted > wheap_ramlimit )
  939.         {
  940.         /* don't allocate ram beyond the ram limit
  941.          */
  942.         return (1);
  943.         }
  944.  
  945.     ptr = wfarmalloc ( nbytes, NULL );
  946.  
  947.     if ( ptr )
  948.         {
  949.         hptr-> whp_ram  = ptr;
  950.         wheap_ramused = ram_wanted;        
  951.         retcode = 0;
  952.         }
  953.     else
  954.          {
  955.         retcode = 1;
  956.         }
  957.  
  958.     return (retcode);    /* ram_alloc */
  959.     }
  960.  
  961.  
  962.  
  963.  
  964.  
  965.  
  966.  
  967.  
  968.  
  969.     /*----------- integrated (whole heap) routines -------------*/
  970.  
  971.  
  972.  
  973.     /* note that wheap-init is called before other windows routines,
  974.      * so it must not call window routines outside this module...
  975.      */
  976. void     wheap_init ( void )
  977.     {
  978.     int rambase = 1;
  979.  
  980.     #ifndef __TURBOC__
  981.         /* Microsoft C is unable to initialize the double linked
  982.          * list properly at compile-time,
  983.          * so it has to be done at run-time
  984.          */
  985.         heap_top.whp_prev = &heap_bottom;
  986.         heap_top.whp_dsklo = &heap_bottom;
  987.  
  988.     #endif  /* Microsoft */
  989.  
  990.     /* see if xms support is present, get page frame address, etc...
  991.      */
  992.     xms_check ();
  993.  
  994.  
  995.     /* get a buffer for disk access...
  996.      * use the xms base page if enough xms is avail (need 64k)
  997.      */
  998.  
  999.     if ( xmspresent )
  1000.         {
  1001.         /* allocate 64k of xms
  1002.          */
  1003.         rambase = xms_alloc ( &heap_top );
  1004.         if ( rambase == 0 )
  1005.             {
  1006.             heap_top.whp_ram  = xmsbase;
  1007.             }
  1008.         }
  1009.  
  1010.     if ( rambase == 1 )
  1011.         {
  1012.         /* must use ram for disk-based heap data...
  1013.          */
  1014.         xmspresent = 0;        /* too small to bother */
  1015.  
  1016.         /* can't use wfarmalloc(),  windows not initialized.
  1017.          */
  1018.         heap_top.whp_ram = farmalloc ( WHEAP_MAX );
  1019.         if ( ! heap_top.whp_ram )
  1020.             {
  1021.             exit (ENOMEM);
  1022.             }
  1023.         NORMALIZE ( heap_top.whp_ram );
  1024.  
  1025.         }
  1026.  
  1027.  
  1028.     return;        /* wheap_init */
  1029.     }
  1030.  
  1031.  
  1032. WHEAP    *wheap_alloc ( size_t nbytes,  unsigned char priority, char *errmsg)
  1033.     {
  1034.     WHEAP *hptr;
  1035.     int   need;
  1036.     int   low_priority =1;
  1037.  
  1038.     /* 80 byte errmsg, 31 bytes used, 39 left for caller
  1039.      */
  1040.     #define MSG_OFFSET 30
  1041.     #define MSG_REMAIN 50
  1042.  
  1043.  
  1044.     char msgbuff[81];
  1045.     strcpy ( msgbuff, "Out of heap memory, call from  " );
  1046.  
  1047.     hptr = wmalloc ( sizeof (WHEAP), "WHEAP" );
  1048.  
  1049.     memset ( hptr, 0, sizeof (WHEAP) );
  1050.  
  1051.  
  1052.     if ( nbytes > WHEAP_MAX || nbytes == 0 )
  1053.         {
  1054.         werror ('W', "heap request too large");
  1055.         }
  1056.  
  1057.     /* double linked list
  1058.      */
  1059.     hptr-> whp_nb       = nbytes;
  1060.     hptr-> whp_priority     = priority;
  1061.  
  1062.     hptr-> whp_next        = &heap_top;
  1063.     hptr-> whp_prev     = heap_top.whp_prev;
  1064.  
  1065.     (heap_top.whp_prev)->whp_next    = hptr;
  1066.     (heap_top.whp_prev)              = hptr;
  1067.  
  1068.  
  1069.  
  1070.  
  1071.  
  1072.     if ( priority > 0 )
  1073.         {
  1074.         while (    ( nbytes > wheap_avail () )
  1075.             && ( low_priority < priority )  )
  1076.  
  1077.             {
  1078.             /* need more ram than is presently avail,
  1079.              * so swap lower priority objects to disk
  1080.              * until either enough ram or all objects swapped
  1081.              */
  1082.             wheap_swapall2dsk ( low_priority );
  1083.             ++low_priority;
  1084.             }
  1085.  
  1086.  
  1087.         need = xms_alloc ( hptr );
  1088.         hptr-> whp_flag = WHP_XMS;
  1089.  
  1090.  
  1091.         if ( need )
  1092.             {
  1093.             need =  ram_alloc ( hptr );
  1094.             hptr->  whp_flag = WHP_RAM;
  1095.             }
  1096.  
  1097.         }
  1098.  
  1099.  
  1100.     if ( need  && (priority < 255) )
  1101.         {
  1102.         /* unable to allocate from xms or ram,
  1103.          * and not highest priority item,
  1104.          * so allocate from disk -
  1105.          * all work here is done at time of saving data.
  1106.          */
  1107.         hptr->  whp_flag      = WHP_DSK;
  1108.         hptr -> whp_typewrite = WHPTP_NOTYET;
  1109.         need = 0;
  1110.         }
  1111.  
  1112.  
  1113.     if ( need && errmsg )
  1114.         {
  1115.         memcpy(msgbuff+MSG_OFFSET, errmsg, MSG_REMAIN);
  1116.         msgbuff[sizeof(msgbuff)-1] = 0;
  1117.  
  1118.         werror ( 'W', msgbuff );
  1119.         }
  1120.  
  1121.  
  1122.     return ( hptr );    /* wheap_alloc */
  1123.     }
  1124.  
  1125.  
  1126.  
  1127.  
  1128. void far     *wheap_access   ( WHEAP *hptr,  int readwrite )
  1129.     {
  1130.  
  1131.     void far *ptr;
  1132.  
  1133.     if ( current_access )
  1134.         {
  1135.         wheap_deaccess ( current_access, 0 );
  1136.         }
  1137.  
  1138.  
  1139.     switch (  hptr-> whp_flag )
  1140.         {
  1141.     case ( WHP_XMS ):
  1142.         xms_access ( hptr );
  1143.         break;
  1144.  
  1145.     case ( WHP_DSK ):
  1146.         dsk_access ( hptr, readwrite );
  1147.         break;
  1148.  
  1149.         }
  1150.  
  1151.     ptr = hptr -> whp_ram;
  1152.  
  1153.     current_access = hptr;
  1154.  
  1155.  
  1156.     return ( ptr );    /* wheap_access */
  1157.     }
  1158.  
  1159.  
  1160.  
  1161. void          wheap_deaccess ( WHEAP *hptr,  int readwrite )
  1162.     {
  1163.  
  1164.     /* expanded memory and ram don't need to be de-accessed
  1165.      */
  1166.  
  1167.     if ( hptr-> whp_flag  == WHP_DSK )
  1168.         {
  1169.         dsk_deaccess (hptr, readwrite);
  1170.         }
  1171.  
  1172.  
  1173.     current_access = NULL;
  1174.  
  1175.     return;        /* wheap_deaccess */
  1176.     }
  1177.  
  1178.  
  1179. /* unchain_heap() - remove WHEAP object from linked list
  1180.  *    and free memory used to store WHEAP item.
  1181.  *
  1182.  */
  1183. static void  W_NEAR  unchain_heap ( WHEAP *hptr )
  1184.     {
  1185.     WHEAP   *pr, *nx;
  1186.  
  1187.     pr = hptr-> whp_prev;
  1188.     nx = hptr-> whp_next;
  1189.  
  1190.     pr-> whp_next = nx;
  1191.     nx-> whp_prev = pr;
  1192.  
  1193.  
  1194.     free ( hptr );
  1195.  
  1196.     return;        /* unchain_heap */
  1197.     }
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203. void         wheap_free  ( WHEAP *hptr )
  1204.     {
  1205.  
  1206.  
  1207.     if ( current_access )
  1208.         {
  1209.         wheap_deaccess ( current_access, 0 );
  1210.         }
  1211.  
  1212.  
  1213.  
  1214.     switch (  hptr-> whp_flag )
  1215.         {
  1216.     case ( WHP_XMS ):
  1217.         xms_free ( hptr );
  1218.         break;
  1219.  
  1220.     case ( WHP_RAM ):
  1221.         farfree ( hptr-> whp_ram );
  1222.         wheap_ramused -= (hptr-> whp_nb);
  1223.         break;
  1224.  
  1225.     case ( WHP_DSK ):
  1226.         dsk_free ( hptr );
  1227.         break;
  1228.  
  1229.         }
  1230.  
  1231.     unchain_heap ( hptr );
  1232.  
  1233.     return;        /* wheap_free */
  1234.     }
  1235.  
  1236.  
  1237.  
  1238. unsigned long     wheap_avail    ( void )
  1239.     {
  1240.     unsigned long avail;
  1241.  
  1242.     /* note problems associated with subtracting unsigned long -
  1243.      * can get large positive when what you want is negative.
  1244.      */
  1245.     avail = ( wheap_ramlimit > wheap_ramused ) ? 
  1246.                     (wheap_ramlimit - wheap_ramused) 
  1247.                 /* else */
  1248.                     : 0;
  1249.  
  1250.     return ( avail + wheap_availxms() );   /* wheap_avail */
  1251.     }
  1252.  
  1253.  
  1254.  
  1255. unsigned long     wheap_availxms ( void )
  1256.     {
  1257.     unsigned long availxms = 0;
  1258.     unsigned int  npages;
  1259.  
  1260.  
  1261.     PSEUDOREGS
  1262.  
  1263.     if ( xmspresent )
  1264.         {
  1265.  
  1266.         _AH = 0x42;
  1267.         INTERRUPT ( 0x67 );
  1268.         npages = _BX;    /* number of unallocated pages */
  1269.  
  1270.         /* _DX gives total number of XMS pages in system
  1271.          */
  1272.  
  1273.         availxms = ( ( unsigned long ) npages ) * XMS_PG;
  1274.         }
  1275.  
  1276.     return (availxms);                /* wheap_availxms */
  1277.     }
  1278.  
  1279.  
  1280.  
  1281.  
  1282. void         wheap_swap2dsk ( WHEAP *hptr )
  1283.     {
  1284.     char oldflag;
  1285.  
  1286.     oldflag = hptr-> whp_flag;
  1287.  
  1288.  
  1289.  
  1290.     if ( oldflag == WHP_DSK )
  1291.         {
  1292.         return;        /* already is disk */
  1293.         }
  1294.  
  1295.     wheap_access ( hptr, 0 );
  1296.  
  1297.  
  1298.     /* now setup values in WHEAP block
  1299.      * to make it llok like an nsaved disk block element, and then save.
  1300.      */
  1301.     hptr-> whp_flag      = WHP_DSK;
  1302.     hptr-> whp_typewrite = WHPTP_NOTYET;
  1303.  
  1304.     dsk_write ( hptr );
  1305.  
  1306.  
  1307.  
  1308.     /* see if any ram needs to be free, or xms pages released
  1309.      */
  1310.     if ( oldflag == WHP_RAM )
  1311.         {
  1312.         farfree ( hptr-> whp_ram );
  1313.         hptr-> whp_ram = NULL;
  1314.         }
  1315.     else
  1316.         {
  1317.         /* must be xms, release handle.
  1318.          */
  1319.         xms_free ( hptr );
  1320.         }
  1321.  
  1322.  
  1323.     return;        /* wheap_swap2dsk */
  1324.     }
  1325.  
  1326.  
  1327. /* swap all WHEAP blocks of given priority to disk
  1328.  */
  1329. void         wheap_swapall2dsk ( int priority )
  1330.     {
  1331.     WHEAP *hptr;
  1332.  
  1333.         hptr =heap_bottom.whp_next;
  1334.     while ( &heap_top != hptr )
  1335.         {
  1336.         if  ( hptr-> whp_priority == priority )
  1337.             {
  1338.             wheap_swap2dsk ( hptr );
  1339.             }
  1340.         hptr =hptr->whp_next;
  1341.         }
  1342.  
  1343.     return;        /* wheap_swapall2dsk */
  1344.     }
  1345.  
  1346.  
  1347.  
  1348.  
  1349.  
  1350.  
  1351. void far     *wheap_unlink ( WHEAP *hptr )
  1352.     {
  1353.     void far *ptr;
  1354.  
  1355.     size_t    numbytes;
  1356.  
  1357.  
  1358.     wheap_access ( hptr, 1 );
  1359.  
  1360.     numbytes = hptr-> whp_nb;
  1361.  
  1362.     ptr = hptr->whp_ram;
  1363.  
  1364.  
  1365.     if ( xmspresent && (hptr->whp_flag != WHP_RAM) )
  1366.         {
  1367.         /* XMS items are kept in the XMS page frame
  1368.          * and need to be copied to FAR memory
  1369.          *
  1370.          * DSK items are accessed by reading into XMS page,
  1371.          * (but not if xms is not present)
  1372.          * and need to be mapped into FAR memory
  1373.          */
  1374.         ptr = wfarmalloc ( numbytes, "HEAP" );
  1375.  
  1376.         farmemcpy ( ptr, hptr->whp_ram, numbytes );
  1377.  
  1378.  
  1379.         }
  1380.  
  1381.     switch ( hptr-> whp_flag )
  1382.         {
  1383.     case ( WHP_DSK ):
  1384.         dsk_free (hptr);
  1385.         break;
  1386.     case ( WHP_XMS ):
  1387.         xms_free ( hptr );
  1388.         break;
  1389.         }
  1390.  
  1391.  
  1392.     /* now take item hptr out of the heap lists
  1393.      */
  1394.     unchain_heap ( hptr );
  1395.  
  1396.  
  1397.     return (ptr);    /* wheap_unlink */
  1398.     }
  1399.  
  1400.  
  1401.  
  1402.  
  1403.  
  1404.  
  1405. void         wheap_freeall ( void )
  1406.     {
  1407.     WHEAP *hptr, *pending;
  1408.  
  1409.  
  1410.  
  1411.         /* point to first allocated one
  1412.      */
  1413.     hptr = heap_bottom.whp_next;
  1414.  
  1415.  
  1416.  
  1417.     /* run up chain, removing elelments one at a time
  1418.      */
  1419.     while ( &heap_top != hptr )
  1420.         {
  1421.  
  1422.         pending  = hptr-> whp_next;
  1423.  
  1424.         wheap_free ( hptr );
  1425.  
  1426.         hptr = pending;
  1427.  
  1428.         }    /* end while */
  1429.  
  1430.     /* if needed, erase the disk file
  1431.      * (and clean up for another pass)
  1432.      */
  1433.     if ( hiwater >0 )
  1434.         {
  1435.         /* disk storage has been used, clean up disk and internals
  1436.          */
  1437.         remove ( dskname );
  1438.         hiwater = 0;
  1439.  
  1440.         }
  1441.  
  1442.  
  1443.     if ( xmspresent )
  1444.         {
  1445.         /* we used xms as base memory for disk access...
  1446.          * need to free that handle, too.
  1447.          */
  1448.         xms_free ( &heap_top );
  1449.         }
  1450.  
  1451.  
  1452.  
  1453.     return;        /* wheap_freeall */
  1454.     }
  1455.  
  1456.  
  1457.  
  1458.  
  1459.  
  1460.     /*------------------- end of WHEAP.C -------------------- */
  1461.  
  1462.  
  1463.