976 lines
181 KiB
HTML
976 lines
181 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/Contents.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<link href="../docs-assets/Progress.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<link href="../docs-assets/Navigation.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<link href="../docs-assets/Fonts.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
<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 class="commentary-font">
|
|
<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-->
|
|
<div class="breadcrumbs">
|
|
<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></div>
|
|
<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. Simple memory allocations</a></li><li><a href="2-mmr.html#SP27">§27. Memory usage report</a></li><li><a href="2-mmr.html#SP32">§32. Run-time pointer type checking</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="commentary firstcommentary"><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 "class" has its own doubly-linked list, and in each class 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="commentary firstcommentary"><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 <span class="extract"><span class="extract-syntax">struct</span></span>; thus,
|
|
a plain <span class="extract"><span class="extract-syntax">int</span></span> is not an object. The memory manager can only deal with
|
|
a given type of <span class="extract"><span class="extract-syntax">struct</span></span> if it contains three special elements, and we
|
|
define those using a macro. Thus, if the user wants to allocate larger
|
|
structures of type <span class="extract"><span class="extract-syntax">thingummy</span></span>, then it needs to be defined like so:
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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">CLASS_DEFINITION</span>
|
|
<span class="plain-syntax"> } </span><span class="identifier-syntax">thingummy</span><span class="plain-syntax">;</span>
|
|
</pre>
|
|
<p class="commentary">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 code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">CLASS_DEFINITION</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-syntax"> 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-syntax"> 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-syntax"> Previous object in double-linked list</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP3"></a><b>§3. </b>It is also necessary to define a constant in the following enumeration
|
|
family: for <span class="extract"><span class="extract-syntax">thingummy</span></span>, it would be <span class="extract"><span class="extract-syntax">thingummy_CLASS</span></span>. Had it been a smaller
|
|
object, it would have been <span class="extract"><span class="extract-syntax">thingummy_array_CLASS</span></span> instead.
|
|
</p>
|
|
|
|
<p class="commentary">There is no significance to the order in which classes are registered
|
|
with the memory system; the following sentinel value is not the class ID
|
|
of any actual class, and simply forces the others to have IDs which are
|
|
positive, since they count upwards from this.
|
|
</p>
|
|
|
|
<pre class="definitions code-font"><span class="definition-keyword">enum</span> <span class="constant-syntax">unused_class_value_CLASS</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><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 <span class="extract"><span class="extract-syntax">no_allocated_together</span></span> 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), <span class="extract"><span class="extract-syntax">no_allocated_together</span></span> 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 code-font">
|
|
<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-syntax"> 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-syntax"> 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-syntax"> 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-syntax"> tail of doubly linked list</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="comment-syntax"> 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-syntax"> e.g., </span><span class="extract"><span class="extract-syntax">"index_lexicon_entry_CLASS"</span></span>
|
|
<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-syntax"> 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-syntax"> 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-syntax"> 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="commentary firstcommentary"><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 code-font">
|
|
<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_CLASS_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="comment-syntax">?</span><span class="popuptext" id="usagePopup1">Usage of <span class="code-font"><span class="function-syntax">Memory::start</span></span>:<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_CLASS_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#SP21" class="function-link"><span class="function-syntax">Memory::name_fundamental_reasons</span></a><span class="plain-syntax">();</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><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>
|
|
|
|
<ul class="items"><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.
|
|
</li></ul>
|
|
<p class="commentary firstcommentary"><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 code-font"><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="commentary firstcommentary"><a id="SP8"></a><b>§8. </b>At present <span class="extract"><span class="extract-syntax">MEMORY_GRANULARITY</span></span> is 800K. This is the quantity of memory
|
|
allocated by each individual <span class="extract"><span class="extract-syntax">malloc</span></span> call.
|
|
</p>
|
|
|
|
<p class="commentary">After <span class="extract"><span class="extract-syntax">MAX_BLOCKS_ALLOWED</span></span> 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 <span class="extract"><span class="extract-syntax">malloc</span></span>, until the user was
|
|
unable to get the GUI responsive enough to kill the process.)
|
|
</p>
|
|
|
|
<pre class="definitions code-font"><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-syntax"> which must be divisible by 1024</span>
|
|
</pre>
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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-syntax"> a potentially larger number, used only for the debugging log</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><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 <span class="extract"><span class="extract-syntax">SAFETY_MARGIN</span></span>
|
|
null bytes, followed by actual data.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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="commentary firstcommentary"><a id="SP10"></a><b>§10. </b></p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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-syntax"> 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-syntax"> 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-syntax"> number of bytes so far used in the tail memory block</span>
|
|
|
|
<span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_single_allocation_mutex</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_array_allocation_mutex</span><span class="plain-syntax">)</span>
|
|
<span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_statistics_mutex</span><span class="plain-syntax">)</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><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 code-font">
|
|
<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="comment-syntax">?</span><span class="popuptext" id="usagePopup2">Usage of <span class="code-font"><span class="function-syntax">Memory::allocate_another_block</span></span>:<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-container code-font"><a href="2-mmr.html#SP11_1" class="named-paragraph-link"><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></a></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-container code-font"><a href="2-mmr.html#SP11_2" class="named-paragraph-link"><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></a></span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP11_1"></a><b>§11.1. </b>Note that <span class="extract"><span class="extract-syntax">cp</span></span> and <span class="extract"><span class="extract-syntax">mh</span></span> are set to the same value: they merely have different
|
|
pointer types as far as the C compiler is concerned.
|
|
</p>
|
|
|
|
<p class="commentary"><span class="named-paragraph-container code-font"><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></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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="function-link"><span class="function-syntax">Errors::fatal</span></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="function-link"><span class="function-syntax">Memory::check_memory_integrity</span></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#SP31" class="function-link"><span class="function-syntax">Memory::paranoid_calloc</span></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="function-link"><span class="function-syntax">Errors::fatal</span></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="commentary firstcommentary"><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="commentary"><span class="named-paragraph-container code-font"><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></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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="commentary firstcommentary"><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 code-font">
|
|
<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="comment-syntax">?</span><span class="popuptext" id="usagePopup3">Usage of <span class="code-font"><span class="function-syntax">Memory::free</span></span>:<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="4-cst.html#SP12" class="function-link"><span class="function-syntax">CStrings::free_ssas</span></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="commentary firstcommentary"><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 code-font"><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-syntax"> a value unlikely to be in memory just by chance</span>
|
|
</pre>
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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-syntax"> this should always contain the </span><span class="extract"><span class="extract-syntax">INTEGRITY_NUMBER</span></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="identifier-syntax">next_frame</span><span class="plain-syntax">; </span><span class="comment-syntax"> 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-syntax"> 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-syntax"> 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="commentary firstcommentary"><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 code-font">
|
|
<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-syntax"> 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-syntax"> most recent memory frame allocated</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><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.
|
|
<span class="extract"><span class="extract-syntax">Memory::check_memory_integrity</span></span> 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 code-font">
|
|
<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="comment-syntax">?</span><span class="popuptext" id="usagePopup4">Usage of <span class="code-font"><span class="function-syntax">Memory::check_memory_integrity</span></span>:<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="function-link"><span class="function-syntax">Errors::fatal</span></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><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="commentary firstcommentary"><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 code-font">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::allocate</span><button class="popup" onclick="togglePopup('usagePopup5')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup5">Usage of <span class="code-font"><span class="function-syntax">Memory::allocate</span></span>:<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="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-syntax"> 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-syntax"> each allocation is followed by </span><span class="extract"><span class="extract-syntax">SAFETY_MARGIN</span></span><span class="comment-syntax"> null bytes</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP16_1" class="named-paragraph-link"><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></a></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-syntax"> 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-syntax"> 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-container code-font"><a href="2-mmr.html#SP16_2" class="named-paragraph-link"><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></a></span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP16_3" class="named-paragraph-link"><span class="named-paragraph">Update the allocation status for this type of object</span><span class="named-paragraph-number">16.3</span></a></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="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="commentary firstcommentary"><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="commentary"><span class="named-paragraph-container code-font"><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></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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="function-link"><span class="function-syntax">Memory::allocate_another_block</span></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="function-link"><span class="function-syntax">Memory::allocate_another_block</span></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="function-link"><span class="function-syntax">Errors::fatal</span></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="commentary firstcommentary"><a id="SP16_2"></a><b>§16.2. </b>New memory frames are added to the tail of the list:
|
|
</p>
|
|
|
|
<p class="commentary"><span class="named-paragraph-container code-font"><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></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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="commentary firstcommentary"><a id="SP16_3"></a><b>§16.3. </b>See the definition of <span class="extract"><span class="extract-syntax">alloc_status</span></span> above.
|
|
</p>
|
|
|
|
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Update the allocation status for this type of object</span><span class="named-paragraph-number">16.3</span></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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="commentary firstcommentary"><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="commentary">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 <span class="extract"><span class="extract-syntax">##</span></span> concatenation
|
|
operator: basically <span class="extract"><span class="extract-syntax">CREATE(thing)</span></span> expands into <span class="extract"><span class="extract-syntax">(allocate_thing())</span></span>
|
|
because of the <span class="extract"><span class="extract-syntax">##</span></span>. (See Kernighan and Ritchie, section 4.11.2.)
|
|
</p>
|
|
|
|
<pre class="definitions code-font"><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">_CLASS</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">_CLASS</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">_CLASS</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</span><span class="plain-syntax">)</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><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 code-font"><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="commentary firstcommentary"><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 <span class="extract"><span class="extract-syntax">DECLARE_CLASS(parse_node)</span></span>,
|
|
which will expand to three functions: <span class="extract"><span class="extract-syntax">allocate_parse_node</span></span>,
|
|
<span class="extract"><span class="extract-syntax">deallocate_parse_node</span></span> and <span class="extract"><span class="extract-syntax">allocate_parse_node_before</span></span>.
|
|
</p>
|
|
|
|
<p class="commentary">Quaintly, <span class="extract"><span class="extract-syntax">#type_name</span></span> expands into the value of <span class="extract"><span class="extract-syntax">type_name</span></span> put within
|
|
double-quotes.
|
|
</p>
|
|
|
|
<pre class="definitions code-font"><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="function-link"><span class="function-syntax">Memory::allocate</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_CLASS</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">DECLARE_CLASS</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) </span><span class="identifier-syntax">DECLARE_CLASS_WITH_ID</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">_CLASS</span><span class="plain-syntax">)</span>
|
|
<span class="definition-keyword">define</span> <span class="identifier-syntax">DECLARE_CLASS_WITH_ID</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">id_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">id_name</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">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_single_allocation_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">id_name</span><span class="plain-syntax">].</span><span class="element-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><a href="2-mmr.html#SP16" class="function-link"><span class="function-syntax">Memory::allocate</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_CLASS</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="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">id_name</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">id_name</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="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_single_allocation_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">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_single_allocation_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">id_name</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">id_name</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">id_name</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="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_single_allocation_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">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_single_allocation_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">id_name</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">id_name</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="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_single_allocation_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">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_single_allocation_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">memory_single_allocation_mutex</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP20"></a><b>§20. </b><span class="extract"><span class="extract-syntax">DECLARE_CLASS_ALLOCATED_IN_ARRAYS</span></span> is still more obfuscated. When we
|
|
<span class="extract"><span class="extract-syntax">DECLARE_CLASS_ALLOCATED_IN_ARRAYS(X, 100)</span></span>, the result will be definitions of
|
|
a new type <span class="extract"><span class="extract-syntax">X_array</span></span> and constructors for both <span class="extract"><span class="extract-syntax">X</span></span> and <span class="extract"><span class="extract-syntax">X_array</span></span>, the former
|
|
of which uses the latter. 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 code-font"><span class="definition-keyword">define</span> <span class="identifier-syntax">DECLARE_CLASS_ALLOCATED_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">_CLASS</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">CLASS_DEFINITION</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="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array_CLASS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_CLASS</span><span class="plain-syntax">; </span><span class="comment-syntax"> C does permit </span><span class="extract"><span class="extract-syntax">#define</span></span><span class="comment-syntax"> to make </span><span class="extract"><span class="extract-syntax">#define</span></span><span class="comment-syntax">s</span>
|
|
<span class="identifier-syntax">DECLARE_CLASS_WITH_ID</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">_CLASS</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">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_array_allocation_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_CLASS</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">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">rv</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="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><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_array_allocation_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">rv</span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP21"></a><b>§21. 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 <span class="extract"><span class="extract-syntax">malloc</span></span> and <span class="extract"><span class="extract-syntax">calloc</span></span> routines.
|
|
</p>
|
|
|
|
<pre class="definitions code-font"><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">ARRAY_SORTING_MREASON</span>
|
|
</pre>
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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('usagePopup6')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup6">Usage of <span class="code-font"><span class="function-syntax">Memory::name_fundamental_reasons</span></span>:<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#SP22" class="function-link"><span class="function-syntax">Memory::reason_name</span></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#SP22" class="function-link"><span class="function-syntax">Memory::reason_name</span></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#SP22" class="function-link"><span class="function-syntax">Memory::reason_name</span></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#SP22" class="function-link"><span class="function-syntax">Memory::reason_name</span></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#SP22" class="function-link"><span class="function-syntax">Memory::reason_name</span></a><span class="plain-syntax">(</span><span class="constant-syntax">ARRAY_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="commentary firstcommentary"><a id="SP22"></a><b>§22. </b>And here is the (very simple) implementation.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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('usagePopup7')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup7">Usage of <span class="code-font"><span class="function-syntax">Memory::reason_name</span></span>:<br/><a href="2-mmr.html#SP21">§21</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('usagePopup8')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup8">Usage of <span class="code-font"><span class="function-syntax">Memory::description_of_reason</span></span>:<br/><a href="2-mmr.html#SP25_1">§25.1</a>, <a href="2-mmr.html#SP28">§28</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="commentary firstcommentary"><a id="SP23"></a><b>§23. </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 code-font">
|
|
<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="commentary firstcommentary"><a id="SP24"></a><b>§24. </b>Our allocation routines behave just like the standard C library's <span class="extract"><span class="extract-syntax">malloc</span></span>
|
|
and <span class="extract"><span class="extract-syntax">calloc</span></span>, 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-<span class="extract"><span class="extract-syntax">NULL</span></span> pointers.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::calloc</span><button class="popup" onclick="togglePopup('usagePopup9')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup9">Usage of <span class="code-font"><span class="function-syntax">Memory::calloc</span></span>:<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><br/>Time - <a href="3-tm.html#SP7_1">§7.1</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#SP25" class="function-link"><span class="function-syntax">Memory::alloc_inner</span></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('usagePopup10')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup10">Usage of <span class="code-font"><span class="function-syntax">Memory::malloc</span></span>:<br/>Streams - <a href="2-str.html#SP35_3">§35.3</a><br/>C Strings - <a href="4-cst.html#SP11">§11</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#SP25" class="function-link"><span class="function-syntax">Memory::alloc_inner</span></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="commentary firstcommentary"><a id="SP25"></a><b>§25. </b>And this, then, is the joint routine implementing both.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::alloc_inner</span><button class="popup" onclick="togglePopup('usagePopup11')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup11">Usage of <span class="code-font"><span class="function-syntax">Memory::alloc_inner</span></span>:<br/><a href="2-mmr.html#SP24">§24</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="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-container code-font"><a href="2-mmr.html#SP25_2" class="named-paragraph-link"><span class="named-paragraph">Zero out the statistics on simple memory allocations</span><span class="named-paragraph-number">25.2</span></a></span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP25_1" class="named-paragraph-link"><span class="named-paragraph">Claim the memory using malloc or calloc as appropriate</span><span class="named-paragraph-number">25.1</span></a></span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP25_3" class="named-paragraph-link"><span class="named-paragraph">Update the statistics on simple memory allocations</span><span class="named-paragraph-number">25.3</span></a></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="commentary firstcommentary"><a id="SP25_1"></a><b>§25.1. </b>I am nervous about assuming that <span class="extract"><span class="extract-syntax">calloc(0, X)</span></span> returns a non-<span class="extract"><span class="extract-syntax">NULL</span></span> pointer
|
|
in all implementations of the standard C library, so the case when <span class="extract"><span class="extract-syntax">N</span></span> is zero
|
|
allocates a tiny but positive amount of memory, just to be safe.
|
|
</p>
|
|
|
|
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Claim the memory using malloc or calloc as appropriate</span><span class="named-paragraph-number">25.1</span></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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#SP31" class="function-link"><span class="function-syntax">Memory::paranoid_calloc</span></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#SP31" class="function-link"><span class="function-syntax">Memory::paranoid_calloc</span></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="function-link"><span class="function-syntax">Errors::fatal_with_C_string</span></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#SP22" class="function-link"><span class="function-syntax">Memory::description_of_reason</span></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#SP25">§25</a>.</li></ul>
|
|
<p class="commentary firstcommentary"><a id="SP25_2"></a><b>§25.2. </b>These statistics have no function except to improve the diagnostics in the
|
|
debugging log, but they are very cheap to keep, since <span class="extract"><span class="extract-syntax">Memory::alloc_inner</span></span> is called only
|
|
rarely and to allocate large blocks of memory.
|
|
</p>
|
|
|
|
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Zero out the statistics on simple memory allocations</span><span class="named-paragraph-number">25.2</span></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_statistics_mutex</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_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>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_statistics_mutex</span><span class="plain-syntax">);</span>
|
|
</pre>
|
|
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP25">§25</a>.</li></ul>
|
|
<p class="commentary firstcommentary"><a id="SP25_3"></a><b>§25.3. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Update the statistics on simple memory allocations</span><span class="named-paragraph-number">25.3</span></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_statistics_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_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>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_statistics_mutex</span><span class="plain-syntax">);</span>
|
|
</pre>
|
|
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP25">§25</a>.</li></ul>
|
|
<p class="commentary firstcommentary"><a id="SP26"></a><b>§26. </b>We also provide our own wrapper for <span class="extract"><span class="extract-syntax">free</span></span>:
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::I7_free</span><button class="popup" onclick="togglePopup('usagePopup12')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup12">Usage of <span class="code-font"><span class="function-syntax">Memory::I7_free</span></span>:<br/>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><br/>C Strings - <a href="4-cst.html#SP12">§12</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">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_statistics_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">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">memory_statistics_mutex</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="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::I7_array_free</span><button class="popup" onclick="togglePopup('usagePopup13')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup13">Usage of <span class="code-font"><span class="function-syntax">Memory::I7_array_free</span></span>:<br/>Time - <a href="3-tm.html#SP7_1">§7.1</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">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#SP26" class="function-link"><span class="function-syntax">Memory::I7_free</span></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="commentary firstcommentary"><a id="SP27"></a><b>§27. Memory usage report. </b>A small utility routine to help keep track of our unquestioned profligacy.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::log_statistics</span><button class="popup" onclick="togglePopup('usagePopup14')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup14">Usage of <span class="code-font"><span class="function-syntax">Memory::log_statistics</span></span>:<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-syntax"> 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#SP28" class="function-link"><span class="function-syntax">Memory::log_usage</span></a><span class="plain-syntax">(0); </span><span class="comment-syntax"> 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_CLASS_VALUES</span><span class="plain-syntax">]; </span><span class="comment-syntax"> 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-syntax"> total memory usage in KB</span>
|
|
|
|
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP27_2" class="named-paragraph-link"><span class="named-paragraph">Sort the table of memory type usages into decreasing size order</span><span class="named-paragraph-number">27.2</span></a></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-syntax"> out of the </span><span class="extract"><span class="extract-syntax">total_for_objects</span></span><span class="comment-syntax">, 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-container code-font"><a href="2-mmr.html#SP27_1" class="named-paragraph-link"><span class="named-paragraph">Calculate the memory usage for objects</span><span class="named-paragraph-number">27.1</span></a></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-syntax"> bytes wasted</span>
|
|
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP27_3" class="named-paragraph-link"><span class="named-paragraph">Print the report to the debugging log</span><span class="named-paragraph-number">27.3</span></a></span><span class="plain-syntax">;</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP27_1"></a><b>§27.1. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Calculate the memory usage for objects</span><span class="named-paragraph-number">27.1</span></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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_CLASS_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#SP27">§27</a>.</li></ul>
|
|
<p class="commentary firstcommentary"><a id="SP27_2"></a><b>§27.2. </b>This is the criterion for sorting memory types in the report: descending
|
|
order of total number of bytes allocated.
|
|
</p>
|
|
|
|
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Sort the table of memory type usages into decreasing size order</span><span class="named-paragraph-number">27.2</span></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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_CLASS_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_CLASS_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#SP29" class="function-link"><span class="function-syntax">Memory::compare_usage</span></a><span class="plain-syntax">);</span>
|
|
</pre>
|
|
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP27">§27</a>.</li></ul>
|
|
<p class="commentary firstcommentary"><a id="SP27_3"></a><b>§27.3. </b>And here is the actual report:
|
|
</p>
|
|
|
|
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Print the report to the debugging log</span><span class="named-paragraph-number">27.3</span></span><span class="comment-syntax"> =</span>
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Total memory consumption was %dK = %d MB\n\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><a href="2-mmr.html#SP30" class="function-link"><span class="function-syntax">Memory::log_percentage</span></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">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" was used for %d objects, in %d frames in %d x %dK = %dK = %d MB:\n\n"</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="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">total_for_objects</span><span class="plain-syntax">/1024, (</span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax">+512)/1024/1024);</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">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_CLASS_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="reserved-syntax">int</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">" "</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP30" class="function-link"><span class="function-syntax">Memory::log_percentage</span></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">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" %s"</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">for</span><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">strlen</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="identifier-syntax">n</span><span class="plain-syntax"><41; </span><span class="identifier-syntax">n</span><span class="plain-syntax">++) </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-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">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="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"object"</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">1</span><span class="plain-syntax">) </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-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="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">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 x %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="reserved-syntax">else</span>
|
|
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"1 x %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">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"</span><span class="plain-syntax">);</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 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><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"\n"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP30" class="function-link"><span class="function-syntax">Memory::log_percentage</span></a><span class="plain-syntax">(1024*</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</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">" was used for memory not allocated for objects:\n\n"</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP28" class="function-link"><span class="function-syntax">Memory::log_usage</span></a><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">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"\n"</span><span class="plain-syntax">); </span><a href="2-mmr.html#SP30" class="function-link"><span class="function-syntax">Memory::log_percentage</span></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="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" was overhead - %d bytes = %dK = %d MB\n\n"</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="identifier-syntax">overhead_for_objects</span><span class="plain-syntax">/1024, (</span><span class="identifier-syntax">overhead_for_objects</span><span class="plain-syntax">+512)/1024/1024);</span>
|
|
</pre>
|
|
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP27">§27</a>.</li></ul>
|
|
<p class="commentary firstcommentary"><a id="SP28"></a><b>§28. </b></p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::log_usage</span><button class="popup" onclick="togglePopup('usagePopup15')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup15">Usage of <span class="code-font"><span class="function-syntax">Memory::log_usage</span></span>:<br/><a href="2-mmr.html#SP27">§27</a>, <a href="2-mmr.html#SP27_3">§27.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="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">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" "</span><span class="plain-syntax">);</span>
|
|
<span class="plain-syntax"> </span><a href="2-mmr.html#SP30" class="function-link"><span class="function-syntax">Memory::log_percentage</span></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><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" %s"</span><span class="plain-syntax">, </span><a href="2-mmr.html#SP22" class="function-link"><span class="function-syntax">Memory::description_of_reason</span></a><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="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">strlen</span><span class="plain-syntax">(</span><a href="2-mmr.html#SP22" class="function-link"><span class="function-syntax">Memory::description_of_reason</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">i</span><span class="plain-syntax">)); </span><span class="identifier-syntax">n</span><span class="plain-syntax"><41; </span><span class="identifier-syntax">n</span><span class="plain-syntax">++) </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" "</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 bytes in %d claim%s\n"</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="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">1</span><span class="plain-syntax">)?</span><span class="string-syntax">""</span><span class="plain-syntax">:</span><span class="string-syntax">"s"</span><span class="plain-syntax">);</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="commentary firstcommentary"><a id="SP29"></a><b>§29. </b></p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::compare_usage</span><button class="popup" onclick="togglePopup('usagePopup16')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup16">Usage of <span class="code-font"><span class="function-syntax">Memory::compare_usage</span></span>:<br/><a href="2-mmr.html#SP27_2">§27.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="commentary firstcommentary"><a id="SP30"></a><b>§30. </b>Finally, a little routine to compute the proportions of memory for each
|
|
usage. Recall that <span class="extract"><span class="extract-syntax">bytes</span></span> is measured in bytes, but <span class="extract"><span class="extract-syntax">total</span></span> in kilobytes.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::log_percentage</span><button class="popup" onclick="togglePopup('usagePopup17')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup17">Usage of <span class="code-font"><span class="function-syntax">Memory::log_percentage</span></span>:<br/><a href="2-mmr.html#SP27_3">§27.3</a>, <a href="2-mmr.html#SP28">§28</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">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">P</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">N</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" ----"</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">"%2d.%01d%%"</span><span class="plain-syntax">, </span><span class="identifier-syntax">N</span><span class="plain-syntax">/10, </span><span class="identifier-syntax">N</span><span class="plain-syntax">%10);</span>
|
|
<span class="plain-syntax">}</span>
|
|
</pre>
|
|
<p class="commentary firstcommentary"><a id="SP31"></a><b>§31. </b>At one time, the following function was paranoid about thread-safety of
|
|
<span class="extract"><span class="extract-syntax">calloc</span></span> as implemented in some C libraries, and was protected by a mutex.
|
|
It has now learned to chill.
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::paranoid_calloc</span><button class="popup" onclick="togglePopup('usagePopup18')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup18">Usage of <span class="code-font"><span class="function-syntax">Memory::paranoid_calloc</span></span>:<br/><a href="2-mmr.html#SP11_1">§11.1</a>, <a href="2-mmr.html#SP25_1">§25.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="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="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="commentary firstcommentary"><a id="SP32"></a><b>§32. Run-time pointer type checking. </b>In several places Inform needs to store pointers of type <span class="extract"><span class="extract-syntax">void *</span></span>, 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="commentary">The structure <span class="extract"><span class="extract-syntax">general_pointer</span></span> holds a <span class="extract"><span class="extract-syntax">void *</span></span> pointer to any one of the
|
|
following:
|
|
</p>
|
|
|
|
<ul class="items"><li>(a) <span class="extract"><span class="extract-syntax">NULL</span></span>, to which we assign ID number \(-1\);
|
|
</li><li>(b) <span class="extract"><span class="extract-syntax">char</span></span>, 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, <span class="extract"><span class="extract-syntax">blorb_figure_CLASS</span></span>
|
|
is the ID number for a <span class="extract"><span class="extract-syntax">general_pointer</span></span> which points to a <span class="extract"><span class="extract-syntax">blorb_figure</span></span>
|
|
structure.
|
|
</li></ul>
|
|
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">NULL_GENERAL_POINTER</span><span class="plain-syntax"> (</span><a href="2-mmr.html#SP32" class="function-link"><span class="function-syntax">Memory::store_gp_null</span></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#SP32" class="function-link"><span class="function-syntax">Memory::test_gp_null</span></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 code-font">
|
|
<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><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-syntax"> guaranteed to differ from all </span><span class="extract"><span class="extract-syntax">_CLASS</span></span><span class="comment-syntax"> 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><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="commentary firstcommentary"><a id="SP33"></a><b>§33. </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 code-font"><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="commentary firstcommentary"><a id="SP34"></a><b>§34. </b>If we have a pointer to <span class="extract"><span class="extract-syntax">circus</span></span> (say) then <span class="extract"><span class="extract-syntax">g=STORE_POINTER_circus(p)</span></span>
|
|
returns a <span class="extract"><span class="extract-syntax">general_pointer</span></span> with <span class="extract"><span class="extract-syntax">p</span></span> as the actual pointer, but will not
|
|
compile unless <span class="extract"><span class="extract-syntax">p</span></span> is indeed of type <span class="extract"><span class="extract-syntax">circus *</span></span>. When we later
|
|
<span class="extract"><span class="extract-syntax">RETRIEVE_POINTER_circus(g)</span></span>, an internal error is thrown if <span class="extract"><span class="extract-syntax">g</span></span> contains a pointer
|
|
which is other than <span class="extract"><span class="extract-syntax">void *</span></span>, or which has never been referenced.
|
|
</p>
|
|
|
|
<pre class="definitions code-font"><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="commentary firstcommentary"><a id="SP35"></a><b>§35. </b>Suitable <span class="extract"><span class="extract-syntax">MAKE_REFERENCE_ROUTINES</span></span> were expanded for all of the memory
|
|
allocated objects above; so that leaves only humble <span class="extract"><span class="extract-syntax">char *</span></span> pointers:
|
|
</p>
|
|
|
|
<pre class="displayed-code all-displayed-code code-font">
|
|
<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>
|
|
<nav role="progress"><div class="progresscontainer">
|
|
<ul class="progressbar"><li class="progressprev"><a href="2-dl.html">❮</a></li><li class="progresschapter"><a href="P-abgtf.html">P</a></li><li class="progresschapter"><a href="1-fm.html">1</a></li><li class="progresscurrentchapter">2</li><li class="progresssection"><a href="2-dl.html">dl</a></li><li class="progresscurrent">mmr</li><li class="progresssection"><a href="2-fc.html">fc</a></li><li class="progresssection"><a href="2-lcl.html">lcl</a></li><li class="progresssection"><a href="2-str.html">str</a></li><li class="progresssection"><a href="2-wal.html">wal</a></li><li class="progresssection"><a href="2-mth.html">mth</a></li><li class="progresssection"><a href="2-llas.html">llas</a></li><li class="progresssection"><a href="2-dct.html">dct</a></li><li class="progresssection"><a href="2-trs.html">trs</a></li><li class="progresschapter"><a href="3-em.html">3</a></li><li class="progresschapter"><a href="4-chr.html">4</a></li><li class="progresschapter"><a href="5-htm.html">5</a></li><li class="progresschapter"><a href="6-bf.html">6</a></li><li class="progresschapter"><a href="7-vn.html">7</a></li><li class="progresschapter"><a href="8-ws.html">8</a></li><li class="progressnext"><a href="2-fc.html">❯</a></li></ul></div>
|
|
</nav><!--End of weave-->
|
|
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|