gpgscm: Remove arbitrary limit on number of cell segments.

* tests/gpgscm/scheme-private.h (struct scheme): Remove fixed-size
arrays for cell segments, replace them with a pointer to the new
'struct cell_segment' instead.
* tests/gpgscm/scheme.c (struct cell_segment): New definition.
(_alloc_cellseg): Allocate the header within the segment, return a
pointer to the header.
(_dealloc_cellseg): New function.
(alloc_cellseg): Insert the segments into a list.
(_get_cell): Allocate a new segment if less than a quarter of
CELL_SIGSIZE is recovered during garbage collection.
(initialize_small_integers): Adapt callsite.
(gc): Walk the list of segments.
(scheme_init_custom_alloc): Remove initialization of removed field.
(scheme_deinit): Adapt deallocation.
--

Previously the number of cells that could be allocated was a
compile-time limit.  Remove this limit.

Signed-off-by: Justus Winter <justus@g10code.com>
This commit is contained in:
Justus Winter 2017-03-22 16:22:57 +01:00
parent bf8b5e9042
commit 56638c28ad
No known key found for this signature in database
GPG Key ID: DD1A52F9DA8C9020
2 changed files with 74 additions and 44 deletions

View File

@ -108,12 +108,7 @@ int tracing;
#ifndef CELL_SEGSIZE
#define CELL_SEGSIZE 5000 /* # of cells in one segment */
#endif
#ifndef CELL_NSEGMENT
#define CELL_NSEGMENT 10 /* # of segments for cells */
#endif
void *alloc_seg[CELL_NSEGMENT];
pointer cell_seg[CELL_NSEGMENT];
int last_cell_seg;
struct cell_segment *cell_segments;
/* We use 4 registers. */
pointer args; /* register for arguments of function */
@ -159,8 +154,7 @@ pointer COMPILE_HOOK; /* *compile-hook* */
#if USE_SMALL_INTEGERS
/* A fixed allocation of small integers. */
void *integer_alloc;
pointer integer_cells;
struct cell_segment *integer_segment;
#endif
pointer free_cell; /* pointer to top of free cells */

View File

