home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / pgmutil / val_link.zip / MEMORY.C < prev    next >
Text File  |  1989-02-18  |  11KB  |  263 lines

  1. /*                                 MEMORY.C                                */
  2.  
  3. /* Memory management presents a challenge if one desires to be compatible
  4.    with OS/2.  The problem centers on the fact that memory references
  5.    (e.g., a memory address) differ between the real (8086) and protected
  6.    (80286) modes of operation.  In the real mode, a memory reference is
  7.    is via a "segment/offset" while in the protected mode, a memory reference
  8.    is via a "descriptor/offset".  Both are 32-bit items with the 16-bit
  9.    offset working the same in both.  However, segments and descriptors are
  10.    not necessarily the same.  If compatibility with OS/2 and DOS is an
  11.    objective, then one must not use a descriptor as if it were a segment.
  12.    It is however safe to use a segment as if it were a descriptor.  In
  13.    effect, this means you cannot treat the segment as if it is related to
  14.    a memory address by a factor of 16.  A segment must be treated as if
  15.    were a descriptor.  That is, a segment is treated as a reference (not
  16.    necessarily an address) to the beginning of an area of memory which can
  17.    be up to 64K.  Each byte within the area of memory is accessed via the
  18.    offset mechanism. */
  19.  
  20. /* The data structure for memory is handled as follows:  At the beginning
  21.    of execution, all available far memory is allocated in 64K chunks, with
  22.    a "memory descriptor" for each chunk.  The memory desciptors for these
  23.    chunks are linked together into memory pools.  Initially, all descriptors
  24.    are linked to the free pool.  As a chunk is needed, it is allocated to
  25.    a pool.  Some pools are needed only for a brief time.  In these cases,
  26.    when a chunk is no longer needed it is returned to the free pool. */
  27.  
  28.  
  29. /*+-------------------------------------------------------------------------+
  30.   |                                                                         |
  31.   |                         add_chunk_to_pool                               |
  32.   |                                                                         |
  33.   +-------------------------------------------------------------------------+*/
  34.  
  35. memory_descriptor_ptr add_chunk_to_pool(pool_descriptor_ptr pool,
  36.                                         bit_32 size)
  37. BeginDeclarations
  38. #define Pool                           (*pool)
  39. memory_descriptor_ptr                  desc;
  40. #define Desc                           (*desc)
  41. memory_descriptor_ptr                  prior;
  42. #define Prior                          (*prior)
  43. EndDeclarations
  44. BeginCode
  45.  prior = Null;
  46.  desc  = free_pool.memory_descriptor_list;
  47.  While desc IsNotNull
  48.   BeginWhile
  49.    If Desc.available NotLessThan size
  50.     Then
  51.      If prior IsNull
  52.       Then
  53.        free_pool.memory_descriptor_list  = Desc.next;
  54.       Else
  55.        Prior.next                        = Desc.next;
  56.       EndIf;
  57.      free_pool.pool_size              -= Desc.available;
  58.      Pool.pool_size                   += Desc.available;
  59.      Desc.next                         = Pool.memory_descriptor_list;
  60.      Pool.memory_descriptor_list       = desc;
  61.      far_set(Desc.chunk, 0, Bit_16(Desc.available));
  62.      return(desc);
  63.     EndIf;
  64.    prior = desc;
  65.    Next(desc);
  66.   EndWhile;
  67.  linker_error (8,"No more free far memory for pool \"%s\"\n."
  68.                  "\tTry running again with smaller buffersize and/or\n"
  69.                  "\tvirtualized fixup processing.\n",
  70.                  Pool.pool_id);
  71.  return(desc); /* To kill warning */
  72. EndCode
  73. #undef Pool
  74. #undef Desc
  75. #undef Prior
  76.  
  77. /*+-------------------------------------------------------------------------+
  78.   |                                                                         |
  79.   |                            allocate_memory                              |
  80.   |                                                                         |
  81.   +-------------------------------------------------------------------------+*/
  82.  
  83. byte_ptr allocate_memory (pool_descriptor_ptr pool, bit_32 size)
  84. BeginDeclarations
  85. #define Pool                           (*pool)
  86. #define Desc                           (*desc)
  87. #define Prev                           (*prev)
  88. memory_descriptor_ptr                  desc;
  89. memory_descriptor_ptr                  prev;
  90. byte_ptr                               element;
  91. EndDeclarations
  92. BeginCode
  93.  
  94. /* Traverse the memory descriptor list and allocate the space from the
  95.    first memory descriptor which has enough available space for the entire
  96.    element to be allocated. */
  97.  
  98.  prev = NULL;
  99.  desc = Pool.memory_descriptor_list;
  100.  While desc IsNotNull
  101.   BeginWhile
  102.    If size NotGreaterThan Desc.available
  103.     Then /* We can take the element from this chunk */
  104.      Pool.used_bytes         += size;
  105.      element                  = Desc.unused_base;
  106.      Desc.unused_base        += Bit_16(size);
  107.      Desc.available          -= size;
  108.      If prev IsNotNull
  109.       Then
  110.        Prev.next                   = Desc.next;
  111.        Desc.next                   = Pool.memory_descriptor_list;
  112.        Pool.memory_descriptor_list = desc;
  113.       EndIf;
  114.      return(element);
  115.     EndIf;
  116.    prev = desc;
  117.    Next(desc);
  118.   EndWhile;
  119.  
  120. /* Well, none of the memory descriptors had enough space to allocate this
  121.    element.  So, we will have to get another chunk, add it to this pool and
  122.    allocate the space from the new chunk. */
  123.  
  124.  desc                         = add_chunk_to_pool(pool, size);
  125.  Pool.used_bytes             += size;
  126.  element                      = Desc.unused_base;
  127.  Desc.unused_base            += Bit_16(size);
  128.  Desc.available              -= size;
  129.  return(element);
  130. EndCode
  131. #undef Pool
  132. #undef Desc
  133. #undef Prev
  134.  
  135. /*+-------------------------------------------------------------------------+
  136.   |                                                                         |
  137.   |                           initialize_memory                             |
  138.   |                                                                         |
  139.   |                             O/S dependent                               |
  140.   |                                                                         |
  141.   +-------------------------------------------------------------------------+*/
  142.  
  143. void initialize_memory()
  144. BeginDeclarations
  145. byte huge                             *far_memory;
  146. bit_32                                 far_memory_size;
  147. bit_32                                 size_this_chunk;
  148. bit_16                                 rc;
  149. memory_descriptor_ptr                  desc;
  150. #define Desc                           (*desc)
  151. EndDeclarations
  152. BeginCode
  153. /* First step for PC-DOS is to gobble all free paragraphs above the heap.
  154.    The variable "far_memory" will point to that area. */
  155.  
  156.  inregs.h.ah = 0x48;                     /* DOS allocate memory */
  157.  inregs.x.bx = 0xFFFF;                   /* Ask for too much memory */
  158.  rc = intdos(Addr(inregs),Addr(outregs));/* Do the allocate expecting to fail*/
  159.  If (outregs.x.cflag IsFalse) OrIf (rc IsNot 8)
  160.   Then
  161.    DOS_error("Problem allocating memory above heap.\n");
  162.   EndIf;
  163.  inregs.x.bx = outregs.x.bx;             /* Ask for the right amount this time*/
  164.  DOS_int21("Problem allocating memory above heap.\n");
  165.  
  166.  far_memory      = (byte huge *) MakeFarPtr(outregs.x.ax,0);
  167.  far_memory_size = Bit_32(inregs.x.bx) ShiftedLeft 4;
  168.  If far_memory_size LessThan 65536L
  169.   Then
  170.    linker_error(8,"Too little memory above heap.\n"
  171.                  "\tTry running again with smaller buffersize and/or\n"
  172.                  "\tvirtualized fixup processing.\n");
  173.   EndIf;
  174.  
  175. /* Initialize the static pool with it's first chunk. This is a little
  176.    tricky because the initial value of several data structures are
  177.    initialized simutaneously. */
  178.  
  179.  far_set(BytePtr(far_memory), 0, 0);  /* Clear initial chunk */
  180.  desc                                 = (memory_descriptor_ptr) far_memory;
  181.  static_pool.memory_descriptor_list   = desc;
  182.  static_pool.used_bytes               = sizeof(memory_descriptor_type);
  183.  static_pool.pool_size                =
  184.  Desc.size                            =
  185.  Desc.available                       = 65536L;
  186.  Desc.chunk                           =
  187.  Desc.unused_base                     = BytePtr(far_memory);
  188.  Desc.next                            = NULL;
  189.  far_memory                          += Desc.available;
  190.  far_memory_size                     -= Desc.available;
  191.  Desc.available                      -= sizeof(memory_descriptor_type);
  192.  Desc.unused_base                    += sizeof(memory_descriptor_type);
  193.  
  194. /* Now set up the free pool */
  195.  
  196.  free_pool.pool_size                  =
  197.  free_pool.used_bytes                 = 0L;
  198.  free_pool.memory_descriptor_list     = NULL;
  199.  While far_memory_size IsNotZero
  200.   BeginWhile
  201.    desc = (memory_descriptor_ptr) 
  202.            allocate_memory(Addr(static_pool),
  203.                            Bit_32(sizeof(memory_descriptor_type)));
  204.    If far_memory_size Exceeds 65536L
  205.     Then
  206.      size_this_chunk                  = 65536L;
  207.     Else
  208.      size_this_chunk                  = far_memory_size;
  209.     EndIf;
  210.    Desc.chunk                         =
  211.    Desc.unused_base                   = BytePtr(far_memory);
  212.    Desc.size                          =
  213.    Desc.available                     = size_this_chunk;
  214.    free_pool.pool_size               += size_this_chunk;
  215.    Desc.next                          = free_pool.memory_descriptor_list;
  216.    free_pool.memory_descriptor_list   = desc;
  217.    far_memory                        += size_this_chunk;
  218.    far_memory_size                   -= size_this_chunk;
  219.   EndWhile;
  220.  free_pool.pool_id                   = "Free pool";
  221.  static_pool.pool_id                 = "Static pool";
  222.  dynamic_pool.pool_id                = "Dynamic pool";
  223.  dynamic_pool.memory_descriptor_list = Null;
  224.  dynamic_pool.pool_size              =
  225.  dynamic_pool.used_bytes             = 0L;
  226.  return;
  227. EndCode
  228. #undef Desc
  229.  
  230. /*+-------------------------------------------------------------------------+
  231.   |                                                                         |
  232.   |                              release_pool                               |
  233.   |                                                                         |
  234.   +-------------------------------------------------------------------------+*/
  235.  
  236. void release_pool(pool_descriptor_ptr pool)
  237. BeginDeclarations
  238. #define Pool                           (*pool)
  239. memory_descriptor_ptr                  desc;
  240. #define Desc                           (*desc)
  241. memory_descriptor_ptr                  next;
  242. EndDeclarations
  243. BeginCode
  244.  desc  = Pool.memory_descriptor_list;
  245.  While desc IsNotNull
  246.   BeginWhile
  247.    Desc.available                    = Desc.size;
  248.    Desc.unused_base                  = Desc.chunk;
  249.    free_pool.pool_size              += Desc.available;
  250.    next                              = Desc.next;
  251.    Desc.next                         = free_pool.memory_descriptor_list;
  252.    free_pool.memory_descriptor_list  = desc;
  253.    desc = next;
  254.   EndWhile;
  255.  Pool.memory_descriptor_list = Null;
  256.  Pool.pool_size              =
  257.  Pool.used_bytes             = 0L;
  258.  return;
  259. EndCode
  260. #undef Pool
  261. #undef Desc
  262.  
  263.