1 /* DLIFE Copyright (C) 2000 Richard W.M. Jones <rich@annexia.org>
2 * and other authors listed in the ``AUTHORS'' file.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 * $Id: soup.c,v 1.2 2002/04/05 16:47:13 rich Exp $
41 #define TRACE_SOUP_ALLOCATIONS 0
44 soup_init (struct state *state, int _soup_size)
48 state->soup_size = _soup_size;
49 state->soup_free = _soup_size;
50 state->soup = malloc (_soup_size);
51 if (state->soup == 0) { perror ("malloc"); abort (); }
53 /* Fill the soup with entropy. */
54 for (i = 0; i < _soup_size; ++i)
56 state->soup[i] = get_rand_byte ();
60 /* Allocate a new fragment of soup. */
62 soup_frag_malloc (struct state *state,
63 struct soup_frag *mother_frag, reg_t len)
65 struct soup_frag *p, *t;
67 int is_first_cell = state->soup_free == state->soup_size;
69 #if TRACE_SOUP_ALLOCATIONS
70 printf ("soup alloc: want %d bytes ", len);
73 p = malloc (sizeof (struct soup_frag));
74 if (p == 0) { perror ("malloc"); abort (); }
78 state->soup_free -= len;
80 /* The first cell is allocated specially. */
87 #if TRACE_SOUP_ALLOCATIONS
88 printf ("first cell 0 OK\n");
94 /* If a cell has no parent, we can insert it anywhere. */
97 /* Need to go and grab a cell at random, then search indefinitely
100 mother_frag = _cell_get_any_frag (state);
108 #if TRACE_SOUP_ALLOCATIONS
109 printf ("[%d,%d:%d,%d] ",
110 t->base, t->base + t->len,
111 t->next->base, t->next->base + t->next->len);
114 /* Handle the wrap-around case gracefully. */
115 if (t->next->base > t->base)
116 diff = t->next->base - (t->base + t->len);
118 diff = t->next->base - (t->base + t->len) + state->soup_size;
120 /* Is there space after this fragment? */
123 /* Yes: insert the cell here. */
126 p->base = (t->base + t->len) & (state->soup_size-1);
130 #if TRACE_SOUP_ALLOCATIONS
131 printf ("%d OK\n", p->base);
137 offset += diff + t->len;
140 while (offset <= state->soup_size && t != mother_frag);
142 /* No space for it. */
143 state->soup_free += len;
146 #if TRACE_SOUP_ALLOCATIONS
153 /* Find a suitable fragment near the mother. */
155 /* Search forwards first. */
162 #if TRACE_SOUP_ALLOCATIONS
163 printf ("[%d,%d:%d,%d] ",
164 t->base, t->base + t->len,
165 t->next->base, t->next->base + t->next->len);
168 /* Handle the wrap-around case gracefully. */
169 if (t->next->base > t->base)
170 diff = t->next->base - (t->base + t->len);
172 diff = t->next->base - (t->base + t->len) + state->soup_size;
174 /* Is there space after this fragment? */
177 /* Yes: insert the cell here. */
180 p->base = (t->base + t->len) & (state->soup_size-1);
184 #if TRACE_SOUP_ALLOCATIONS
185 printf ("%d OK\n", p->base);
191 offset += diff + t->len;
194 while (offset <= MAX_SPAWN_DISTANCE && t != mother_frag);
196 /* Search backwards. */
203 #if TRACE_SOUP_ALLOCATIONS
204 printf ("[%d,%d:%d,%d] ",
205 t->prev->base, t->prev->base + t->prev->len,
206 t->base, t->base + t->len);
209 /* Handle the wrap-around case gracefully. */
210 if (t->prev->base < t->base)
211 diff = t->base - (t->prev->base + t->prev->len);
213 diff = t->base - (t->prev->base + t->prev->len) + state->soup_size;
215 /* Is there space before this fragment? */
218 /* Yes: insert the cell here. */
221 p->base = (t->base - len) & (state->soup_size-1);
226 #if TRACE_SOUP_ALLOCATIONS
227 printf ("%d OK\n", p->base);
233 offset += diff + t->prev->len;
236 while (offset <= MAX_SPAWN_DISTANCE && t != mother_frag);
238 /* No space for it. */
239 state->soup_free += len;
242 #if TRACE_SOUP_ALLOCATIONS
249 /* Free up a soup fragment. */
251 soup_frag_free (struct state *state,
252 struct soup_frag *frag)
254 /* NB. We ignore the case of freeing up the single last remaining
255 * fragment, since that should never happen in real life.
257 frag->next->prev = frag->prev;
258 frag->prev->next = frag->next;
260 state->soup_free += frag->len;
265 /* Compute the CRC for a frag. */
267 soup_frag_compute_crc32 (const struct state *state,
268 const struct soup_frag *frag)
270 /* Take care of the case where a cell straddles the end of the soup. */
271 if (frag->base + frag->len <= state->soup_size)
273 return compute_crc32 (state->soup + frag->base, frag->len);
277 crc_t crc = compute_crc32 (state->soup + frag->base,
278 state->soup_size - frag->base);
279 return incr_compute_crc32 (crc, state->soup,
280 frag->len - (state->soup_size - frag->base));
285 /* This function checks that the soup is consistent. We are passed
286 * one fragment (at random) and walk the circular linked list,
287 * examining the fragments to ensure they are in order and do not
291 soup_check (struct state *state)
293 const struct soup_frag *start_frag = _cell_get_any_frag (state);
294 const struct soup_frag *frag = start_frag;
296 int soup_free = state->soup_size;
300 assert (0 <= frag->base && frag->base < state->soup_size);
301 assert (frag->len > 0);
303 assert (frag->next->prev == frag);
304 assert (frag->prev->next == frag);
306 if (frag->prev->base < frag->base)
307 assert (frag->prev->base + frag->prev->len <= frag->base);
309 assert (frag->prev->base + frag->prev->len <= frag->base + state->soup_size);
311 if (frag->base < frag->next->base)
312 assert (frag->base + frag->len <= frag->next->base);
314 assert (frag->base + frag->len <= frag->next->base + state->soup_size);
316 soup_free -= frag->len;
321 while (frag != start_frag);
323 assert (nr_frags == state->nr_cells_allocated);
324 assert (soup_free == state->soup_free);
327 /* Dump the soup and soup structures out to a file. This function is
331 soup_state_save (struct state *state, FILE *fp)
333 struct soup_frag *start_frag, *frag;
335 /* Write out the size of the soup. */
336 fwrite (&state->soup_size, sizeof state->soup_size, 1, fp);
337 fwrite (&state->soup_free, sizeof state->soup_free, 1, fp);
339 /* Write out the soup itself. */
340 fwrite (state->soup, 1, state->soup_size, fp);
342 /* Write out the number of fragments. Note that this is the same
343 * as the number of allocated cells.
345 fwrite (&state->nr_cells_allocated,
346 sizeof state->nr_cells_allocated, 1, fp);
348 /* Write out the fragment list. */
349 frag = start_frag = _cell_get_any_frag (state);
352 fwrite (frag, sizeof (struct soup_frag), 1, fp);
356 while (frag != start_frag);
359 /* Load the soup state from a previously saved file. */
361 soup_state_load (struct state *state, FILE *fp)
363 int _soup_size, nr_frags, i;
364 struct soup_frag *first_frag = 0, *prev_frag = 0;
366 /* Load the size of the soup expected. */
367 if (fread (&_soup_size, sizeof _soup_size, 1, fp) != 1)
369 fprintf (stderr, "error in soup state\n");
372 if (state->soup_size != _soup_size)
374 fprintf (stderr, "soup size doesn't match - can't load this soup image\n");
377 if (fread (&state->soup_free, sizeof state->soup_free, 1, fp) != 1)
379 fprintf (stderr, "error in soup state\n");
382 if (state->soup_free > state->soup_size)
384 fprintf (stderr, "soup free > soup_size - can't load this soup image\n");
388 /* Load the soup itself. */
389 if (fread (state->soup, 1, _soup_size, fp) != _soup_size)
391 fprintf (stderr, "error in soup state\n");
395 /* Load the number of fragments expected. */
396 if (fread (&nr_frags, sizeof nr_frags, 1, fp) != 1)
398 fprintf (stderr, "error in soup state\n");
401 if (nr_frags != state->nr_cells_allocated)
403 fprintf (stderr, "nr_frags != nr_cells_allocated - can't load this soup image\n");
407 /* Load each fragment. */
408 for (i = 0; i < nr_frags; ++i)
412 p = malloc (sizeof (struct soup_frag));
413 if (p == 0) { perror ("malloc"); abort (); }
415 if (fread (p, sizeof (struct soup_frag), 1, fp) != 1)
417 fprintf (stderr, "error in soup state\n");
424 /* Find the cell which references this fragment and fix it up. */
425 _cell_fixup_soup_ref (state, p->base, p);
427 /* Join the fragments to form a circular linked list. */
437 /* Finish off the circular linked list. */
438 first_frag->prev = prev_frag;
439 prev_frag->next = first_frag;