0. Overview
1-3. Actions within the far heap
4. Summary

===

0. Overview
===========

The far (or huge) heap consists of fragments.

Fragments are linked together by a single linked list and are
described by four values:
1) the pointer to the next fragment,
2) the size of the fragment,
3) the handle associated to this fragment to be passed to DOS API functions,&
4) the pointer to the very first node within the fragment.

The first fragment is initialized by the startup code and is situated directly
above the stack segment. It is initialized with a HEAP_END node. This
fragment is never deleted, it can be shrunk down to contain one node:
the HEAP_END node marking the end of the far heap.

Like the local heap the nodes of the far heap form a single-linked list;
totally ignoring the fragmentation. This is achieved by surround holes
between two fragments by a HEAP_USED node. See below for further detailes.

Doing so, hides the fragmentation to most of the mechanisms and, thus,
easies the implementation. Because of the way to point to the next node
it is not important, if the next fragment physically preceeds or follows
a fragment.

Each node is described by two values:
1) the type of the node (same as local heap),
2) the pointer to the next node.

Unlike the local heap the far heap can contain nodes of nodes with a size
greater or smaller than 64KB. One way to implement would be to round
up all nodes to a size of a multiple of a paragraphe size, but with a
normal program that needs much rather than large chunks of data, the far
heap would be filled with many pad bytes. Therefore the next node is
pointed to by a pointer rather then by the size of the data portion.

Unlike the local heap the HEAP_END node within the far heap consists
of the full structure of a HEAP_USED node, and not just of the node
type flag. For the reason see the "Allocating a new node" section.

Actions over the far heap:
1. Allocating a new node,
2. Deallocating an existing node,&
3. Resizing an existing node.

===

1. Allocating a new node
========================

Basicly the mechanism is like the within the local heap:
All nodes of the type HEAP_UNUSED are touched and the first node that
is capable of holding the requested amount of bytes is choosen. This
node is splitted, if possible.

If the search failed (or, the HEAP_END node has been found), the new node
cannot be simply appended like within the local heap, because the HEAP_END
node simply marks the _end_of_the_physical_memory_ available to the
program. Therefore the memory must be extended.

The first try is to extend the last fragment, which also contains the
HEAP_END node the search algorithm hit currently. The fragment is tried
to grow by paragraphes_of(size - free_bytes_of_last_paragraphe). There is
a little chance that the new node can be placed into the unused portion
of the last paragraphe, but this case is ignored for this explanation.

The fragment is resized by passing its DOS handle to the DOS Resize
Memory function and the new size.

On success, the node is created and the HEAP_END node appended.

On failure, a new fragment of at least the requested size is allocated.

On failure, the system is definitely unable to allocated memory of the
requested size and returns NULL.

On success, the new fragment is linked into the chain of fragments. Then
the current HEAP_END node is changed into a HEAP_USED node and the "next
node" pointer is initialized with the first node of the newly allocated
fragment. The first node of the new fragment is now initialized as the
allocated node to be returned and the HEAP_END node is appended.

The above mechanism of linking two fragments requires that the HEAP_END
node foresees the possibility to be turned into a HEAP_USED node and, thus,
the required memory is allocated for each HEAP_END node.

2. Deallocating a node
======================

Like the local heap the node to be deallocated is searched, and if
found turned into a HEAP_UNUSED node.

If the turned node is preceeded by a HEAP_UNUSED node, it is joined
with the previous node.

If the, possibly joined, node is followed by a HEAP_UNSED node, it
is joined with the following one.

If the following node is HEAP_END, the fragment is resized to the lowest
number of paragraphes that are able to hold the HEAP_END node.

If the new HEAP_END node becomes the first node of the fragment and
is not situated within the first fragment, the current fragment is
deallocted, and the previous fragment becomes the "last fragment".
The very last HEAP_USED node is turned into a HEAP_END node, as this
node was used to step over the hole between two fragments.

3. Resizing a node
===================

This algorithm follows the one for the local heap:
a) If the node shrinks, the node is splitted; the node is not moved to
somewhere else.
b) If the node grows, the first try is the extend the node into the
immediately following one, if that is an HEAP_UNUSED one. Otherwise,
the node is temporarily deallocated and a new node is searched and
the data portion is moved there.

When the node is "temporarily deallocated" the fragment does _not_ shrink,
if the node is the last within the chain, otherwise the shrink-process
could destroy the data.

===

4. Summary
==========

The fact that the last node of each fragment is of the type HEAP_USED
prevents any algorithm from touching this node. Only the two special
algorithms that deal with creating and destroying a fragment know of
the special meaning of this node.

This implementation of the far heap follows the one of the local heap
in many terms and should be easy to implement therefore.

