1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

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 #ifndef CELL_SEGSIZE
#define CELL_SEGSIZE 5000 /* # of cells in one segment */ #define CELL_SEGSIZE 5000 /* # of cells in one segment */
#endif #endif
#ifndef CELL_NSEGMENT struct cell_segment *cell_segments;
#define CELL_NSEGMENT 10 /* # of segments for cells */
#endif
void *alloc_seg[CELL_NSEGMENT];
pointer cell_seg[CELL_NSEGMENT];
int last_cell_seg;
/* We use 4 registers. */ /* We use 4 registers. */
pointer args; /* register for arguments of function */ pointer args; /* register for arguments of function */
@ -159,8 +154,7 @@ pointer COMPILE_HOOK; /* *compile-hook* */
#if USE_SMALL_INTEGERS #if USE_SMALL_INTEGERS
/* A fixed allocation of small integers. */ /* A fixed allocation of small integers. */
void *integer_alloc; struct cell_segment *integer_segment;
pointer integer_cells;
#endif #endif
pointer free_cell; /* pointer to top of free cells */ 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. */ /* Allocate a new cell segment but do not make it available yet. */
static int 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; int adj = ADJ;
void *cp; void *cp;
@ -735,46 +752,64 @@ _alloc_cellseg(scheme *sc, size_t len, void **alloc, pointer *cells)
if (adj < sizeof(struct cell)) if (adj < sizeof(struct cell))
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) if (cp == NULL)
return 1; 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 */ /* adjust in TYPE_BITS-bit boundary */
if (((uintptr_t) cp) % adj != 0) if (((uintptr_t) cp) % adj != 0)
cp = (void *) (adj * ((uintptr_t) cp / adj + 1)); cp = (void *) (adj * ((uintptr_t) cp / adj + 1));
*cells = cp; (*segment)->cells = cp;
(*segment)->cells_len = len;
return 0; 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 */ /* allocate new cell segment */
static int alloc_cellseg(scheme *sc, int n) { static int alloc_cellseg(scheme *sc, int n) {
pointer newp;
pointer last; pointer last;
pointer p; pointer p;
long i;
int k; int k;
for (k = 0; k < n; k++) { for (k = 0; k < n; k++) {
if (sc->last_cell_seg >= CELL_NSEGMENT - 1) struct cell_segment *new, **s;
return k; if (_alloc_cellseg(sc, CELL_SEGSIZE, &new)) {
i = ++sc->last_cell_seg;
if (_alloc_cellseg(sc, CELL_SEGSIZE, &sc->alloc_seg[i], &newp)) {
sc->last_cell_seg--;
return k; return k;
} }
/* insert new segment in address order */ /* insert new segment in reverse address order */
sc->cell_seg[i] = newp; for (s = &sc->cell_segments;
while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) { *s && (uintptr_t) (*s)->alloc > (uintptr_t) new->alloc;
p = sc->cell_seg[i]; s = &(*s)->next) {
sc->cell_seg[i] = sc->cell_seg[i - 1]; /* walk */
sc->cell_seg[--i] = p; }
} new->next = *s;
sc->fcells += CELL_SEGSIZE; *s = new;
last = newp + CELL_SEGSIZE - 1;
for (p = newp; p <= last; p++) { sc->fcells += new->cells_len;
last = new->cells + new->cells_len - 1;
for (p = new->cells; p <= last; p++) {
typeflag(p) = 0; typeflag(p) = 0;
cdr(p) = p + 1; cdr(p) = p + 1;
car(p) = sc->NIL; 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 */ /* insert new cells in address order on free list */
if (sc->free_cell == sc->NIL || p < sc->free_cell) { if (sc->free_cell == sc->NIL || p < sc->free_cell) {
cdr(last) = sc->free_cell; cdr(last) = sc->free_cell;
sc->free_cell = newp; sc->free_cell = new->cells;
} else { } else {
p = sc->free_cell; 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); p = cdr(p);
cdr(last) = cdr(p); cdr(last) = cdr(p);
cdr(p) = newp; cdr(p) = new->cells;
} }
} }
return n; return n;
@ -922,7 +957,7 @@ static pointer _get_cell(scheme *sc, pointer a, pointer b) {
assert (gc_enabled (sc)); assert (gc_enabled (sc));
if (sc->free_cell == sc->NIL) { 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); gc(sc,a, b);
if (sc->fcells < min_to_be_recovered if (sc->fcells < min_to_be_recovered
|| sc->free_cell == sc->NIL) { || sc->free_cell == sc->NIL) {
@ -1283,12 +1318,11 @@ static int
initialize_small_integers(scheme *sc) initialize_small_integers(scheme *sc)
{ {
int i; int i;
if (_alloc_cellseg(sc, MAX_SMALL_INTEGER, &sc->integer_alloc, if (_alloc_cellseg(sc, MAX_SMALL_INTEGER, &sc->integer_segment))
&sc->integer_cells))
return 1; return 1;
for (i = 0; i < MAX_SMALL_INTEGER; i++) { 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; typeflag(x) = T_NUMBER | T_ATOM | MARK;
ivalue_unchecked(x) = i; ivalue_unchecked(x) = i;
set_num_integer(x); set_num_integer(x);
@ -1302,7 +1336,7 @@ mk_small_integer(scheme *sc, long n)
{ {
#define mk_small_integer_allocates 0 #define mk_small_integer_allocates 0
assert(0 <= n && n < MAX_SMALL_INTEGER); assert(0 <= n && n < MAX_SMALL_INTEGER);
return &sc->integer_cells[n]; return &sc->integer_segment->cells[n];
} }
#else #else
@ -1666,6 +1700,7 @@ E6: /* up. Undo the link switching from steps E4 and E5. */
/* garbage collection. parameter a, b is marked. */ /* garbage collection. parameter a, b is marked. */
static void gc(scheme *sc, pointer a, pointer b) { static void gc(scheme *sc, pointer a, pointer b) {
pointer p; pointer p;
struct cell_segment *s;
int i; int i;
assert (gc_enabled (sc)); 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 (which are also kept sorted by address) downwards to build the
free-list in sorted order. free-list in sorted order.
*/ */
for (i = sc->last_cell_seg; i >= 0; i--) { for (s = sc->cell_segments; s; s = s->next) {
p = sc->cell_seg[i] + CELL_SEGSIZE; p = s->cells + s->cells_len;
while (--p >= sc->cell_seg[i]) { while (--p >= s->cells) {
if ((typeflag(p) & 1) == 0) if ((typeflag(p) & 1) == 0)
/* All types have the LSB set. This is not a typeflag. */ /* All types have the LSB set. This is not a typeflag. */
continue; continue;
@ -5592,7 +5627,6 @@ int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
sc->gensym_cnt=0; sc->gensym_cnt=0;
sc->malloc=malloc; sc->malloc=malloc;
sc->free=free; sc->free=free;
sc->last_cell_seg = -1;
sc->sink = &sc->_sink; sc->sink = &sc->_sink;
sc->NIL = &sc->_NIL; sc->NIL = &sc->_NIL;
sc->T = &sc->_HASHT; 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->strbuff_size = STRBUFFSIZE;
sc->cell_segments = NULL;
if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) { if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
sc->no_memory=1; sc->no_memory=1;
return 0; return 0;
@ -5726,6 +5761,7 @@ void scheme_set_external_data(scheme *sc, void *p) {
} }
void scheme_deinit(scheme *sc) { void scheme_deinit(scheme *sc) {
struct cell_segment *s;
int i; int i;
sc->oblist=sc->NIL; sc->oblist=sc->NIL;
@ -5758,11 +5794,11 @@ void scheme_deinit(scheme *sc) {
gc(sc,sc->NIL,sc->NIL); gc(sc,sc->NIL,sc->NIL);
#if USE_SMALL_INTEGERS #if USE_SMALL_INTEGERS
sc->free(sc->integer_alloc); _dealloc_cellseg(sc, sc->integer_segment);
#endif #endif
for(i=0; i<=sc->last_cell_seg; i++) { for (s = sc->cell_segments; s; s = _dealloc_cellseg(sc, s)) {
sc->free(sc->alloc_seg[i]); /* nop */
} }
sc->free(sc->strbuff); sc->free(sc->strbuff);
} }