1107 lines
188 KiB
HTML
1107 lines
188 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>Memory</title>
|
|
<link href="../docs-assets/Breadcrumbs.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<meta name="viewport" content="width=device-width initial-scale=1">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta http-equiv="Content-Language" content="en-gb">
|
|
|
|
<link href="../docs-assets/Base.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<script>
|
|
function togglePopup(material_id) {
|
|
var popup = document.getElementById(material_id);
|
|
popup.classList.toggle("show");
|
|
}
|
|
</script>
|
|
|
|
<link href="../docs-assets/Popups.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<script>
|
|
MathJax = {
|
|
tex: {
|
|
inlineMath: '$', '$'], ['\\(', '\\)'
|
|
},
|
|
svg: {
|
|
fontCache: 'global'
|
|
}
|
|
};
|
|
</script>
|
|
<script type="text/javascript" id="MathJax-script" async
|
|
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js">
|
|
</script>
|
|
|
|
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
|
|
</head>
|
|
<body>
|
|
<nav role="navigation">
|
|
<h1><a href="../index.html">
|
|
<img src="../docs-assets/Octagram.png" width=72 height=72">
|
|
</a></h1>
|
|
<ul><li><a href="../inweb/index.html">inweb</a></li>
|
|
</ul><h2>Foundation Module</h2><ul>
|
|
<li><a href="index.html"><span class="selectedlink">foundation</span></a></li>
|
|
<li><a href="../foundation-test/index.html">foundation-test</a></li>
|
|
</ul><h2>Example Webs</h2><ul>
|
|
<li><a href="../goldbach/index.html">goldbach</a></li>
|
|
<li><a href="../twinprimes/twinprimes.html">twinprimes</a></li>
|
|
<li><a href="../eastertide/index.html">eastertide</a></li>
|
|
</ul><h2>Repository</h2><ul>
|
|
<li><a href="https://github.com/ganelson/inweb"><img src="../docs-assets/github.png" height=18> github</a></li>
|
|
</ul><h2>Related Projects</h2><ul>
|
|
<li><a href="../../../inform/docs/index.html">inform</a></li>
|
|
<li><a href="../../../intest/docs/index.html">intest</a></li>
|
|
|
|
</ul>
|
|
</nav>
|
|
<main role="main">
|
|
|
|
<!--Weave of 'Memory' generated by Inweb-->
|
|
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="index.html">foundation</a></li><li><a href="index.html#2">Chapter 2: Memory, Streams and Collections</a></li><li><b>Memory</b></li></ul><p class="purpose">To allocate memory suitable for the dynamic creation of objects of different sizes, placing some larger objects automatically into doubly linked lists and assigning each a unique allocation ID number.</p>
|
|
|
|
<ul class="toc"><li><a href="2-mmr.html#SP1">§1. Memory manager</a></li><li><a href="2-mmr.html#SP6">§6. Architecture</a></li><li><a href="2-mmr.html#SP7">§7. Level 1: memory blocks</a></li><li><a href="2-mmr.html#SP13">§13. Level 2: memory frames and integrity checking</a></li><li><a href="2-mmr.html#SP17">§17. Level 3: managing linked lists of allocated objects</a></li><li><a href="2-mmr.html#SP19">§19. Allocator functions created by macros</a></li><li><a href="2-mmr.html#SP21">§21. Expanding many macros</a></li><li><a href="2-mmr.html#SP22">§22. Simple memory allocations</a></li><li><a href="2-mmr.html#SP28">§28. Text storage</a></li><li><a href="2-mmr.html#SP32">§32. Memory usage report</a></li><li><a href="2-mmr.html#SP36">§36. Run-time pointer type checking</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="inwebparagraph"><a id="SP1"></a><b>§1. Memory manager. </b>This allocates memory as needed to store the numerous "objects" of different
|
|
sizes, all C structures. There's no garbage collection because nothing is ever
|
|
destroyed. Each type has its own doubly-linked list, and in each type the
|
|
objects created are given unique IDs (within that type) counting upwards
|
|
from 0. These IDs will be unique across all threads.
|
|
</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP2"></a><b>§2. </b>Before going much further, we will need to anticipate what the memory
|
|
manager wants. An "object" is a copy in memory of a C <code class="display"><span class="extract-syntax">struct</span></code>; thus,
|
|
a plain <code class="display"><span class="extract-syntax">int</span></code> is not an object. The memory manager can only deal with
|
|
a given type of <code class="display"><span class="extract-syntax">struct</span></code> if it contains three special elements, and we
|
|
define those using a macro. Thus, if the user wants to allocate larger
|
|
structures of type <code class="display"><span class="extract-syntax">thingummy</span></code>, then it needs to be defined like so:
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">thingummy</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">whatsit</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">text_stream</span><span class="plain-syntax"> *</span><span class="identifier-syntax">doobrey</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> ...</span>
|
|
<span class="plain-syntax"> </span><span class="constant-syntax">MEMORY_MANAGEMENT</span>
|
|
<span class="plain-syntax"> }</span>
|
|
</pre>
|
|
<p class="inwebparagraph">The caveat about "larger structures" is that smaller objects can instead be
|
|
stored in arrays, to reduce memory and speed overheads. Their structure
|
|
declarations do not include the following macro; they do not have unique
|
|
IDs; and they cannot be iterated over.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="constant-syntax">MEMORY_MANAGEMENT</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">allocation_id</span><span class="plain-syntax">; </span><span class="comment"> Numbered from 0 upwards in creation order</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax">; </span><span class="comment"> Next object in double-linked list</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">; </span><span class="comment"> Previous object in double-linked list</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP3"></a><b>§3. </b>It is also necessary to define a constant in the following enumeration
|
|
family: for <code class="display"><span class="extract-syntax">thingummy</span></code>, it would be <code class="display"><span class="extract-syntax">thingummy_MT</span></code>. Had it been a smaller
|
|
object, it would have been <code class="display"><span class="extract-syntax">thingummy_array_MT</span></code> instead.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">There is no significance to the order in which structures are registered
|
|
with the memory system. The ones here are those needed by Foundation.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">filename_MT</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">pathname_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">string_storage_area_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">scan_directory_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_datum_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_volume_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_chapter_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_page_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_image_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">HTML_file_state_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">HTML_tag_array_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">text_stream_array_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">command_line_switch_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">dictionary_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">dict_entry_array_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">debugging_aspect_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">linked_list_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">linked_list_item_array_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">match_avinue_array_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">match_trie_array_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">method_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">method_set_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_mark_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">semantic_version_number_holder_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">semver_range_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">web_md_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">chapter_md_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">section_md_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">web_bibliographic_datum_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">module_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">module_search_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">heterogeneous_tree_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">tree_type_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">tree_node_MT</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">tree_node_type_MT</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP4"></a><b>§4. </b>For each type of object to be allocated, a single structure of the
|
|
following design is maintained. Types which are allocated individually,
|
|
like world objects, have <code class="display"><span class="extract-syntax">no_allocated_together</span></code> set to 1, and the doubly
|
|
linked list is of the objects themselves. For types allocated in small
|
|
arrays (typically of 100 objects at a time), <code class="display"><span class="extract-syntax">no_allocated_together</span></code> is set
|
|
to the number of objects in each completed array (so, typically 100) and
|
|
the doubly linked list is of the arrays.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">allocation_status_structure</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="comment"> actually needed for allocation purposes:</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">objects_allocated</span><span class="plain-syntax">; </span><span class="comment"> total number of objects (or arrays) ever allocated</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">first_in_memory</span><span class="plain-syntax">; </span><span class="comment"> head of doubly linked list</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">last_in_memory</span><span class="plain-syntax">; </span><span class="comment"> tail of doubly linked list</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="comment"> used only to provide statistics for the debugging log:</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">name_of_type</span><span class="plain-syntax">; </span><span class="comment"> e.g., </span><code class="display"><span class="extract-syntax">"lexicon_entry_MT"</span></code>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes_allocated</span><span class="plain-syntax">; </span><span class="comment"> total allocation for this type of object, not counting overhead</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">objects_count</span><span class="plain-syntax">; </span><span class="comment"> total number currently in existence (i.e., undeleted)</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">no_allocated_together</span><span class="plain-syntax">; </span><span class="comment"> number of objects in each array of this type of object</span>
|
|
<span class="plain-syntax">} </span><span class="reserved-syntax">allocation_status_structure</span><span class="plain-syntax">;</span>
|
|
</pre><ul class="endnotetexts"><li>The structure allocation_status_structure is private to this section.</li></ul><p class="inwebparagraph"><a id="SP5"></a><b>§5. </b>The memory allocator itself needs some memory, but only a fixed-size and
|
|
fairly small array of the structures defined above. The allocator can safely
|
|
begin as soon as this is initialised.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">allocation_status_structure</span><span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">];</span>
|
|
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::start</span><button class="popup" onclick="togglePopup('usagePopup1')">...<span class="popuptext" id="usagePopup1">Usage of <b>Memory::start</b>:<br>Foundation Module - <a href="1-fm.html#SP8">§8</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax"><</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">last_in_memory</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">name_of_type</span><span class="plain-syntax"> = </span><span class="string-syntax">"unused"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP22" class="internal">Memory::name_fundamental_reasons</a><span class="plain-syntax">();</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP6"></a><b>§6. Architecture. </b>The memory manager is built in three levels, with its interface to the user
|
|
being entirely at level 3 (except that when it shuts down it calls a level 1
|
|
routine to free everything). Each level uses the one below it.
|
|
</p>
|
|
|
|
</li><li>(3) Managing linked lists of large objects, within which objects can be
|
|
created at any point, and from which objects can be deleted; and providing
|
|
a way to create new small objects of any given type.
|
|
</li><li>(2) Allocating some thousands of memory frames, each holding one large object
|
|
or an array of small objects.
|
|
</li><li>(1) Allocating and freeing a few dozen large blocks of contiguous memory.
|
|
</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP7"></a><b>§7. Level 1: memory blocks. </b>Memory is allocated in blocks within which objects are allocated as
|
|
needed. The "safety margin" is the number of spare bytes left blank at the
|
|
end of each object: this is done because we want to be paranoid about
|
|
compilers on different architectures aligning structures to different
|
|
boundaries (multiples of 4, 8, 16, etc.). Each block also ends with a
|
|
firebreak of zeroes, which ought never to be touched: we want to minimise the
|
|
chance of a mistake causing a memory exception which crashes the compiler,
|
|
because if that happens it will be difficult to recover the circumstances from
|
|
the debugging log.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="constant-syntax">SAFETY_MARGIN</span><span class="plain-syntax"> </span><span class="constant-syntax">128</span>
|
|
<span class="definition-keyword">define</span> <span class="constant-syntax">BLANK_END_SIZE</span><span class="plain-syntax"> </span><span class="constant-syntax">256</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP8"></a><b>§8. </b>At present <code class="display"><span class="extract-syntax">MEMORY_GRANULARITY</span></code> is 800K. This is the quantity of memory
|
|
allocated by each individual <code class="display"><span class="extract-syntax">malloc</span></code> call.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">After <code class="display"><span class="extract-syntax">MAX_BLOCKS_ALLOWED</span></code> blocks, we throw in the towel: we must have
|
|
fallen into an endless loop which creates endless new objects somewhere.
|
|
(If this ever happens, it would be a bug: the point of this mechanism is to
|
|
be able to recover. Without this safety measure, OS X in particular would
|
|
grind slowly to a halt, never refusing a <code class="display"><span class="extract-syntax">malloc</span></code>, until the user was
|
|
unable to get the GUI responsive enough to kill the process.)
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="constant-syntax">MAX_BLOCKS_ALLOWED</span><span class="plain-syntax"> </span><span class="constant-syntax">15000</span>
|
|
<span class="definition-keyword">define</span> <span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax"> </span><span class="constant-syntax">100</span><span class="plain-syntax">*1024*8 </span><span class="comment"> which must be divisible by 1024</span>
|
|
</pre>
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">no_blocks_allocated</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_objects_allocated</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="comment"> a potentially larger number, used only for the debugging log</span>
|
|
</pre><p class="inwebparagraph"><a id="SP9"></a><b>§9. </b>Memory blocks are stored in a linked list, and we keep track of the
|
|
size of the current block: that is, the block at the tail of the list.
|
|
Each memory block consists of a header structure, followed by <code class="display"><span class="extract-syntax">SAFETY_MARGIN</span></code>
|
|
null bytes, followed by actual data.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">block_number</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">the_memory</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">} </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax">;</span>
|
|
</pre><ul class="endnotetexts"><li>The structure memblock_header is accessed in 2/trs, 4/taa and here.</li></ul><p class="inwebparagraph"><a id="SP10"></a><b>§10. </b></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">first_memblock_header</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="comment"> head of list of memory blocks</span>
|
|
<span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="comment"> tail of list of memory blocks</span>
|
|
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="comment"> number of bytes so far used in the tail memory block</span>
|
|
</pre><p class="inwebparagraph"><a id="SP11"></a><b>§11. </b>The actual allocation and deallocation is performed by the following
|
|
pair of routines.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::allocate_another_block</span><button class="popup" onclick="togglePopup('usagePopup2')">...<span class="popuptext" id="usagePopup2">Usage of <b>Memory::allocate_another_block</b>:<br><a href="2-mmr.html#SP16_1">§16.1</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Allocate and zero out a block of memory, making cp point to it</span> <span class="named-paragraph-number">11.1</span>><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax"> = </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax">) + </span><span class="constant-syntax">SAFETY_MARGIN</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax">-></span><span class="element-syntax">the_memory</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) (</span><span class="identifier-syntax">cp</span><span class="plain-syntax"> + </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax">);</span>
|
|
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Add new block to the tail of the list of memory blocks</span> <span class="named-paragraph-number">11.2</span>><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP11_1"></a><b>§11.1. </b>Note that <code class="display"><span class="extract-syntax">cp</span></code> and <code class="display"><span class="extract-syntax">mh</span></code> are set to the same value: they merely have different
|
|
pointer types as far as the C compiler is concerned.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Allocate and zero out a block of memory, making cp point to it</span> <span class="named-paragraph-number">11.1</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">no_blocks_allocated</span><span class="plain-syntax">++ >= </span><span class="constant-syntax">MAX_BLOCKS_ALLOWED</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><a href="3-em.html#SP2" class="internal">Errors::fatal</a><span class="plain-syntax">(</span>
|
|
<span class="plain-syntax"> </span><span class="string-syntax">"the memory manager has halted inweb, which seems to be generating "</span>
|
|
<span class="plain-syntax"> </span><span class="string-syntax">"endless structures. Presumably it is trapped in a loop"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP15" class="internal">Memory::check_memory_integrity</a><span class="plain-syntax">();</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">cp</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *) (</span><a href="2-mmr.html#SP35" class="internal">Memory::paranoid_calloc</a><span class="plain-syntax">(</span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">, </span><span class="constant-syntax">1</span><span class="plain-syntax">));</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">cp</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><a href="3-em.html#SP2" class="internal">Errors::fatal</a><span class="plain-syntax">(</span><span class="string-syntax">"Run out of memory: malloc failed"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax"><</span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP11">§11</a>.</li></ul><p class="inwebparagraph"><a id="SP11_2"></a><b>§11.2. </b>As can be seen, memory block numbers count upwards from 0 in order of
|
|
their allocation.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Add new block to the tail of the list of memory blocks</span> <span class="named-paragraph-number">11.2</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax">-></span><span class="element-syntax">block_number</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">first_memblock_header</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax">-></span><span class="element-syntax">block_number</span><span class="plain-syntax"> = </span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax">-></span><span class="element-syntax">block_number</span><span class="plain-syntax"> + </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax">-></span><span class="identifier-syntax">next</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP11">§11</a>.</li></ul><p class="inwebparagraph"><a id="SP12"></a><b>§12. </b>Freeing all this memory again is just a matter of freeing each block
|
|
in turn, but of course being careful to avoid following links in a just-freed
|
|
block.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::free</span><button class="popup" onclick="togglePopup('usagePopup3')">...<span class="popuptext" id="usagePopup3">Usage of <b>Memory::free</b>:<br>Foundation Module - <a href="1-fm.html#SP9">§9</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP30" class="internal">Memory::free_ssas</a><span class="plain-syntax">();</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mh</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first_memblock_header</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">mh</span><span class="plain-syntax"> != </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_mh</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mh</span><span class="plain-syntax">-></span><span class="element-syntax">next</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">p</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax">(</span><span class="identifier-syntax">p</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax"> = </span><span class="identifier-syntax">next_mh</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP13"></a><b>§13. Level 2: memory frames and integrity checking. </b>Within these extensive blocks of contiguous memory, we place the actual
|
|
objects in between "memory frames", which are only used at present to police
|
|
the integrity of memory: again, finding obscure and irritating memory-corruption
|
|
bugs is more important to us than saving bytes. Each memory frame wraps either
|
|
a single large object, or a single array of small objects.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="constant-syntax">INTEGRITY_NUMBER</span><span class="plain-syntax"> </span><span class="constant-syntax">0x12345678</span><span class="plain-syntax"> </span><span class="comment"> a value unlikely to be in memory just by chance</span>
|
|
</pre>
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">integrity_check</span><span class="plain-syntax">; </span><span class="comment"> this should always contain the </span><code class="display"><span class="extract-syntax">INTEGRITY_NUMBER</span></code>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_frame</span><span class="plain-syntax">; </span><span class="comment"> next frame in the list of memory frames</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">; </span><span class="comment"> type of object stored in this frame</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">allocation_id</span><span class="plain-syntax">; </span><span class="comment"> allocation ID number of object stored in this frame</span>
|
|
<span class="plain-syntax">} </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax">;</span>
|
|
</pre><ul class="endnotetexts"><li>The structure memory_frame is private to this section.</li></ul><p class="inwebparagraph"><a id="SP14"></a><b>§14. </b>There is a single linked list of all the memory frames, perhaps of about
|
|
10000 entries in length, beginning here. (These frames live in different memory
|
|
blocks, but we don't need to worry about that.)
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="comment"> earliest memory frame ever allocated</span>
|
|
<span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">last_memory_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="comment"> most recent memory frame allocated</span>
|
|
</pre><p class="inwebparagraph"><a id="SP15"></a><b>§15. </b>If the integrity numbers of every frame are still intact, then it is pretty
|
|
unlikely that any bug has caused memory to overwrite one frame into another.
|
|
<code class="display"><span class="extract-syntax">Memory::check_memory_integrity</span></code> might on very large runs be run often, if we didn't
|
|
prevent this: since the number of calls would be roughly proportional to
|
|
memory usage, we would implicitly have an \(O(n^2)\) running time in the
|
|
amount of storage \(n\) allocated.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">calls_to_cmi</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::check_memory_integrity</span><button class="popup" onclick="togglePopup('usagePopup4')">...<span class="popuptext" id="usagePopup4">Usage of <b>Memory::check_memory_integrity</b>:<br><a href="2-mmr.html#SP11_1">§11.1</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">c</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">c</span><span class="plain-syntax"> = </span><span class="identifier-syntax">calls_to_cmi</span><span class="plain-syntax">++;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!((</span><span class="identifier-syntax">c</span><span class="plain-syntax"><10) || (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> == </span><span class="constant-syntax">100</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> == </span><span class="constant-syntax">1000</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> == </span><span class="constant-syntax">10000</span><span class="plain-syntax">))) </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax">; </span><span class="identifier-syntax">mf</span><span class="plain-syntax">; </span><span class="identifier-syntax">c</span><span class="plain-syntax">++, </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">next_frame</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">integrity_check</span><span class="plain-syntax"> != </span><span class="constant-syntax">INTEGRITY_NUMBER</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><a href="3-em.html#SP2" class="internal">Errors::fatal</a><span class="plain-syntax">(</span><span class="string-syntax">"Memory manager failed integrity check"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::debug_memory_frames</span><button class="popup" onclick="togglePopup('usagePopup5')">...<span class="popuptext" id="usagePopup5">Usage of <b>Memory::debug_memory_frames</b>:<br>none</span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">to</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">c</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax">; (</span><span class="identifier-syntax">mf</span><span class="plain-syntax">) && (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> <= </span><span class="identifier-syntax">to</span><span class="plain-syntax">); </span><span class="identifier-syntax">c</span><span class="plain-syntax">++, </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">next_frame</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> >= </span><span class="identifier-syntax">from</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">desc</span><span class="plain-syntax"> = </span><span class="string-syntax">"corrupt"</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">integrity_check</span><span class="plain-syntax"> == </span><span class="constant-syntax">INTEGRITY_NUMBER</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">desc</span><span class="plain-syntax"> = </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">name_of_type</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP16"></a><b>§16. </b>We have seen how memory is allocated in large blocks, and that a linked
|
|
list of memory frames will live inside those blocks; we have seen how the
|
|
list is checked for integrity; but we not seen how it is built. Every
|
|
memory frame is created by the following function:
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::allocate</span><button class="popup" onclick="togglePopup('usagePopup6')">...<span class="popuptext" id="usagePopup6">Usage of <b>Memory::allocate</b>:<br><a href="2-mmr.html#SP19">§19</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">extent</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes_free_in_current_memblock</span><span class="plain-syntax">, </span><span class="identifier-syntax">extent_without_overheads</span><span class="plain-syntax"> = </span><span class="identifier-syntax">extent</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">extent</span><span class="plain-syntax"> += </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax">); </span><span class="comment"> each allocation is preceded by a memory frame</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">extent</span><span class="plain-syntax"> += </span><span class="constant-syntax">SAFETY_MARGIN</span><span class="plain-syntax">; </span><span class="comment"> each allocation is followed by </span><code class="display"><span class="extract-syntax">SAFETY_MARGIN</span></code><span class="comment"> null bytes</span>
|
|
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Ensure that the current memory block has room for this many bytes</span> <span class="named-paragraph-number">16.1</span>><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">cp</span><span class="plain-syntax"> = ((</span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *) (</span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax">-></span><span class="element-syntax">the_memory</span><span class="plain-syntax">)) + </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax"> += </span><span class="identifier-syntax">extent</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">; </span><span class="comment"> the new memory frame,</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">cp</span><span class="plain-syntax"> = </span><span class="identifier-syntax">cp</span><span class="plain-syntax"> + </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax">); </span><span class="comment"> following which is the actual allocated data</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">integrity_check</span><span class="plain-syntax"> = </span><span class="constant-syntax">INTEGRITY_NUMBER</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">allocation_id</span><span class="plain-syntax"> = </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">mem_type</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Add the new memory frame to the big linked list of all frames</span> <span class="named-paragraph-number">16.2</span>><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Update the allocation status for this type of object</span> <span class="named-paragraph-number">16.3</span>><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">total_objects_allocated</span><span class="plain-syntax">++;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP16_1"></a><b>§16.1. </b>The granularity error below will be triggered the first time a particular
|
|
object type is allocated. So this is not a potential time-bomb just waiting
|
|
for a user with a particularly long and involved source text to discover.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Ensure that the current memory block has room for this many bytes</span> <span class="named-paragraph-number">16.1</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><a href="2-mmr.html#SP11" class="internal">Memory::allocate_another_block</a><span class="plain-syntax">();</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_free_in_current_memblock</span><span class="plain-syntax"> = </span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax"> - (</span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax"> + </span><span class="identifier-syntax">extent</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bytes_free_in_current_memblock</span><span class="plain-syntax"> < </span><span class="constant-syntax">BLANK_END_SIZE</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP11" class="internal">Memory::allocate_another_block</a><span class="plain-syntax">();</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">extent</span><span class="plain-syntax">+</span><span class="constant-syntax">BLANK_END_SIZE</span><span class="plain-syntax"> >= </span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><a href="3-em.html#SP2" class="internal">Errors::fatal</a><span class="plain-syntax">(</span><span class="string-syntax">"Memory manager failed because granularity too low"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> }</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP16">§16</a>.</li></ul><p class="inwebparagraph"><a id="SP16_2"></a><b>§16.2. </b>New memory frames are added to the tail of the list:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Add the new memory frame to the big linked list of all frames</span> <span class="named-paragraph-number">16.2</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-></span><span class="element-syntax">next_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">last_memory_frame</span><span class="plain-syntax">-></span><span class="element-syntax">next_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">last_memory_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP16">§16</a>.</li></ul><p class="inwebparagraph"><a id="SP16_3"></a><b>§16.3. </b>See the definition of <code class="display"><span class="extract-syntax">alloc_status</span></code> above.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Update the allocation status for this type of object</span> <span class="named-paragraph-number">16.3</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">last_in_memory</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">++;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax"> += </span><span class="identifier-syntax">extent_without_overheads</span><span class="plain-syntax">;</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP16">§16</a>.</li></ul><p class="inwebparagraph"><a id="SP17"></a><b>§17. Level 3: managing linked lists of allocated objects. </b>We define macros which look as if they are functions, but for which one
|
|
argument is the name of a type: expanding these macros provides suitable C
|
|
functions to handle each possible type. These macros provide the interface
|
|
through which all other sections allocate and leaf through memory.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Note that Inweb allows multi-line macro definitions without backslashes
|
|
to continue them, unlike ordinary C. Otherwise these are "standard"
|
|
macros, though this was my first brush with the <code class="display"><span class="extract-syntax">##</span></code> concatenation
|
|
operator: basically <code class="display"><span class="extract-syntax">CREATE(thing)</span></code> expands into <code class="display"><span class="extract-syntax">(allocate_thing())</span></code>
|
|
because of the <code class="display"><span class="extract-syntax">##</span></code>. (See Kernighan and Ritchie, section 4.11.2.)
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">CREATE</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">())</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">COPY</span><span class="plain-syntax">(</span><span class="identifier-syntax">to</span><span class="plain-syntax">, </span><span class="identifier-syntax">from</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">copy_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">to</span><span class="plain-syntax">, </span><span class="identifier-syntax">from</span><span class="plain-syntax">))</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">CREATE_BEFORE</span><span class="plain-syntax">(</span><span class="identifier-syntax">existing</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_before</span><span class="plain-syntax">(</span><span class="identifier-syntax">existing</span><span class="plain-syntax">))</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">DESTROY</span><span class="plain-syntax">(</span><span class="identifier-syntax">this</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">deallocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">this</span><span class="plain-syntax">))</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">FIRST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax">)</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">LAST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">last_in_memory</span><span class="plain-syntax">)</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">NEXT_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">this</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) (</span><span class="identifier-syntax">this</span><span class="plain-syntax">-></span><span class="identifier-syntax">next_structure</span><span class="plain-syntax">))</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">PREV_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">this</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) (</span><span class="identifier-syntax">this</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">))</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">NUMBER_CREATED</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</span><span class="plain-syntax">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP18"></a><b>§18. </b>The following macros are widely used (well, the first one is, anyway)
|
|
for looking through the double linked list of existing objects of a
|
|
given type.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">LOOP_OVER</span><span class="plain-syntax">(</span><span class="identifier-syntax">var</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">var</span><span class="plain-syntax">=</span><span class="identifier-syntax">FIRST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">); </span><span class="identifier-syntax">var</span><span class="plain-syntax"> != </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="identifier-syntax">var</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NEXT_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">var</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">))</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">LOOP_BACKWARDS_OVER</span><span class="plain-syntax">(</span><span class="identifier-syntax">var</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">var</span><span class="plain-syntax">=</span><span class="identifier-syntax">LAST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">); </span><span class="identifier-syntax">var</span><span class="plain-syntax"> != </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="identifier-syntax">var</span><span class="plain-syntax"> = </span><span class="identifier-syntax">PREV_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">var</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">))</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP19"></a><b>§19. Allocator functions created by macros. </b>The following macros generate a family of systematically named functions.
|
|
For instance, we shall shortly expand <code class="display"><span class="extract-syntax">ALLOCATE_INDIVIDUALLY(parse_node)</span></code>,
|
|
which will expand to three functions: <code class="display"><span class="extract-syntax">allocate_parse_node</span></code>,
|
|
<code class="display"><span class="extract-syntax">deallocate_parse_node</span></code> and <code class="display"><span class="extract-syntax">allocate_parse_node_before</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Quaintly, <code class="display"><span class="extract-syntax">#type_name</span></code> expands into the value of <code class="display"><span class="extract-syntax">type_name</span></code> put within
|
|
double-quotes.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">NEW_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) </span><a href="2-mmr.html#SP16" class="internal">Memory::allocate</a><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">, </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">)))</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">MAKE_REFERENCE_ROUTINES</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="identifier-syntax">name_of_type</span><span class="plain-syntax"> = #</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">LAST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">new_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NEW_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-></span><span class="element-syntax">allocation_id</span><span class="plain-syntax"> = </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">-1;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-></span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax"> != </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">-></span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="identifier-syntax">objects_count</span><span class="plain-syntax">++;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="identifier-syntax">deallocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">kill_me</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">PREV_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">kill_me</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NEXT_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">kill_me</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax"> = </span><span class="identifier-syntax">next_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">-></span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">next_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">next_obj</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">last_in_memory</span><span class="plain-syntax"> = </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">next_obj</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="identifier-syntax">objects_count</span><span class="plain-syntax">--;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
<span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_before</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">existing</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">new_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">();</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">deallocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">existing</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">existing</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> != </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">existing</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">)-></span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-></span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">existing</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">existing</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="identifier-syntax">objects_count</span><span class="plain-syntax">++;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="identifier-syntax">copy_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">to</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">from</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to</span><span class="plain-syntax">-></span><span class="identifier-syntax">next_structure</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">aid</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to</span><span class="plain-syntax">-></span><span class="element-syntax">allocation_id</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> *</span><span class="identifier-syntax">to</span><span class="plain-syntax"> = *</span><span class="identifier-syntax">from</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">to</span><span class="plain-syntax">-></span><span class="element-syntax">allocation_id</span><span class="plain-syntax"> = </span><span class="identifier-syntax">aid</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">to</span><span class="plain-syntax">-></span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">next_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">to</span><span class="plain-syntax">-></span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP20"></a><b>§20. </b><code class="display"><span class="extract-syntax">ALLOCATE_IN_ARRAYS</span></code> is still more obfuscated. When we
|
|
<code class="display"><span class="extract-syntax">ALLOCATE_IN_ARRAYS(X, 100)</span></code>, the result will be definitions of a new type
|
|
<code class="display"><span class="extract-syntax">X_block</span></code> and functions <code class="display"><span class="extract-syntax">allocate_X</span></code>, <code class="display"><span class="extract-syntax">allocate_X_block</span></code>,
|
|
<code class="display"><span class="extract-syntax">deallocate_X_block</span></code> and <code class="display"><span class="extract-syntax">allocate_X_block_before</span></code> (though the last is not
|
|
destined ever to be used). Note that we are not provided with the means to
|
|
deallocate individual objects this time: that's the trade-off for
|
|
allocating in blocks.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">NO_TO_ALLOCATE_TOGETHER</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">MAKE_REFERENCE_ROUTINES</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array_MT</span><span class="plain-syntax">)</span>
|
|
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">used</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> </span><span class="identifier-syntax">array</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_TO_ALLOCATE_TOGETHER</span><span class="plain-syntax">];</span>
|
|
<span class="plain-syntax"> </span><span class="constant-syntax">MEMORY_MANAGEMENT</span>
|
|
<span class="plain-syntax">} </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">;</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) ||</span>
|
|
<span class="plain-syntax"> (</span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">-></span><span class="identifier-syntax">used</span><span class="plain-syntax"> >= </span><span class="identifier-syntax">NO_TO_ALLOCATE_TOGETHER</span><span class="plain-syntax">)) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array_MT</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NO_TO_ALLOCATE_TOGETHER</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> = </span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">();</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">-></span><span class="identifier-syntax">used</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> &(</span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">-></span><span class="identifier-syntax">array</span><span class="plain-syntax">[</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">-></span><span class="identifier-syntax">used</span><span class="plain-syntax">++]);</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP21"></a><b>§21. Expanding many macros. </b>Each given structure must have a typedef name, say <code class="display"><span class="extract-syntax">marvel</span></code>, and can be
|
|
used in one of two ways. Either way, we can obtain a new one with the macro
|
|
<code class="display"><span class="extract-syntax">CREATE(marvel)</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Either (a) it will be individually allocated. In this case <code class="display"><span class="extract-syntax">marvel_MT</span></code>
|
|
should be defined with a new MT (memory type) number, and the macro
|
|
<code class="display"><span class="extract-syntax">ALLOCATE_INDIVIDUALLY(marvel)</span></code> should be expanded. The first and last
|
|
objects created will be <code class="display"><span class="extract-syntax">FIRST_OBJECT(marvel)</span></code> and <code class="display"><span class="extract-syntax">LAST_OBJECT(marvel)</span></code>,
|
|
and we can proceed either way through a double linked list of them with
|
|
<code class="display"><span class="extract-syntax">PREV_OBJECT(mv, marvel)</span></code> and <code class="display"><span class="extract-syntax">NEXT_OBJECT(mv, marvel)</span></code>. For convenience,
|
|
we can loop through marvels, in creation order, using <code class="display"><span class="extract-syntax">LOOP_OVER(var,
|
|
</span></code>marvel)<code class="display"><span class="extract-syntax">, which expands to a </span></code>for<code class="display"><span class="extract-syntax"> loop in which the variable </span></code>var<code class="display"><span class="extract-syntax"> runs
|
|
</span></code>through each created marvel in turn; or equally we can run backwards
|
|
through using <code class="display"><span class="extract-syntax">LOOP_BACKWARDS_OVER(var, marvel)</span></code>. In addition, there are
|
|
corruption checks to protect the memory from overrunning accidents, and the
|
|
structure can be used as a value in the symbols table. Good for large
|
|
structures with significant semantic content.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Or (b) it will be allocated in arrays. Once again we can obtain new marvels
|
|
with <code class="display"><span class="extract-syntax">CREATE(marvel)</span></code>. This is more efficient both in speed and memory
|
|
usage, but we lose the ability to loop through the objects. For this
|
|
arrangement, define <code class="display"><span class="extract-syntax">marvel_array_MT</span></code> with a new MT number and expand the
|
|
macro <code class="display"><span class="extract-syntax">ALLOCATE_IN_ARRAYS(marvel, 100)</span></code>, where 100 (or what may you) is the
|
|
number of objects allocated jointly as a block. Good for small structures
|
|
used in the lower levels.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Here goes, then.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">filename</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">pathname</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">scan_directory</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_datum</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_volume</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_chapter</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_page</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_image</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">HTML_file_state</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">command_line_switch</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">dictionary</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">debugging_aspect</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">linked_list</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">method</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">method_set</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_mark</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">semantic_version_number_holder</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">semver_range</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">web_bibliographic_datum</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">web_md</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">chapter_md</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">section_md</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">module</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">module_search</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">heterogeneous_tree</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">tree_type</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">tree_node</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">tree_node_type</span><span class="plain-syntax">)</span>
|
|
|
|
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">dict_entry</span><span class="plain-syntax">, </span><span class="constant-syntax">100</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">HTML_tag</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">linked_list_item</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">match_avinue</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">match_trie</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">text_stream</span><span class="plain-syntax">, </span><span class="constant-syntax">100</span><span class="plain-syntax">)</span>
|
|
</pre><p class="inwebparagraph"><a id="SP22"></a><b>§22. Simple memory allocations. </b>Not all of our memory will be claimed in the form of structures: now and then
|
|
we need to use the equivalent of traditional <code class="display"><span class="extract-syntax">malloc</span></code> and <code class="display"><span class="extract-syntax">calloc</span></code> routines.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">STREAM_MREASON</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">FILENAME_STORAGE_MREASON</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">STRING_STORAGE_MREASON</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">DICTIONARY_MREASON</span>
|
|
<span class="definition-keyword">enum</span> <span class="constant-syntax">CLS_SORTING_MREASON</span>
|
|
</pre>
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::name_fundamental_reasons</span><button class="popup" onclick="togglePopup('usagePopup7')">...<span class="popuptext" id="usagePopup7">Usage of <b>Memory::name_fundamental_reasons</b>:<br><a href="2-mmr.html#SP5">§5</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="internal">Memory::reason_name</a><span class="plain-syntax">(</span><span class="constant-syntax">STREAM_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"text stream storage"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="internal">Memory::reason_name</a><span class="plain-syntax">(</span><span class="constant-syntax">FILENAME_STORAGE_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"filename/pathname storage"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="internal">Memory::reason_name</a><span class="plain-syntax">(</span><span class="constant-syntax">STRING_STORAGE_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"string storage"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="internal">Memory::reason_name</a><span class="plain-syntax">(</span><span class="constant-syntax">DICTIONARY_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"dictionary storage"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="internal">Memory::reason_name</a><span class="plain-syntax">(</span><span class="constant-syntax">CLS_SORTING_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"sorting"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP23"></a><b>§23. </b>And here is the (very simple) implementation.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">memory_needs</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">];</span>
|
|
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::reason_name</span><button class="popup" onclick="togglePopup('usagePopup8')">...<span class="popuptext" id="usagePopup8">Usage of <b>Memory::reason_name</b>:<br><a href="2-mmr.html#SP22">§22</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">r</span><span class="plain-syntax">, </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">reason</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">r</span><span class="plain-syntax"> < </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">r</span><span class="plain-syntax"> >= </span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">)) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"MR out of range"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_needs</span><span class="plain-syntax">[</span><span class="identifier-syntax">r</span><span class="plain-syntax">] = </span><span class="identifier-syntax">reason</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
|
|
<span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::description_of_reason</span><button class="popup" onclick="togglePopup('usagePopup9')">...<span class="popuptext" id="usagePopup9">Usage of <b>Memory::description_of_reason</b>:<br><a href="2-mmr.html#SP26_1">§26.1</a>, <a href="2-mmr.html#SP31">§31</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">r</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">r</span><span class="plain-syntax"> < </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">r</span><span class="plain-syntax"> >= </span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">)) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"MR out of range"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">memory_needs</span><span class="plain-syntax">[</span><span class="identifier-syntax">r</span><span class="plain-syntax">];</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP24"></a><b>§24. </b>We keep some statistics on this. The value for "memory claimed" is the
|
|
net amount of memory currently owned, which is increased when we allocate
|
|
it and decreased when we free it. Whether the host OS is able to make
|
|
efficient use of the memory we free, we can't know, but it probably is, and
|
|
therefore the best estimate of how well we're doing is the "maximum memory
|
|
claimed" — the highest recorded net usage count over the run.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">],</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">],</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">number_of_claims_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">];</span>
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_claimed_simply</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
</pre><p class="inwebparagraph"><a id="SP25"></a><b>§25. </b>Our allocation routines behave just like the standard C library's <code class="display"><span class="extract-syntax">malloc</span></code>
|
|
and <code class="display"><span class="extract-syntax">calloc</span></code>, but where a third argument supplies a reason why the memory is
|
|
needed, and where any failure to allocate memory is tidily dealt with. We will
|
|
exit on any such failure, so that the caller can be certain that the return
|
|
values of these functions are always non-<code class="display"><span class="extract-syntax">NULL</span></code> pointers.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::calloc</span><button class="popup" onclick="togglePopup('usagePopup10')">...<span class="popuptext" id="usagePopup10">Usage of <b>Memory::calloc</b>:<br>Streams - <a href="2-str.html#SP26">§26</a><br>Dictionaries - <a href="2-dct.html#SP2">§2</a><br>Command Line Arguments - <a href="3-cla.html#SP14">§14</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">how_many</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">reason</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><a href="2-mmr.html#SP26" class="internal">Memory::alloc_inner</a><span class="plain-syntax">(</span><span class="identifier-syntax">how_many</span><span class="plain-syntax">, </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">, </span><span class="identifier-syntax">reason</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::malloc</span><button class="popup" onclick="togglePopup('usagePopup11')">...<span class="popuptext" id="usagePopup11">Usage of <b>Memory::malloc</b>:<br><a href="2-mmr.html#SP29">§29</a>, Streams - <a href="2-str.html#SP35_3">§35.3</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">reason</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><a href="2-mmr.html#SP26" class="internal">Memory::alloc_inner</a><span class="plain-syntax">(-1, </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">, </span><span class="identifier-syntax">reason</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP26"></a><b>§26. </b>And this, then, is the joint routine implementing both.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::alloc_inner</span><button class="popup" onclick="togglePopup('usagePopup12')">...<span class="popuptext" id="usagePopup12">Usage of <b>Memory::alloc_inner</b>:<br><a href="2-mmr.html#SP25">§25</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">N</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">S</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">R</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">R</span><span class="plain-syntax"> < </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">R</span><span class="plain-syntax"> >= </span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">)) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"no such memory reason"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">total_claimed_simply</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><<span class="named-paragraph">Zero out the statistics on simple memory allocations</span> <span class="named-paragraph-number">26.2</span>><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Claim the memory using malloc or calloc as appropriate</span> <span class="named-paragraph-number">26.1</span>><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Update the statistics on simple memory allocations</span> <span class="named-paragraph-number">26.3</span>><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">pointer</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP26_1"></a><b>§26.1. </b>I am nervous about assuming that <code class="display"><span class="extract-syntax">calloc(0, X)</span></code> returns a non-<code class="display"><span class="extract-syntax">NULL</span></code> pointer
|
|
in all implementations of the standard C library, so the case when <code class="display"><span class="extract-syntax">N</span></code> is zero
|
|
allocates a tiny but positive amount of memory, just to be safe.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Claim the memory using malloc or calloc as appropriate</span> <span class="named-paragraph-number">26.1</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">N</span><span class="plain-syntax"> > </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">pointer</span><span class="plain-syntax"> = </span><a href="2-mmr.html#SP35" class="internal">Memory::paranoid_calloc</a><span class="plain-syntax">((</span><span class="identifier-syntax">size_t</span><span class="plain-syntax">) </span><span class="identifier-syntax">N</span><span class="plain-syntax">, (</span><span class="identifier-syntax">size_t</span><span class="plain-syntax">) </span><span class="identifier-syntax">S</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax"> = </span><span class="identifier-syntax">N</span><span class="plain-syntax">*</span><span class="identifier-syntax">S</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">pointer</span><span class="plain-syntax"> = </span><a href="2-mmr.html#SP35" class="internal">Memory::paranoid_calloc</a><span class="plain-syntax">(1, (</span><span class="identifier-syntax">size_t</span><span class="plain-syntax">) </span><span class="identifier-syntax">S</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax"> = </span><span class="identifier-syntax">S</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">pointer</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><a href="3-em.html#SP2" class="internal">Errors::fatal_with_C_string</a><span class="plain-syntax">(</span><span class="string-syntax">"Out of memory for %s"</span><span class="plain-syntax">, </span><a href="2-mmr.html#SP23" class="internal">Memory::description_of_reason</a><span class="plain-syntax">(</span><span class="identifier-syntax">R</span><span class="plain-syntax">));</span>
|
|
<span class="plain-syntax"> }</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP26">§26</a>.</li></ul><p class="inwebparagraph"><a id="SP26_2"></a><b>§26.2. </b>These statistics have no function except to improve the diagnostics in the
|
|
debugging log, but they are very cheap to keep, since <code class="display"><span class="extract-syntax">Memory::alloc_inner</span></code> is called only
|
|
rarely and to allocate large blocks of memory.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Zero out the statistics on simple memory allocations</span> <span class="named-paragraph-number">26.2</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax"><</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">number_of_claims_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP26">§26</a>.</li></ul><p class="inwebparagraph"><a id="SP26_3"></a><b>§26.3. </b><code class="display">
|
|
<<span class="named-paragraph-defn">Update the statistics on simple memory allocations</span> <span class="named-paragraph-number">26.3</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">] += </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">total_claimed_simply</span><span class="plain-syntax"> += </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">number_of_claims_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">]++;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">] > </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">])</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">] = </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">];</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP26">§26</a>.</li></ul><p class="inwebparagraph"><a id="SP27"></a><b>§27. </b>We also provide our own wrapper for <code class="display"><span class="extract-syntax">free</span></code>:
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::I7_free</span><button class="popup" onclick="togglePopup('usagePopup13')">...<span class="popuptext" id="usagePopup13">Usage of <b>Memory::I7_free</b>:<br><a href="2-mmr.html#SP30">§30</a>, Streams - <a href="2-str.html#SP34_2">§34.2</a><br>Dictionaries - <a href="2-dct.html#SP7_2">§7.2</a>, <a href="2-dct.html#SP11">§11</a><br>Command Line Arguments - <a href="3-cla.html#SP14">§14</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">R</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes_freed</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">R</span><span class="plain-syntax"> < </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">R</span><span class="plain-syntax"> >= </span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">)) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"no such memory reason"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">pointer</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"can't free NULL memory"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">] -= </span><span class="identifier-syntax">bytes_freed</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax">(</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::I7_array_free</span><button class="popup" onclick="togglePopup('usagePopup14')">...<span class="popuptext" id="usagePopup14">Usage of <b>Memory::I7_array_free</b>:<br>none</span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">R</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">num_cells</span><span class="plain-syntax">, </span><span class="identifier-syntax">size_t</span><span class="plain-syntax"> </span><span class="identifier-syntax">cell_size</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP27" class="internal">Memory::I7_free</a><span class="plain-syntax">(</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">, </span><span class="identifier-syntax">R</span><span class="plain-syntax">, </span><span class="identifier-syntax">num_cells</span><span class="plain-syntax">*((</span><span class="reserved-syntax">int</span><span class="plain-syntax">) </span><span class="identifier-syntax">cell_size</span><span class="plain-syntax">));</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP28"></a><b>§28. Text storage. </b>We will also use much simpler memory areas for text, in 64K chunks:
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="constant-syntax">SSA_CAPACITY</span><span class="plain-syntax"> </span><span class="constant-syntax">64</span><span class="plain-syntax">*1024</span>
|
|
</pre>
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">storage_at</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">first_free_byte</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="constant-syntax">MEMORY_MANAGEMENT</span>
|
|
<span class="plain-syntax">} </span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="reserved-syntax">string_storage_area</span><span class="plain-syntax"> *</span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
</pre><ul class="endnotetexts"><li>The structure string_storage_area is private to this section.</li></ul><p class="inwebparagraph"><a id="SP29"></a><b>§29. </b>The following is ideal for parking a read-only string of text somewhere
|
|
safe in memory. Since the length can't be extended, it's usually unsafe
|
|
to write to the result.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::new_string</span><button class="popup" onclick="togglePopup('usagePopup15')">...<span class="popuptext" id="usagePopup15">Usage of <b>Memory::new_string</b>:<br>none</span></button><span class="plain-syntax">(</span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">from</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">length_needed</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">int</span><span class="plain-syntax">) </span><span class="identifier-syntax">strlen</span><span class="plain-syntax">(</span><span class="identifier-syntax">from</span><span class="plain-syntax">) + </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!((</span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">) &&</span>
|
|
<span class="plain-syntax"> (</span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-></span><span class="element-syntax">first_free_byte</span><span class="plain-syntax"> + </span><span class="identifier-syntax">length_needed</span><span class="plain-syntax"> < </span><span class="constant-syntax">SSA_CAPACITY</span><span class="plain-syntax">))) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax"> = </span><span class="identifier-syntax">CREATE</span><span class="plain-syntax">(</span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-></span><span class="element-syntax">storage_at</span><span class="plain-syntax"> = </span><a href="2-mmr.html#SP25" class="internal">Memory::malloc</a><span class="plain-syntax">(</span><span class="constant-syntax">SSA_CAPACITY</span><span class="plain-syntax">, </span><span class="constant-syntax">STRING_STORAGE_MREASON</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-></span><span class="element-syntax">first_free_byte</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">rp</span><span class="plain-syntax"> = </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-></span><span class="element-syntax">storage_at</span><span class="plain-syntax"> + </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-></span><span class="element-syntax">first_free_byte</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-></span><span class="element-syntax">first_free_byte</span><span class="plain-syntax"> += </span><span class="identifier-syntax">length_needed</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">strcpy</span><span class="plain-syntax">(</span><span class="identifier-syntax">rp</span><span class="plain-syntax">, </span><span class="identifier-syntax">from</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">rp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP30"></a><b>§30. </b>And here we free any SSAs needed in the course of the run.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::free_ssas</span><button class="popup" onclick="togglePopup('usagePopup16')">...<span class="popuptext" id="usagePopup16">Usage of <b>Memory::free_ssas</b>:<br><a href="2-mmr.html#SP12">§12</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax"> *</span><span class="identifier-syntax">ssa</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOOP_OVER</span><span class="plain-syntax">(</span><span class="identifier-syntax">ssa</span><span class="plain-syntax">, </span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP27" class="internal">Memory::I7_free</a><span class="plain-syntax">(</span><span class="identifier-syntax">ssa</span><span class="plain-syntax">-></span><span class="element-syntax">storage_at</span><span class="plain-syntax">, </span><span class="constant-syntax">STRING_STORAGE_MREASON</span><span class="plain-syntax">, </span><span class="constant-syntax">SSA_CAPACITY</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP31"></a><b>§31. </b>And the following provides statistics, and a mini-report, for the memory
|
|
report in the debugging log (for which, see below).
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::log_usage</span><button class="popup" onclick="togglePopup('usagePopup17')">...<span class="popuptext" id="usagePopup17">Usage of <b>Memory::log_usage</b>:<br><a href="2-mmr.html#SP32">§32</a>, <a href="2-mmr.html#SP32_3">§32.3</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">total_claimed_simply</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">, </span><span class="identifier-syntax">t</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax"><</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">t</span><span class="plain-syntax"> += </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">];</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">total</span><span class="plain-syntax"> > </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"0.%03d: %s - %d bytes in %d claim(s)\n"</span><span class="plain-syntax">,</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP34" class="internal">Memory::proportion</a><span class="plain-syntax">(</span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">], </span><span class="identifier-syntax">total</span><span class="plain-syntax">),</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="internal">Memory::description_of_reason</a><span class="plain-syntax">(</span><span class="identifier-syntax">i</span><span class="plain-syntax">),</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">],</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">number_of_claims_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">]);</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">t</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP32"></a><b>§32. Memory usage report. </b>A small utility routine to help keep track of our unquestioned profligacy.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::log_statistics</span><button class="popup" onclick="togglePopup('usagePopup18')">...<span class="popuptext" id="usagePopup18">Usage of <b>Memory::log_statistics</b>:<br>Foundation Module - <a href="1-fm.html#SP9">§9</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax"> = </span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">*</span><span class="identifier-syntax">no_blocks_allocated</span><span class="plain-syntax">; </span><span class="comment"> usage in bytes</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_for_SMAs</span><span class="plain-syntax"> = </span><a href="2-mmr.html#SP31" class="internal">Memory::log_usage</a><span class="plain-syntax">(0); </span><span class="comment"> usage in bytes</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">]; </span><span class="comment"> memory type numbers, in usage order</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total</span><span class="plain-syntax"> = (</span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax"> + </span><span class="identifier-syntax">total_for_SMAs</span><span class="plain-syntax">)/1024; </span><span class="comment"> total memory usage in KB</span>
|
|
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Sort the table of memory type usages into decreasing size order</span> <span class="named-paragraph-number">32.2</span>><span class="plain-syntax">;</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_for_objects_used</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="comment"> out of the </span><code class="display"><span class="extract-syntax">total_for_objects</span></code><span class="comment">, the bytes used</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_objects</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Calculate the memory usage for objects</span> <span class="named-paragraph-number">32.1</span>><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">overhead_for_objects</span><span class="plain-syntax"> = </span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax"> - </span><span class="identifier-syntax">total_for_objects_used</span><span class="plain-syntax">; </span><span class="comment"> bytes wasted</span>
|
|
<span class="plain-syntax"> </span><<span class="named-paragraph">Print the report to the debugging log</span> <span class="named-paragraph-number">32.3</span>><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP32_1"></a><b>§32.1. </b><code class="display">
|
|
<<span class="named-paragraph-defn">Calculate the memory usage for objects</span> <span class="named-paragraph-number">32.1</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">, </span><span class="identifier-syntax">j</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">j</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">j</span><span class="plain-syntax"><</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">j</span><span class="plain-syntax">++) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">[</span><span class="identifier-syntax">j</span><span class="plain-syntax">];</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax"> != </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax"> == </span><span class="constant-syntax">1</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">total_objects</span><span class="plain-syntax"> += </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">total_objects</span><span class="plain-syntax"> += </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">*</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">total_for_objects_used</span><span class="plain-syntax"> += </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> }</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP32">§32</a>.</li></ul><p class="inwebparagraph"><a id="SP32_2"></a><b>§32.2. </b>This is the criterion for sorting memory types in the report: descending
|
|
order of total number of bytes allocated.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Sort the table of memory type usages into decreasing size order</span> <span class="named-paragraph-number">32.2</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax"><</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) </span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="identifier-syntax">i</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">qsort</span><span class="plain-syntax">(</span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">, (</span><span class="identifier-syntax">size_t</span><span class="plain-syntax">) </span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">, </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax">), </span><a href="2-mmr.html#SP33" class="internal">Memory::compare_usage</a><span class="plain-syntax">);</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP32">§32</a>.</li></ul><p class="inwebparagraph"><a id="SP32_3"></a><b>§32.3. </b>And here is the actual report:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="named-paragraph-defn">Print the report to the debugging log</span> <span class="named-paragraph-number">32.3</span>> =
|
|
</code></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"\nReport by memory manager:\n\n"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Total consumption was %dK = %dMB, divided up in the following proportions:\n"</span><span class="plain-syntax">,</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">total</span><span class="plain-syntax">, (</span><span class="identifier-syntax">total</span><span class="plain-syntax">+512)/1024);</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"0.%03d: %d objects in %d frames in %d memory blocks (of %dK each):\n"</span><span class="plain-syntax">,</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP34" class="internal">Memory::proportion</a><span class="plain-syntax">(</span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax">, </span><span class="identifier-syntax">total</span><span class="plain-syntax">),</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">total_objects</span><span class="plain-syntax">, </span><span class="identifier-syntax">total_objects_allocated</span><span class="plain-syntax">, </span><span class="identifier-syntax">no_blocks_allocated</span><span class="plain-syntax">, </span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">/1024);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" 0.%03d: memory manager overhead - %d bytes\n"</span><span class="plain-syntax">,</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP34" class="internal">Memory::proportion</a><span class="plain-syntax">(</span><span class="identifier-syntax">overhead_for_objects</span><span class="plain-syntax">, </span><span class="identifier-syntax">total</span><span class="plain-syntax">), </span><span class="identifier-syntax">overhead_for_objects</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">, </span><span class="identifier-syntax">j</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">j</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">j</span><span class="plain-syntax"><</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">j</span><span class="plain-syntax">++) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">[</span><span class="identifier-syntax">j</span><span class="plain-syntax">];</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax"> != </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" 0.%03d: %s - "</span><span class="plain-syntax">,</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP34" class="internal">Memory::proportion</a><span class="plain-syntax">(</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax">, </span><span class="identifier-syntax">total</span><span class="plain-syntax">),</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">name_of_type</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax"> == </span><span class="constant-syntax">1</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"%d "</span><span class="plain-syntax">, </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</span><span class="plain-syntax"> != </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"(+%d deleted) "</span><span class="plain-syntax">,</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax"> - </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"%d blocks of %d = %d "</span><span class="plain-syntax">,</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">, </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax">,</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">*</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"objects, %d bytes\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP31" class="internal">Memory::log_usage</a><span class="plain-syntax">(</span><span class="identifier-syntax">total</span><span class="plain-syntax">);</span>
|
|
</pre><ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP32">§32</a>.</li></ul><p class="inwebparagraph"><a id="SP33"></a><b>§33. </b></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::compare_usage</span><button class="popup" onclick="togglePopup('usagePopup19')">...<span class="popuptext" id="usagePopup19">Usage of <b>Memory::compare_usage</b>:<br><a href="2-mmr.html#SP32_2">§32.2</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">const</span><span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">ent1</span><span class="plain-syntax">, </span><span class="reserved-syntax">const</span><span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">ent2</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">ix1</span><span class="plain-syntax"> = *((</span><span class="reserved-syntax">const</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">ent1</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">ix2</span><span class="plain-syntax"> = *((</span><span class="reserved-syntax">const</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">ent2</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">ix2</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax"> - </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">ix1</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP34"></a><b>§34. </b>Finally, a little routine to compute the proportions of memory for each
|
|
usage. Recall that <code class="display"><span class="extract-syntax">bytes</span></code> is measured in bytes, but <code class="display"><span class="extract-syntax">total</span></code> in kilobytes.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::proportion</span><button class="popup" onclick="togglePopup('usagePopup20')">...<span class="popuptext" id="usagePopup20">Usage of <b>Memory::proportion</b>:<br><a href="2-mmr.html#SP31">§31</a>, <a href="2-mmr.html#SP32_3">§32.3</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">float</span><span class="plain-syntax"> </span><span class="identifier-syntax">B</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">float</span><span class="plain-syntax">) </span><span class="identifier-syntax">bytes</span><span class="plain-syntax">, </span><span class="identifier-syntax">T</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">float</span><span class="plain-syntax">) </span><span class="identifier-syntax">total</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">float</span><span class="plain-syntax"> </span><span class="identifier-syntax">P</span><span class="plain-syntax"> = (1000*</span><span class="identifier-syntax">B</span><span class="plain-syntax">)/(1024*</span><span class="identifier-syntax">T</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax">) </span><span class="identifier-syntax">P</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP35"></a><b>§35. </b></p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::paranoid_calloc</span><button class="popup" onclick="togglePopup('usagePopup21')">...<span class="popuptext" id="usagePopup21">Usage of <b>Memory::paranoid_calloc</b>:<br><a href="2-mmr.html#SP11_1">§11.1</a>, <a href="2-mmr.html#SP26_1">§26.1</a></span></button><span class="plain-syntax">(</span><span class="identifier-syntax">size_t</span><span class="plain-syntax"> </span><span class="identifier-syntax">N</span><span class="plain-syntax">, </span><span class="identifier-syntax">size_t</span><span class="plain-syntax"> </span><span class="identifier-syntax">S</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">P</span><span class="plain-syntax"> = </span><span class="identifier-syntax">calloc</span><span class="plain-syntax">(</span><span class="identifier-syntax">N</span><span class="plain-syntax">, </span><span class="identifier-syntax">S</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">P</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><p class="inwebparagraph"><a id="SP36"></a><b>§36. Run-time pointer type checking. </b>In several places Inform needs to store pointers of type <code class="display"><span class="extract-syntax">void *</span></code>, that is,
|
|
pointers which have no indication of what type of data they point to.
|
|
This is not type-safe and therefore offers plenty of opportunity for
|
|
blunders. The following provides run-time type checking to ensure that
|
|
each time we dereference a typeless pointer, it does indeed point to
|
|
a structure of the type we think it should.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">The structure <code class="display"><span class="extract-syntax">general_pointer</span></code> holds a <code class="display"><span class="extract-syntax">void *</span></code> pointer to any one of the
|
|
following:
|
|
</p>
|
|
|
|
</li><li>(a) <code class="display"><span class="extract-syntax">NULL</span></code>, to which we assign ID number \(-1\);
|
|
</li><li>(b) <code class="display"><span class="extract-syntax">char</span></code>, to which we assign ID number 1000;
|
|
</li><li>(c) any individually allocated structure of the types listed above, to
|
|
which we assign the ID numbers used above: for instance, <code class="display"><span class="extract-syntax">blorb_figure_MT</span></code>
|
|
is the ID number for a <code class="display"><span class="extract-syntax">general_pointer</span></code> which points to a <code class="display"><span class="extract-syntax">blorb_figure</span></code>
|
|
structure.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="constant-syntax">NULL_GENERAL_POINTER</span><span class="plain-syntax"> (</span><a href="2-mmr.html#SP36" class="internal">Memory::store_gp_null</a><span class="plain-syntax">())</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">GENERAL_POINTER_IS_NULL</span><span class="plain-syntax">(</span><span class="identifier-syntax">gp</span><span class="plain-syntax">) (</span><a href="2-mmr.html#SP36" class="internal">Memory::test_gp_null</a><span class="plain-syntax">(</span><span class="identifier-syntax">gp</span><span class="plain-syntax">))</span>
|
|
</pre>
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">pointer_to_data</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">} </span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax">;</span>
|
|
|
|
<span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::store_gp_null</span><button class="popup" onclick="togglePopup('usagePopup22')">...<span class="popuptext" id="usagePopup22">Usage of <b>Memory::store_gp_null</b>:<br>none</span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">run_time_type_code</span><span class="plain-syntax"> = -1; </span><span class="comment"> guaranteed to differ from all </span><code class="display"><span class="extract-syntax">_MT</span></code><span class="comment"> values</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::test_gp_null</span><button class="popup" onclick="togglePopup('usagePopup23')">...<span class="popuptext" id="usagePopup23">Usage of <b>Memory::test_gp_null</b>:<br>none</span></button><span class="plain-syntax">(</span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax"> == -1) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">TRUE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre><ul class="endnotetexts"><li>The structure general_pointer is accessed in 2/trs and here.</li></ul><p class="inwebparagraph"><a id="SP37"></a><b>§37. </b>The symbols tables need to look at pointer values directly without knowing
|
|
their types, but only to test equality, so we abstract that thus. And the
|
|
debugging log also shows actual hexadecimal addresses to distinguish nameless
|
|
objects and to help with interpreting output from GDB, so we abstract that too.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">COMPARE_GENERAL_POINTERS</span><span class="plain-syntax">(</span><span class="identifier-syntax">gp1</span><span class="plain-syntax">, </span><span class="identifier-syntax">gp2</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> (</span><span class="identifier-syntax">gp1</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax"> == </span><span class="identifier-syntax">gp2</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax">)</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">GENERAL_POINTER_AS_INT</span><span class="plain-syntax">(</span><span class="identifier-syntax">gp</span><span class="plain-syntax">)</span>
|
|
<span class="plain-syntax"> ((</span><span class="identifier-syntax">pointer_sized_int</span><span class="plain-syntax">) </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP38"></a><b>§38. </b>If we have a pointer to <code class="display"><span class="extract-syntax">circus</span></code> (say) then <code class="display"><span class="extract-syntax">g=STORE_POINTER_circus(p)</span></code>
|
|
returns a <code class="display"><span class="extract-syntax">general_pointer</span></code> with <code class="display"><span class="extract-syntax">p</span></code> as the actual pointer, but will not
|
|
compile unless <code class="display"><span class="extract-syntax">p</span></code> is indeed of type <code class="display"><span class="extract-syntax">circus *</span></code>. When we later
|
|
<code class="display"><span class="extract-syntax">RETRIEVE_POINTER_circus(g)</span></code>, an internal error is thrown if <code class="display"><span class="extract-syntax">g</span></code> contains a pointer
|
|
which is other than <code class="display"><span class="extract-syntax">void *</span></code>, or which has never been referenced.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">MAKE_REFERENCE_ROUTINES</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">)</span>
|
|
<span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">STORE_POINTER_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">data</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">data</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">run_time_type_code</span><span class="plain-syntax"> = </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
<span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">RETRIEVE_POINTER_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax"> != </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Wanted ID code %d, found %d\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">, </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">run_time_type_code</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"attempt to retrieve wrong pointer type as "</span><span class="plain-syntax"> #</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
<span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">PASS_POINTER_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax"> != </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Wanted ID code %d, found %d\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">, </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">run_time_type_code</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"attempt to pass wrong pointer type as "</span><span class="plain-syntax"> #</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> }</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">VALID_POINTER_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">) {</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax"> == </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">TRUE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP39"></a><b>§39. </b>Suitable <code class="display"><span class="extract-syntax">MAKE_REFERENCE_ROUTINES</span></code> were expanded for all of the memory
|
|
allocated objects above; so that leaves only humble <code class="display"><span class="extract-syntax">char *</span></code> pointers:
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code">
|
|
<span class="identifier-syntax">MAKE_REFERENCE_ROUTINES</span><span class="plain-syntax">(</span><span class="reserved-syntax">char</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
|
|
</pre><hr class="tocbar">
|
|
<ul class="toc"><li><a href="2-dl.html">Back to 'Debugging Log'</a></li><li><a href="2-str.html">Continue with 'Streams'</a></li></ul><hr class="tocbar">
|
|
<!--End of weave-->
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|