Commit bd294f1d authored by Rusty Russell's avatar Rusty Russell

alloc: remove encode limit arg, and implement free array cache.

parent 7f9d9565
...@@ -13,7 +13,7 @@ int main(void) ...@@ -13,7 +13,7 @@ int main(void)
unsigned char array[ARR_SIZE]; unsigned char array[ARR_SIZE];
unsigned int i, prev; unsigned int i, prev;
plan_tests(567); plan_tests(405);
prev = 0; prev = 0;
/* Test encode_length */ /* Test encode_length */
...@@ -27,11 +27,11 @@ int main(void) ...@@ -27,11 +27,11 @@ int main(void)
/* Test it against actual encoding return val. */ /* Test it against actual encoding return val. */
for (i = 1; i < 0x8000000; i *= 2) { for (i = 1; i < 0x8000000; i *= 2) {
ok1(encode_length(i-1) == encode(i - 1 + MIN_BLOCK_SIZE, ok1(encode_length(i-1) == encode(i - 1 + MIN_BLOCK_SIZE,
false, array, ARR_SIZE)); false, array));
ok1(encode_length(i) == encode(i + MIN_BLOCK_SIZE, ok1(encode_length(i) == encode(i + MIN_BLOCK_SIZE,
false, array, ARR_SIZE)); false, array));
ok1(encode_length(i+1) == encode(i + 1 + MIN_BLOCK_SIZE, ok1(encode_length(i+1) == encode(i + 1 + MIN_BLOCK_SIZE,
false, array, ARR_SIZE)); false, array));
} }
/* Test encoder vs. decoder. */ /* Test encoder vs. decoder. */
...@@ -39,50 +39,21 @@ int main(void) ...@@ -39,50 +39,21 @@ int main(void)
unsigned long hdrlen, len; unsigned long hdrlen, len;
bool free; bool free;
hdrlen = encode(i - 1 + MIN_BLOCK_SIZE, false, array, ARR_SIZE); hdrlen = encode(i - 1 + MIN_BLOCK_SIZE, false, array);
ok1(decode(&len, &free, array) == hdrlen); ok1(decode(&len, &free, array) == hdrlen);
ok1(len == i - 1 + MIN_BLOCK_SIZE); ok1(len == i - 1 + MIN_BLOCK_SIZE);
ok1(free == false); ok1(free == false);
hdrlen = encode(i + MIN_BLOCK_SIZE, true, array, ARR_SIZE); hdrlen = encode(i + MIN_BLOCK_SIZE, true, array);
ok1(decode(&len, &free, array) == hdrlen); ok1(decode(&len, &free, array) == hdrlen);
ok1(len == i + MIN_BLOCK_SIZE); ok1(len == i + MIN_BLOCK_SIZE);
ok1(free == true); ok1(free == true);
hdrlen = encode(i + 1 + MIN_BLOCK_SIZE, true, array, ARR_SIZE); hdrlen = encode(i + 1 + MIN_BLOCK_SIZE, true, array);
ok1(decode(&len, &free, array) == hdrlen); ok1(decode(&len, &free, array) == hdrlen);
ok1(len == i + 1 + MIN_BLOCK_SIZE); ok1(len == i + 1 + MIN_BLOCK_SIZE);
ok1(free == true); ok1(free == true);
} }
/* Test encoder limit enforcement. */
for (i = 1; i < 0x8000000; i *= 2) {
unsigned char *arr;
unsigned int len;
/* These should fit. */
ok1(encode(i-1 + MIN_BLOCK_SIZE, false, array,
encode_length(i-1)) == encode_length(i-1));
ok1(encode(i + MIN_BLOCK_SIZE, false, array,
encode_length(i)) == encode_length(i));
ok1(encode(i+1 + MIN_BLOCK_SIZE, false, array,
encode_length(i+1)) == encode_length(i+1));
/* These should not: malloc so valgrind finds overruns. */
len = encode_length(i-1) - 1;
arr = malloc(len);
ok1(encode(i-1 + MIN_BLOCK_SIZE, true, arr, len) == 0);
free(arr);
len = encode_length(i-1) - 1;
arr = malloc(len);
ok1(encode(i + MIN_BLOCK_SIZE, false, arr, len) == 0);
free(arr);
len = encode_length(i+1) - 1;
arr = malloc(len);
ok1(encode(i+1 + MIN_BLOCK_SIZE, false, arr, len) == 0);
free(arr);
}
return exit_status(); return exit_status();
} }
...@@ -38,9 +38,8 @@ static unsigned encode_len_with_header(unsigned long len) ...@@ -38,9 +38,8 @@ static unsigned encode_len_with_header(unsigned long len)
} }
/* Encoding can be read from front or back; 0 is invalid at either /* Encoding can be read from front or back; 0 is invalid at either
* start or end. Returns bytes used for header, or 0 if won't fit. */ * start or end. Returns bytes used for header. */
static unsigned encode(unsigned long len, bool free, unsigned char arr[], static unsigned encode(unsigned long len, bool free, unsigned char arr[])
size_t limit)
{ {
unsigned int hdrlen = 1; unsigned int hdrlen = 1;
...@@ -48,9 +47,6 @@ static unsigned encode(unsigned long len, bool free, unsigned char arr[], ...@@ -48,9 +47,6 @@ static unsigned encode(unsigned long len, bool free, unsigned char arr[],
assert(len >= MIN_BLOCK_SIZE); assert(len >= MIN_BLOCK_SIZE);
len -= MIN_BLOCK_SIZE; len -= MIN_BLOCK_SIZE;
if (encode_length(len) > limit)
return 0;
/* First byte always contains free bit. */ /* First byte always contains free bit. */
arr[0] = TERM_BIT | (free ? FREE_BIT : 0); arr[0] = TERM_BIT | (free ? FREE_BIT : 0);
/* Also holds 5 bits of data (0 - 31) */ /* Also holds 5 bits of data (0 - 31) */
...@@ -115,8 +111,7 @@ void tiny_alloc_init(void *pool, unsigned long poolsize) ...@@ -115,8 +111,7 @@ void tiny_alloc_init(void *pool, unsigned long poolsize)
return; return;
memset(pool, 0, arrsize); memset(pool, 0, arrsize);
encode(poolsize - arrsize, true, encode(poolsize - arrsize, true, (unsigned char *)pool + arrsize);
(unsigned char *)pool + arrsize, poolsize - arrsize);
} }
/* Walk through and try to coalesce */ /* Walk through and try to coalesce */
...@@ -129,8 +124,7 @@ static bool try_coalesce(unsigned char *pool, unsigned long poolsize) ...@@ -129,8 +124,7 @@ static bool try_coalesce(unsigned char *pool, unsigned long poolsize)
do { do {
hdrlen = decode(&len, &free, pool + off); hdrlen = decode(&len, &free, pool + off);
if (free && prev_free) { if (free && prev_free) {
encode(prev_len + len, true, pool + prev_off, encode(prev_len + len, true, pool + prev_off);
poolsize - prev_off);
coalesced = true; coalesced = true;
} }
prev_free = free; prev_free = free;
...@@ -139,6 +133,10 @@ static bool try_coalesce(unsigned char *pool, unsigned long poolsize) ...@@ -139,6 +133,10 @@ static bool try_coalesce(unsigned char *pool, unsigned long poolsize)
off += len; off += len;
} while (off < poolsize); } while (off < poolsize);
/* FIXME: Refill free_array here. */
if (coalesced)
memset(pool, 0, free_array_size(poolsize));
return coalesced; return coalesced;
} }
...@@ -152,11 +150,23 @@ static bool long_enough(unsigned long offset, unsigned long len, ...@@ -152,11 +150,23 @@ static bool long_enough(unsigned long offset, unsigned long len,
return offset + size <= end; return offset + size <= end;
} }
static unsigned long find_free_end(unsigned char *arr, unsigned long arrsize)
{
unsigned long end;
for (end = 0; end < arrsize; end++) {
if (!arr[end])
break;
}
return end;
}
void *tiny_alloc_get(void *pool, unsigned long poolsize, void *tiny_alloc_get(void *pool, unsigned long poolsize,
unsigned long size, unsigned long align) unsigned long size, unsigned long align)
{ {
unsigned long arrsize = free_array_size(poolsize); unsigned long arrsize = free_array_size(poolsize);
unsigned long len, off, actual, hdr, hdrlen; unsigned long len, off, fa_off, fa_hdrlen, actual, hdr, hdrlen, freelen;
unsigned char *arr = pool;
bool free; bool free;
/* We can't do anything with tiny pools. */ /* We can't do anything with tiny pools. */
...@@ -167,12 +177,25 @@ void *tiny_alloc_get(void *pool, unsigned long poolsize, ...@@ -167,12 +177,25 @@ void *tiny_alloc_get(void *pool, unsigned long poolsize,
if (!size) if (!size)
size = 1; size = 1;
/* FIXME: Look through free array. */ /* Look for entries in free array. */
freelen = find_free_end(pool, arrsize);
for (fa_off = 0; fa_off < freelen; fa_off += fa_hdrlen) {
fa_hdrlen = decode(&off, &free, arr + fa_off);
off -= MIN_BLOCK_SIZE;
hdrlen = decode(&len, &free, arr + off);
if (long_enough(off, len, size, align)) {
/* Move every successive entry down. */
memmove(arr + fa_off, arr + fa_off + fa_hdrlen,
freelen - fa_hdrlen);
memset(arr + freelen - fa_hdrlen, 0, fa_hdrlen);
goto found;
}
}
again: again:
off = arrsize; off = arrsize;
hdrlen = decode(&len, &free, (unsigned char *)pool + off); hdrlen = decode(&len, &free, arr + off);
while (!free || !long_enough(off, len, size, align)) { while (!free || !long_enough(off, len, size, align)) {
/* FIXME: Refill free array if this block is free. */ /* FIXME: Refill free array if this block is free. */
...@@ -183,28 +206,29 @@ again: ...@@ -183,28 +206,29 @@ again:
goto again; goto again;
return NULL; return NULL;
} }
hdrlen = decode(&len, &free, (unsigned char *)pool + off); hdrlen = decode(&len, &free, arr + off);
} }
found:
/* We have a free block. Since we walk from front, take far end. */ /* We have a free block. Since we walk from front, take far end. */
actual = ((off + len - size) & ~(align - 1)); actual = ((off + len - size) & ~(align - 1));
hdr = actual - encode_len_with_header(off + len - actual); hdr = actual - encode_len_with_header(off + len - actual);
/* Do we have enough room to split? */ /* Do we have enough room to split? */
if (hdr - off >= MIN_BLOCK_SIZE) { if (hdr - off >= MIN_BLOCK_SIZE) {
encode(hdr - off, true, (unsigned char *)pool + off, poolsize); encode(hdr - off, true, arr + off);
} else { } else {
hdr = off; hdr = off;
} }
/* Make sure that we are all-zero up to actual, so we can walk back /* Make sure that we are all-zero up to actual, so we can walk back
* and find header. */ * and find header. */
memset((unsigned char *)pool + hdr, 0, actual - hdr); memset(arr + hdr, 0, actual - hdr);
/* Create header for allocated block. */ /* Create header for allocated block. */
encode(off + len - hdr, false, (unsigned char *)pool + hdr, poolsize); encode(off + len - hdr, false, arr + hdr);
return (unsigned char *)pool + actual; return arr + actual;
} }
static unsigned char *to_hdr(void *p) static unsigned char *to_hdr(void *p)
...@@ -224,6 +248,8 @@ static unsigned char *to_hdr(void *p) ...@@ -224,6 +248,8 @@ static unsigned char *to_hdr(void *p)
void tiny_alloc_free(void *pool, unsigned long poolsize, void *freep) void tiny_alloc_free(void *pool, unsigned long poolsize, void *freep)
{ {
unsigned long len, end, arrsize = free_array_size(poolsize);
unsigned char *arr = pool;
unsigned char *hdr; unsigned char *hdr;
/* Too small to do anything. */ /* Too small to do anything. */
...@@ -231,9 +257,14 @@ void tiny_alloc_free(void *pool, unsigned long poolsize, void *freep) ...@@ -231,9 +257,14 @@ void tiny_alloc_free(void *pool, unsigned long poolsize, void *freep)
return; return;
hdr = to_hdr(freep); hdr = to_hdr(freep);
/* FIXME: Put in free array. */
hdr[0] |= FREE_BIT; hdr[0] |= FREE_BIT;
end = find_free_end(pool, arrsize);
/* If we can fit this block, encode it. */
len = encode_length(hdr - arr);
if (end + len <= arrsize)
encode(hdr - arr + MIN_BLOCK_SIZE, true, arr + end);
} }
unsigned long tiny_alloc_size(void *pool, unsigned long poolsize, void *p) unsigned long tiny_alloc_size(void *pool, unsigned long poolsize, void *p)
...@@ -252,41 +283,77 @@ static bool tiny_check_fail(void) ...@@ -252,41 +283,77 @@ static bool tiny_check_fail(void)
return false; return false;
} }
static bool check_decode(const unsigned char *arr, unsigned long len)
{
unsigned int i;
if (len == 0)
return tiny_check_fail();
if (!(arr[0] & TERM_BIT))
return tiny_check_fail();
if (arr[0] & SINGLE_BYTE)
return true;
for (i = 1; i < len; i++) {
if (arr[i] & TERM_BIT)
return true;
}
return tiny_check_fail();
}
bool tiny_alloc_check(void *pool, unsigned long poolsize) bool tiny_alloc_check(void *pool, unsigned long poolsize)
{ {
unsigned long arrsize = free_array_size(poolsize); unsigned long arrsize = free_array_size(poolsize);
unsigned char *arr = pool; unsigned char *arr = pool;
unsigned long len, off, hdrlen; unsigned long len, off, off2, hdrlen, end;
unsigned long i, freearr[arrsize], num_freearr = 0;
bool free; bool free;
if (poolsize < MIN_BLOCK_SIZE) if (poolsize < MIN_BLOCK_SIZE)
return true; return true;
/* For the moment, free array is all zeroes. */ end = find_free_end(pool, arrsize);
for (off = 0; off < arrsize; off++) { for (off = 0; off < end; off += hdrlen) {
if (!check_decode(arr + off, end - off))
return false;
hdrlen = decode(&off2, &free, arr + off);
off2 -= MIN_BLOCK_SIZE;
if (off2 >= poolsize)
return tiny_check_fail();
if (!free)
return tiny_check_fail();
freearr[num_freearr++] = off2;
}
/* Rest of free array should be all zeroes. */
for (off = end; off < arrsize; off++) {
if (arr[off] != 0) if (arr[off] != 0)
return tiny_check_fail(); return tiny_check_fail();
} }
for (off = arrsize; off < poolsize; off += len) { for (off = arrsize; off < poolsize; off += len) {
/* We should have a valid header. */ /* We should have a valid header. */
if (!(arr[off] & TERM_BIT)) if (!check_decode(arr + off, poolsize - off))
return tiny_check_fail(); return false;
if (!(arr[off] & SINGLE_BYTE)) {
unsigned long off2;
for (off2 = off+1; off2 < poolsize; off2++) {
if (arr[off2] & TERM_BIT)
break;
}
if (off2 == poolsize)
return tiny_check_fail();
}
hdrlen = decode(&len, &free, arr + off); hdrlen = decode(&len, &free, arr + off);
if (off + len > poolsize) if (off + len > poolsize)
return tiny_check_fail(); return tiny_check_fail();
if (hdrlen != encode_length(len - MIN_BLOCK_SIZE)) if (hdrlen != encode_length(len - MIN_BLOCK_SIZE))
return tiny_check_fail(); return tiny_check_fail();
for (i = 0; i < num_freearr; i++) {
if (freearr[i] == off) {
if (!free)
return tiny_check_fail();
memmove(&freearr[i], &freearr[i+1],
(num_freearr-- - (i + 1))
* sizeof(freearr[i]));
break;
}
}
} }
/* Now we should have found everything in freearr. */
if (num_freearr)
return tiny_check_fail();
return true; return true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment