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 * An array of pointers to cons pages.
50 */
52
53/**
54 * Make a cons page. Initialise all cells and prepend each to the freelist;
55 * if `initialised_cons_pages` is zero, do not prepend cells 0 and 1 to the
56 * freelist but initialise them as NIL and T respectively.
57 * \todo we ought to handle cons space exhaustion more gracefully than just
58 * crashing; should probably return an exception instead, although obviously
59 * that exception would have to have been pre-built.
60 */
62 struct cons_page *result = malloc( sizeof( struct cons_page ) );
63
64 if ( result != NULL ) {
66
67 for ( int i = 0; i < CONSPAGESIZE; i++ ) {
68 struct cons_space_object *cell =
70 if ( initialised_cons_pages == 0 && i < 2 ) {
71 switch ( i ) {
72 case 0:
73 /*
74 * initialise cell as NIL
75 */
76 strncpy( &cell->tag.bytes[0], NILTAG, TAGLENGTH );
77 cell->count = MAXREFERENCE;
78 cell->payload.free.car = NIL;
79 cell->payload.free.cdr = NIL;
81 L"Allocated special cell NIL\n" );
82 break;
83 case 1:
84 /*
85 * initialise cell as T
86 */
87 strncpy( &cell->tag.bytes[0], TRUETAG, TAGLENGTH );
88 cell->count = MAXREFERENCE;
89 cell->payload.free.car = ( struct cons_pointer ) {
90 0, 1
91 };
92 cell->payload.free.cdr = ( struct cons_pointer ) {
93 0, 1
94 };
96 L"Allocated special cell T\n" );
97 break;
98 }
99 } else {
100 /*
101 * otherwise, standard initialisation
102 */
103 strncpy( &cell->tag.bytes[0], FREETAG, TAGLENGTH );
104 cell->payload.free.car = NIL;
105 cell->payload.free.cdr = freelist;
107 freelist.offset = i;
108 }
109 }
110
112 } else {
114 L"FATAL: Failed to allocate memory for cons page %d\n",
116 exit( 1 );
117 }
118
119}
120
121/**
122 * dump the allocated pages to this `output` stream.
123 */
124void dump_pages( URL_FILE *output ) {
125 for ( int i = 0; i < initialised_cons_pages; i++ ) {
126 url_fwprintf( output, L"\nDUMPING PAGE %d\n", i );
127
128 for ( int j = 0; j < CONSPAGESIZE; j++ ) {
129 dump_object( output, ( struct cons_pointer ) {
130 i, j
131 } );
132 }
133 }
134}
135
136/**
137 * Frees the cell at the specified `pointer`; for all the types of cons-space
138 * object which point to other cons-space objects, cascade the decrement.
139 * Dangerous, primitive, low level.
140 *
141 * @pointer the cell to free
142 */
143void free_cell( struct cons_pointer pointer ) {
144 struct cons_space_object *cell = &pointer2cell( pointer );
145
146 debug_printf( DEBUG_ALLOC, L"Freeing cell " );
147 debug_dump_object( pointer, DEBUG_ALLOC );
148
149 if ( !check_tag( pointer, FREETV ) ) {
150 if ( cell->count == 0 ) {
151 switch ( cell->tag.value ) {
152 case CONSTV:
153 dec_ref( cell->payload.cons.car );
154 dec_ref( cell->payload.cons.cdr );
155 break;
156 case EXCEPTIONTV:
157 dec_ref( cell->payload.exception.payload );
158 dec_ref( cell->payload.exception.frame );
159 break;
160 case FUNCTIONTV:
161 dec_ref( cell->payload.function.meta );
162 break;
163 case INTEGERTV:
164 dec_ref( cell->payload.integer.more );
165 break;
166 case LAMBDATV:
167 case NLAMBDATV:
168 dec_ref( cell->payload.lambda.args );
169 dec_ref( cell->payload.lambda.body );
170 break;
171 case RATIOTV:
172 dec_ref( cell->payload.ratio.dividend );
173 dec_ref( cell->payload.ratio.divisor );
174 break;
175 case READTV:
176 case WRITETV:
177 dec_ref( cell->payload.stream.meta );
178 url_fclose( cell->payload.stream.stream );
179 break;
180 case SPECIALTV:
181 dec_ref( cell->payload.special.meta );
182 break;
183 case STRINGTV:
184 case SYMBOLTV:
185 dec_ref( cell->payload.string.cdr );
186 break;
187 case VECTORPOINTTV:
188 free_vso( pointer );
189 break;
190 default:
191 fprintf( stderr, "WARNING: Freeing object of type %s!",
192 ( char * ) &( cell->tag.bytes ) );
193 }
194
195 strncpy( &cell->tag.bytes[0], FREETAG, TAGLENGTH );
196 cell->payload.free.car = NIL;
197 cell->payload.free.cdr = freelist;
198 freelist = pointer;
200 } else {
202 L"ERROR: Attempt to free cell with %d dangling references at page %d, offset %d\n",
203 cell->count, pointer.page, pointer.offset );
204 }
205 } else {
207 L"ERROR: Attempt to free cell which is already FREE at page %d, offset %d\n",
208 pointer.page, pointer.offset );
209 }
210}
211
212/**
213 * Allocates a cell with the specified `tag`. Dangerous, primitive, low
214 * level.
215 *
216 * @param tag the tag of the cell to allocate - must be a valid cons space tag.
217 * @return the cons pointer which refers to the cell allocated.
218 * \todo handle the case where another cons_page cannot be allocated;
219 * return an exception. Which, as we cannot create such an exception when
220 * cons space is exhausted, means we must construct it at init time.
221 */
222struct cons_pointer allocate_cell( uint32_t tag ) {
223 struct cons_pointer result = freelist;
224
225
226 if ( result.page == NIL.page && result.offset == NIL.offset ) {
228 result = allocate_cell( tag );
229 } else {
230 struct cons_space_object *cell = &pointer2cell( result );
231
232 if ( strncmp( &cell->tag.bytes[0], FREETAG, TAGLENGTH ) == 0 ) {
233 freelist = cell->payload.free.cdr;
234
235 cell->tag.value = tag;
236
237 cell->count = 1;
238 cell->payload.cons.car = NIL;
239 cell->payload.cons.cdr = NIL;
240
242
244 L"Allocated cell of type '%4.4s' at %d, %d \n",
245 cell->tag.bytes, result.page, result.offset );
246 } else {
247 debug_printf( DEBUG_ALLOC, L"WARNING: Allocating non-free cell!" );
248 }
249 }
250
251 return result;
252}
253
254/**
255 * initialise the cons page system; to be called exactly once during startup.
256 */
258 if ( conspageinitihasbeencalled == false ) {
259 for ( int i = 0; i < NCONSPAGES; i++ ) {
260 conspages[i] = ( struct cons_page * ) NULL;
261 }
262
265 } else {
267 L"WARNING: initialise_cons_pages() called a second or subsequent time\n" );
268 }
269}
270
272 fwprintf( stderr,
273 L"Allocation summary: allocated %lld; deallocated %lld; not deallocated %lld.\n",
276}
struct cons_pointer allocate_cell(uint32_t tag)
Allocates a cell with the specified tag.
Definition conspage.c:222
uint64_t total_cells_freed
Definition conspage.c:35
void make_cons_page()
Make a cons page.
Definition conspage.c:61
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:51
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:143
void dump_pages(URL_FILE *output)
dump the allocated pages to this output stream.
Definition conspage.c:124
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:271
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:257
#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 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:21
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.