Post Scarcity 0.0.6
A prototype for a post scarcity programming environment
Loading...
Searching...
No Matches
conspage.c
Go to the documentation of this file.
1/*
2 * conspage.c
3 *
4 * Setup and tear down cons pages, and (FOR NOW) do primitive
5 * allocation/deallocation of cells.
6 * NOTE THAT before we go multi-threaded, these functions must be
7 * aggressively
8 * thread safe.
9 *
10 * (c) 2017 Simon Brooke <simon@journeyman.cc>
11 * Licensed under GPL version 2.0, or, at your option, any later version.
12 */
13
14#include <stdbool.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
20#include "memory/conspage.h"
21#include "debug.h"
22#include "memory/dump.h"
23#include "memory/stack.h"
24#include "memory/vectorspace.h"
25
26/**
27 * Flag indicating whether conspage initialisation has been done.
28 */
30
31/**
32 * keep track of total cells allocated and freed to check for leakage.
33 */
35uint64_t total_cells_freed = 0;
36
37/**
38 * the number of cons pages which have thus far been initialised.
39 */
41
42/**
43 * The (global) pointer to the (global) freelist. Not sure whether this ultimately
44 * belongs in this file.
45 */
47
48/**
49 * The exception message printed when the world blows up, initialised in
50 * `maybe_bind_init_symbols()` in `init.c`, q.v.
51 */
53
54/**
55 * An array of pointers to cons pages.
56 */
58
59/**
60 * Make a cons page. Initialise all cells and prepend each to the freelist;
61 * if `initialised_cons_pages` is zero, do not prepend cells 0 and 1 to the
62 * freelist but initialise them as NIL and T respectively.
63 * \todo we ought to handle cons space exhaustion more gracefully than just
64 * crashing; should probably return an exception instead, although obviously
65 * that exception would have to have been pre-built.
66 */
68 struct cons_page *result = NULL;
69
71 result = malloc( sizeof( struct cons_page ) );
72 }
73
74 if ( result != NULL ) {
76
77 for ( int i = 0; i < CONSPAGESIZE; i++ ) {
78 struct cons_space_object *cell =
80 if ( initialised_cons_pages == 0 && i < 2 ) {
81 switch ( i ) {
82 case 0:
83 /*
84 * initialise cell as NIL
85 */
86 strncpy( &cell->tag.bytes[0], NILTAG, TAGLENGTH );
87 cell->count = MAXREFERENCE;
88 cell->payload.free.car = NIL;
89 cell->payload.free.cdr = NIL;
91 L"Allocated special cell NIL\n" );
92 break;
93 case 1:
94 /*
95 * initialise cell as T
96 */
97 strncpy( &cell->tag.bytes[0], TRUETAG, TAGLENGTH );
98 cell->count = MAXREFERENCE;
99 cell->payload.free.car = ( struct cons_pointer ) {
100 0, 1
101 };
102 cell->payload.free.cdr = ( struct cons_pointer ) {
103 0, 1
104 };
106 L"Allocated special cell T\n" );
107 break;
108 }
109 } else {
110 /*
111 * otherwise, standard initialisation
112 */
113 strncpy( &cell->tag.bytes[0], FREETAG, TAGLENGTH );
114 cell->payload.free.car = NIL;
115 cell->payload.free.cdr = freelist;
117 freelist.offset = i;
118 }
119 }
120
122 } else {
123 fwide( stderr, 1 );
124 fwprintf( stderr,
125 L"FATAL: Failed to allocate memory for cons page %d\n",
127 exit( 1 );
128 }
129}
130
131/**
132 * dump the allocated pages to this `output` stream.
133 */
134void dump_pages( URL_FILE *output ) {
135 for ( int i = 0; i < initialised_cons_pages; i++ ) {
136 url_fwprintf( output, L"\nDUMPING PAGE %d\n", i );
137
138 for ( int j = 0; j < CONSPAGESIZE; j++ ) {
139 struct cons_pointer pointer = ( struct cons_pointer ) { i, j };
140 if ( !freep( pointer ) ) {
141 dump_object( output, ( struct cons_pointer ) {
142 i, j
143 } );
144 }
145 }
146 }
147}
148
149/**
150 * Frees the cell at the specified `pointer`; for all the types of cons-space
151 * object which point to other cons-space objects, cascade the decrement.
152 * Dangerous, primitive, low level.
153 *
154 * @pointer the cell to free
155 */
156void free_cell( struct cons_pointer pointer ) {
157 struct cons_space_object *cell = &pointer2cell( pointer );
158
159 debug_printf( DEBUG_ALLOC, L"Freeing cell " );
160 debug_dump_object( pointer, DEBUG_ALLOC );
161
162 if ( !check_tag( pointer, FREETV ) ) {
163 if ( cell->count == 0 ) {
164 switch ( cell->tag.value ) {
165 case CONSTV:
166 dec_ref( cell->payload.cons.car );
167 dec_ref( cell->payload.cons.cdr );
168 break;
169 case EXCEPTIONTV:
170 dec_ref( cell->payload.exception.payload );
171 dec_ref( cell->payload.exception.frame );
172 break;
173 case FUNCTIONTV:
174 dec_ref( cell->payload.function.meta );
175 break;
176 case INTEGERTV:
177 dec_ref( cell->payload.integer.more );
178 break;
179 case LAMBDATV:
180 case NLAMBDATV:
181 dec_ref( cell->payload.lambda.args );
182 dec_ref( cell->payload.lambda.body );
183 break;
184 case RATIOTV:
185 dec_ref( cell->payload.ratio.dividend );
186 dec_ref( cell->payload.ratio.divisor );
187 break;
188 case READTV:
189 case WRITETV:
190 dec_ref( cell->payload.stream.meta );
191 url_fclose( cell->payload.stream.stream );
192 break;
193 case SPECIALTV:
194 dec_ref( cell->payload.special.meta );
195 break;
196 case STRINGTV:
197 case SYMBOLTV:
198 dec_ref( cell->payload.string.cdr );
199 break;
200 case VECTORPOINTTV:
201 free_vso( pointer );
202 break;
203 default:
204 fprintf( stderr, "WARNING: Freeing object of type %s!",
205 ( char * ) &( cell->tag.bytes ) );
206 }
207
208 strncpy( &cell->tag.bytes[0], FREETAG, TAGLENGTH );
209 cell->payload.free.car = NIL;
210 cell->payload.free.cdr = freelist;
211 freelist = pointer;
213 } else {
215 L"ERROR: Attempt to free cell with %d dangling references at page %d, offset %d\n",
216 cell->count, pointer.page, pointer.offset );
217 }
218 } else {
220 L"ERROR: Attempt to free cell which is already FREE at page %d, offset %d\n",
221 pointer.page, pointer.offset );
222 }
223}
224
225/**
226 * Allocates a cell with the specified `tag`. Dangerous, primitive, low
227 * level.
228 *
229 * @param tag the tag of the cell to allocate - must be a valid cons space tag.
230 * @return the cons pointer which refers to the cell allocated.
231 * \todo handle the case where another cons_page cannot be allocated;
232 * return an exception. Which, as we cannot create such an exception when
233 * cons space is exhausted, means we must construct it at init time.
234 */
235struct cons_pointer allocate_cell( uint32_t tag ) {
236 struct cons_pointer result = freelist;
237
238
239 if ( result.page == NIL.page && result.offset == NIL.offset ) {
241 result = allocate_cell( tag );
242 } else {
243 struct cons_space_object *cell = &pointer2cell( result );
244
245 if ( strncmp( &cell->tag.bytes[0], FREETAG, TAGLENGTH ) == 0 ) {
246 freelist = cell->payload.free.cdr;
247
248 cell->tag.value = tag;
249
250 cell->count = 1;
251 cell->payload.cons.car = NIL;
252 cell->payload.cons.cdr = NIL;
253
255
257 L"Allocated cell of type %4.4s at %u, %u \n",
258 ( ( char * ) cell->tag.bytes ), result.page,
259 result.offset );
260 } else {
261 debug_printf( DEBUG_ALLOC, L"WARNING: Allocating non-free cell!" );
262 }
263 }
264
265 return result;
266}
267
268/**
269 * initialise the cons page system; to be called exactly once during startup.
270 */
272 if ( conspageinitihasbeencalled == false ) {
273 for ( int i = 0; i < NCONSPAGES; i++ ) {
274 conspages[i] = ( struct cons_page * ) NULL;
275 }
276
279 } else {
281 L"WARNING: initialise_cons_pages() called a second or subsequent time\n" );
282 }
283}
284
286 fwprintf( stderr,
287 L"Allocation summary: allocated %lld; deallocated %lld; not deallocated %lld.\n",
290}
struct cons_pointer allocate_cell(uint32_t tag)
Allocates a cell with the specified tag.
Definition conspage.c:235
uint64_t total_cells_freed
Definition conspage.c:35
void make_cons_page()
Make a cons page.
Definition conspage.c:67
int initialised_cons_pages
the number of cons pages which have thus far been initialised.
Definition conspage.c:40
bool conspageinitihasbeencalled
Flag indicating whether conspage initialisation has been done.
Definition conspage.c:29
struct cons_page * conspages[NCONSPAGES]
An array of pointers to cons pages.
Definition conspage.c:57
void free_cell(struct cons_pointer pointer)
Frees the cell at the specified pointer; for all the types of cons-space object which point to other ...
Definition conspage.c:156
void dump_pages(URL_FILE *output)
dump the allocated pages to this output stream.
Definition conspage.c:134
struct cons_pointer privileged_string_memory_exhausted
The exception message printed when the world blows up, initialised in maybe_bind_init_symbols() in in...
Definition conspage.c:52
uint64_t total_cells_allocated
keep track of total cells allocated and freed to check for leakage.
Definition conspage.c:34
void summarise_allocation()
Definition conspage.c:285
struct cons_pointer freelist
The (global) pointer to the (global) freelist.
Definition conspage.c:46
void initialise_cons_pages()
initialise the cons page system; to be called exactly once during startup.
Definition conspage.c:271
#define NCONSPAGES
the number of cons pages we will initially allow for.
Definition conspage.h:40
#define CONSPAGESIZE
the number of cons cells on a cons page.
Definition conspage.h:24
struct cons_space_object cell[CONSPAGESIZE]
Definition conspage.h:49
a cons page is essentially just an array of cons space objects.
Definition conspage.h:48
bool check_tag(struct cons_pointer pointer, uint32_t value)
True if the value of the tag on the cell at this pointer is this value, or, if the tag of the cell is...
struct cons_pointer dec_ref(struct cons_pointer pointer)
Decrement the reference count of the object at this cons pointer.
#define SPECIALTV
The string SPFM, considered as an unsigned int.
#define freep(conspoint)
true if conspoint points to an unassigned cell, else false
#define VECTORPOINTTV
The string VECP, considered as an unsigned int.
#define SYMBOLTV
The string SYMB, considered as an unsigned int.
union cons_space_object::@2 tag
union cons_space_object::@3 payload
#define NIL
a cons pointer which points to the special NIL cell
#define FUNCTIONTV
The string FUNC, considered as an unsigned int.
uint32_t page
the index of the page on which this cell resides
#define STRINGTV
The string STRG, considered as an unsigned int.
#define INTEGERTV
The string INTR, considered as an unsigned int.
#define FREETAG
An unallocated cell on the free list - should never be encountered by a Lisp function.
#define FREETV
The string FREE, considered as an unsigned int.
#define NILTAG
The special cons cell at address {0,0} whose car and cdr both point to itself.
#define TAGLENGTH
The length of a tag, in bytes.
#define RATIOTV
The string RTIO, considered as an unsigned int.
#define CONSTV
The string CONS, considered as an unsigned int.
#define TRUETAG
The special cons cell at address {0,1} which is canonically different from NIL.
#define NLAMBDATV
The string NLMD, considered as an unsigned int.
uint32_t count
the count of the number of references to this cell
uint32_t offset
the index of the cell within the page
#define EXCEPTIONTV
The string EXEP, considered as an unsigned int.
#define MAXREFERENCE
the maximum possible value of a reference count
#define LAMBDATV
The string LMDA, considered as an unsigned int.
#define WRITETV
The string WRIT, considered as an unsigned int.
#define READTV
The string READ, considered as an unsigned int.
#define pointer2cell(pointer)
given a cons_pointer as argument, return the cell.
An indirect pointer to a cons cell.
an object in cons space.
void debug_dump_object(struct cons_pointer pointer, int level)
Like dump_object, q.v., but protected by the verbosity mechanism.
Definition debug.c:155
void debug_printf(int level, wchar_t *format,...)
wprintf adapted for the debug logging system.
Definition debug.c:120
#define DEBUG_ALLOC
Print messages debugging memory allocation.
Definition debug.h:24
void dump_object(URL_FILE *output, struct cons_pointer pointer)
dump the object at this cons_pointer to this output stream.
Definition dump.c:59
int url_fclose(URL_FILE *file)
Definition fopen.c:258
#define url_fwprintf(f,...)
Definition fopen.h:50
void free_vso(struct cons_pointer pointer)
for vector space pointers, free the actual vector-space object.