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