Post Scarcity
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 = malloc( sizeof( struct cons_page ) );
69
70 if ( result != NULL ) {
72
73 for ( int i = 0; i < CONSPAGESIZE; i++ ) {
74 struct cons_space_object *cell =
76 if ( initialised_cons_pages == 0 && i < 2 ) {
77 switch ( i ) {
78 case 0:
79 /*
80 * initialise cell as NIL
81 */
82 strncpy( &cell->tag.bytes[0], NILTAG, TAGLENGTH );
83 cell->count = MAXREFERENCE;
84 cell->payload.free.car = NIL;
85 cell->payload.free.cdr = NIL;
87 L"Allocated special cell NIL\n" );
88 break;
89 case 1:
90 /*
91 * initialise cell as T
92 */
93 strncpy( &cell->tag.bytes[0], TRUETAG, TAGLENGTH );
94 cell->count = MAXREFERENCE;
95 cell->payload.free.car = ( struct cons_pointer ) {
96 0, 1
97 };
98 cell->payload.free.cdr = ( struct cons_pointer ) {
99 0, 1
100 };
102 L"Allocated special cell T\n" );
103 break;
104 }
105 } else {
106 /*
107 * otherwise, standard initialisation
108 */
109 strncpy( &cell->tag.bytes[0], FREETAG, TAGLENGTH );
110 cell->payload.free.car = NIL;
111 cell->payload.free.cdr = freelist;
113 freelist.offset = i;
114 }
115 }
116
118 } else {
120 L"FATAL: Failed to allocate memory for cons page %d\n",
122 exit( 1 );
123 }
124
125}
126
127/**
128 * dump the allocated pages to this `output` stream.
129 */
130void dump_pages( URL_FILE *output ) {
131 for ( int i = 0; i < initialised_cons_pages; i++ ) {
132 url_fwprintf( output, L"\nDUMPING PAGE %d\n", i );
133
134 for ( int j = 0; j < CONSPAGESIZE; j++ ) {
135 struct cons_pointer pointer = ( struct cons_pointer ) { i, j };
136 if ( !freep( pointer ) ) {
137 dump_object( output, ( struct cons_pointer ) {
138 i, j
139 } );
140 }
141 }
142 }
143}
144
145/**
146 * Frees the cell at the specified `pointer`; for all the types of cons-space
147 * object which point to other cons-space objects, cascade the decrement.
148 * Dangerous, primitive, low level.
149 *
150 * @pointer the cell to free
151 */
152void free_cell( struct cons_pointer pointer ) {
153 struct cons_space_object *cell = &pointer2cell( pointer );
154
155 debug_printf( DEBUG_ALLOC, L"Freeing cell " );
156 debug_dump_object( pointer, DEBUG_ALLOC );
157
158 if ( !check_tag( pointer, FREETV ) ) {
159 if ( cell->count == 0 ) {
160 switch ( cell->tag.value ) {
161 case CONSTV:
162 dec_ref( cell->payload.cons.car );
163 dec_ref( cell->payload.cons.cdr );
164 break;
165 case EXCEPTIONTV:
166 dec_ref( cell->payload.exception.payload );
167 dec_ref( cell->payload.exception.frame );
168 break;
169 case FUNCTIONTV:
170 dec_ref( cell->payload.function.meta );
171 break;
172 case INTEGERTV:
173 dec_ref( cell->payload.integer.more );
174 break;
175 case LAMBDATV:
176 case NLAMBDATV:
177 dec_ref( cell->payload.lambda.args );
178 dec_ref( cell->payload.lambda.body );
179 break;
180 case RATIOTV:
181 dec_ref( cell->payload.ratio.dividend );
182 dec_ref( cell->payload.ratio.divisor );
183 break;
184 case READTV:
185 case WRITETV:
186 dec_ref( cell->payload.stream.meta );
187 url_fclose( cell->payload.stream.stream );
188 break;
189 case SPECIALTV:
190 dec_ref( cell->payload.special.meta );
191 break;
192 case STRINGTV:
193 case SYMBOLTV:
194 dec_ref( cell->payload.string.cdr );
195 break;
196 case VECTORPOINTTV:
197 free_vso( pointer );
198 break;
199 default:
200 fprintf( stderr, "WARNING: Freeing object of type %s!",
201 ( char * ) &( cell->tag.bytes ) );
202 }
203
204 strncpy( &cell->tag.bytes[0], FREETAG, TAGLENGTH );
205 cell->payload.free.car = NIL;
206 cell->payload.free.cdr = freelist;
207 freelist = pointer;
209 } else {
211 L"ERROR: Attempt to free cell with %d dangling references at page %d, offset %d\n",
212 cell->count, pointer.page, pointer.offset );
213 }
214 } else {
216 L"ERROR: Attempt to free cell which is already FREE at page %d, offset %d\n",
217 pointer.page, pointer.offset );
218 }
219}
220
221/**
222 * Allocates a cell with the specified `tag`. Dangerous, primitive, low
223 * level.
224 *
225 * @param tag the tag of the cell to allocate - must be a valid cons space tag.
226 * @return the cons pointer which refers to the cell allocated.
227 * \todo handle the case where another cons_page cannot be allocated;
228 * return an exception. Which, as we cannot create such an exception when
229 * cons space is exhausted, means we must construct it at init time.
230 */
231struct cons_pointer allocate_cell( uint32_t tag ) {
232 struct cons_pointer result = freelist;
233
234
235 if ( result.page == NIL.page && result.offset == NIL.offset ) {
237 result = allocate_cell( tag );
238 } else {
239 struct cons_space_object *cell = &pointer2cell( result );
240
241 if ( strncmp( &cell->tag.bytes[0], FREETAG, TAGLENGTH ) == 0 ) {
242 freelist = cell->payload.free.cdr;
243
244 cell->tag.value = tag;
245
246 cell->count = 1;
247 cell->payload.cons.car = NIL;
248 cell->payload.cons.cdr = NIL;
249
251
253 L"Allocated cell of type '%4.4s' at %d, %d \n",
254 cell->tag.bytes, result.page, result.offset );
255 } else {
256 debug_printf( DEBUG_ALLOC, L"WARNING: Allocating non-free cell!" );
257 }
258 }
259
260 return result;
261}
262
263/**
264 * initialise the cons page system; to be called exactly once during startup.
265 */
267 if ( conspageinitihasbeencalled == false ) {
268 for ( int i = 0; i < NCONSPAGES; i++ ) {
269 conspages[i] = ( struct cons_page * ) NULL;
270 }
271
274 } else {
276 L"WARNING: initialise_cons_pages() called a second or subsequent time\n" );
277 }
278}
279
281 fwprintf( stderr,
282 L"Allocation summary: allocated %lld; deallocated %lld; not deallocated %lld.\n",
285}
struct cons_pointer allocate_cell(uint32_t tag)
Allocates a cell with the specified tag.
Definition conspage.c:231
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:152
void dump_pages(URL_FILE *output)
dump the allocated pages to this output stream.
Definition conspage.c:130
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:280
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:266
#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:136
void debug_printf(int level, wchar_t *format,...)
wprintf adapted for the debug logging system.
Definition debug.c:101
#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.