@ -725,9 +725,26 @@ get_tag(scheme *sc, pointer v)
/* Low-level allocator.
*
* Memory is allocated in segments. Every segment holds a fixed
* number of cells. Segments are linked into a list, sorted in
* reverse address order (i.e. those with a higher address first).
* This is used in the garbage collector to build the freelist in
* address order.
*/
struct cell_segment
{
struct cell_segment *next;
void *alloc;
pointer cells;
size_t cells_len;
};
/* Allocate a new cell segment but do not make it available yet. */
static int
_alloc_cellseg(scheme *sc, size_t len, void **alloc, pointer *cells)
_alloc_cellseg(scheme *sc, size_t len, struct cell_segment **segment)
{
int adj = ADJ;
void *cp;
@ -735,46 +752,64 @@ _alloc_cellseg(scheme *sc, size_t len, void **alloc, pointer *cells)
if (adj < sizeof(struct cell))
adj = sizeof(struct cell);
cp = sc->malloc(len * sizeof(struct cell) + adj);
/* The segment header is conveniently allocated with the cells. */
cp = sc->malloc(sizeof **segment + len * sizeof(struct cell) + adj);
if (cp == NULL)
return 1;
*alloc = cp;
*segment = cp;
(*segment)->next = NULL;
(*segment)->alloc = cp;
cp = (void *) ((uintptr_t) cp + sizeof **segment);
/* adjust in TYPE_BITS-bit boundary */
if (((uintptr_t) cp) % adj != 0)
cp = (void *) (adj * ((uintptr_t) cp / adj + 1));
*cells = cp;
(*segment)->cells = cp;
(*segment)->cells_len = len;
return 0;
}
/* Deallocate a cell segment. Returns the next cell segment.
* Convenient for deallocation in a loop. */
static struct cell_segment *
_dealloc_cellseg(scheme *sc, struct cell_segment *segment)
{
struct cell_segment *next;
if (segment == NULL)
return NULL;
next = segment->next;
sc->free(segment->alloc);
return next;
}
/* allocate new cell segment */
static int alloc_cellseg(scheme *sc, int n) {
pointer newp;
pointer last;
pointer p;
long i;
int k;
for (k = 0; k < n; k++) {
if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
return k;
i = ++sc->last_cell_seg;
if (_alloc_cellseg(sc, CELL_SEGSIZE, &sc->alloc_seg[i], &newp)) {
sc->last_cell_seg--;
struct cell_segment *new, **s;
if (_alloc_cellseg(sc, CELL_SEGSIZE, &new)) {
return k;
}
/* insert new segment in address order */
sc->cell_seg[i] = newp;
while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
p = sc->cell_seg[i];
sc->cell_seg[i] = sc->cell_seg[i - 1];
sc->cell_seg[--i] = p;
}
sc->fcells += CELL_SEGSIZE;
last = newp + CELL_SEGSIZE - 1;
for (p = newp; p <= last; p++) {
/* insert new segment in reverse address order */
for (s = &sc->cell_segments;
*s && (uintptr_t) (*s)->alloc > (uintptr_t) new->alloc;
s = &(*s)->next) {
/* walk */
}
new->next = *s;
*s = new;
sc->fcells += new->cells_len;
last = new->cells + new->cells_len - 1;
for (p = new->cells; p <= last; p++) {
typeflag(p) = 0;
cdr(p) = p + 1;
car(p) = sc->NIL;
@ -782,13 +817,13 @@ static int alloc_cellseg(scheme *sc, int n) {
/* insert new cells in address order on free list */
if (sc->free_cell == sc->NIL || p < sc->free_cell) {
cdr(last) = sc->free_cell;
sc->free_cell = newp;
sc->free_cell = new->cells;
} else {
p = sc->free_cell;
while (cdr(p) != sc->NIL && newp > cdr(p))
while (cdr(p) != sc->NIL && (uintptr_t) new->cells > (uintptr_t) cdr(p))
p = cdr(p);
cdr(last) = cdr(p);
cdr(p) = newp;
cdr(p) = new->cells;
}
}
return n;
@ -922,7 +957,7 @@ static pointer _get_cell(scheme *sc, pointer a, pointer b) {
assert (gc_enabled (sc));
if (sc->free_cell == sc->NIL) {
const int min_to_be_recovered = sc->last_cell_seg*8;
const int min_to_be_recovered = CELL_SEGSIZE / 4;
gc(sc,a, b);
if (sc->fcells < min_to_be_recovered
|| sc->free_cell == sc->NIL) {
@ -1283,12 +1318,11 @@ static int
initialize_small_integers(scheme *sc)
{
int i;
if (_alloc_cellseg(sc, MAX_SMALL_INTEGER, &sc->integer_alloc,
&sc->integer_cells))
if (_alloc_cellseg(sc, MAX_SMALL_INTEGER, &sc->integer_segment))
return 1;
for (i = 0; i < MAX_SMALL_INTEGER; i++) {
pointer x = &sc->integer_cells[i];
pointer x = &sc->integer_segment->cells[i];
typeflag(x) = T_NUMBER | T_ATOM | MARK;
ivalue_unchecked(x) = i;
set_num_integer(x);
@ -1302,7 +1336,7 @@ mk_small_integer(scheme *sc, long n)
{
#define mk_small_integer_allocates 0
assert(0 <= n && n < MAX_SMALL_INTEGER);
return &sc->integer_cells[n];
return &sc->integer_segment->cells[n];
}
#else
@ -1666,6 +1700,7 @@ E6: /* up. Undo the link switching from steps E4 and E5. */
/* garbage collection. parameter a, b is marked. */
static void gc(scheme *sc, pointer a, pointer b) {
pointer p;
struct cell_segment *s;
int i;
assert (gc_enabled (sc));
@ -1712,9 +1747,9 @@ static void gc(scheme *sc, pointer a, pointer b) {
(which are also kept sorted by address) downwards to build the
free-list in sorted order.
*/
for (i = sc->last_cell_seg; i >= 0; i--) {
p = sc->cell_seg[i] + CELL_SEGSIZE;
while (--p >= sc->cell_seg[i]) {
for (s = sc->cell_segments; s; s = s->next) {
p = s->cells + s->cells_len;
while (--p >= s->cells) {
if ((typeflag(p) & 1) == 0)
/* All types have the LSB set. This is not a typeflag. */
continue;
@ -5592,7 +5627,6 @@ int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
sc->gensym_cnt=0;
sc->malloc=malloc;
sc->free=free;
sc->last_cell_seg = -1;
sc->sink = &sc->_sink;
sc->NIL = &sc->_NIL;
sc->T = &sc->_HASHT;
@ -5626,6 +5660,7 @@ int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
}
sc->strbuff_size = STRBUFFSIZE;
sc->cell_segments = NULL;
if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
sc->no_memory=1;
return 0;
@ -5726,6 +5761,7 @@ void scheme_set_external_data(scheme *sc, void *p) {
}
void scheme_deinit(scheme *sc) {
struct cell_segment *s;
int i;
sc->oblist=sc->NIL;
@ -5758,11 +5794,11 @@ void scheme_deinit(scheme *sc) {
gc(sc,sc->NIL,sc->NIL);
#if USE_SMALL_INTEGERS
sc->free(sc->integer_alloc);
_dealloc_cellseg(sc, sc->integer_segment);
#endif
for(i=0; i<=sc->last_cell_seg; i++) {
sc->free(sc->alloc_seg[i]);
for (s = sc->cell_segments; s; s = _dealloc_cellseg(sc, s)) {
/* nop */
}
sc->free(sc->strbuff);
}