unit overinit;
{$F+,O-}

INTERFACE

function heapfunc(size: word): integer;


{ShrinkOverlay:  Free memory by dynamically reducing overlay buffer
                during program execution. "Robbing Peter to pay Paul"

Steve Safigan 8/14/90  CompuServe ID 72251,2274
Universal Tax Systems, Inc.
102 Margo Trail
Rome, GA  30161
(404) 232-7757

Donated to the public domain.
Thanks to Kim Kokonen for providing direction.
Thanks to ????? for upgrading to version 6.0 and for the HEAPERROR hook.

The most common means of reducing run-time memory requirements is by using
overlays.  This presents a paradox, because the overlay buffer must be
fixed at program startup, reducing total free memory.  The programmer is
usually forced to define the smallest overlay buffer he (she) can get away
with in order to leave enough room for dynamic variables.  This slows
program performance as the program has to swap code into and out of the
overlay buffer often.

A better solution is to start the program with a very large overlay buffer
to reduce swapping.  As the program requires more dynamic memory, the
boundary between the overlay buffer and the heap can be adjusted to provide
more memory to the heap, and less to the overlay buffer.  Eventually,
the overlay buffer may be reduced to a minimum size.  At this point, the
program may be thrashing terribly, but it may be more acceptable than
running out of memory completely.

Unfortunately, TP does not support changing the overlay buffer size
after any variables are allocated.  But the routine ShrinkOverlay does.
It works by clearing the overlay buffer, changing the boundary between the
overlay buffer and the heap, then adding a free list entry to the heap.

ShrinkOverlay may be called explicitly by your program, or it may be called
explicitly by a HEAPERROR routine when your program runs out of heap
space.  If you call ShrinkOverlay explicitly, it must take the following
form:

   MEMORY_AMT := $8000
   IF MAXAVAIL < $8000 THEN ShrinkOverlay(MEMORY_AMT);

MEMORY_AMT is the amount of memory to rob from the overlay buffer.  It
must be passed via a variable, because ShrinkOverlay returns the
amount of memory actually freed.  If the overlay buffer is already at
its minimum size, or if no heap free list entries are available,
ShrinkOverlay returns 0.  The maximum amount of memory freed in a single
call to ShrinkOverlay is 64K.  ShrinkOverlay will round the memory freed
to the next higher multiple of 16 bytes, so that it frees an even
number of paragraphs.

You may instead wish to use the supplied HEAPFUNC in order to invoke
ShrinkOverlay automatically when the heap runs out of space.  In order
to use heapfunc, you must include the following line in your main
program:

   heaperror := @heapfunc;

This replaces TP's standard heap error handling routine with HEAPFUNC.


Although calling ShrinkOverlay is as simple as that, there are a few
additional steps needed in order to initialize.  The sample unit OVERINIT
shows initializing the memory buffer in preparation for ShrinkOverlay.
Since this unit initializes the overlay buffer, it should appear first
in your USES clause.  You may replace the overlay initialization section
with your own.

The variable MinimumOverlay must be initialized to the minimum overlay
buffer size your program will accept.  This value must not be less than
the initial value of OVRGETBUF, or you will not be able to fit your
largest overlayed unit into the overlay buffer.

This version was submitted to me as an upgrade to my TP5.5 Version.
Regrettably, I have thrown out the fax I received listing the author of
this version!  If the author would like to identify himself, I would be
happy to give him full credit.

If anybody has any corrections or enhancements to ShrinkOverlay, contact
me at the above address.  Although it seems to work fine on my machine,
I can't warrant that it will work properly in all environments.  I'm
looking for an implementation that would reverse this routine and restore
the overlay buffer to its original size.  Any ideas?}

IMPLEMENTATION

uses
  overlay;

type
  linktype = record
    next: pointer;
    bytes: word;
    paragraphs: word;
  end;

  os = record
    o,s: word;
  end;

var
  minimumoverlay: longint;

procedure shrinkoverlay(var size: word);
var
  tempsize: word;
  work: linktype;
begin
  if ovrgetbuf - size < minimumoverlay then
    size := ovrgetbuf - minimumoverlay;
  size := size - (size mod 16);
  if size > 0 then
  begin
    tempsize := size div 16;
    ovrclearbuf;
    dec(ovrheapend,tempsize);
    os(heaporg).s := ovrheapend;
    os(heaporg).o := 0;
    work.next := freelist;
    work.paragraphs := tempsize;
    work.bytes := 0;
    move(work,heaporg^,8);
    freelist := heaporg;
    if ovrgetretry > ovrgetbuf then
      ovrsetretry(ovrgetbuf div 3);
  end;
end;

function heapfunc(size: word): integer;
var
  x: word;
begin
  if size > 0 then
  begin
    x := size + 16;
    if maxavail < size then
      shrinkoverlay(x)
    else
      x := 0;
    if x < size then
      heapfunc := 0
    else
      heapfunc := 2;
  end;
end;


begin
  minimumoverlay := ovrgetbuf;
  ovrsetbuf(ovrgetbuf + $F000);  {set your own value here}
  ovrsetretry(ovrgetbuf div 3);
end.