fixed more bugs in xma

This commit is contained in:
hyung-hwan 2020-11-03 06:08:34 +00:00
parent 26e0570a53
commit 42637318b7

View File

@ -1,7 +1,7 @@
/*
* $Id$
*
Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
Copyright (c) 2014-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@ -27,11 +27,31 @@
#include <hawk-xma.h>
#include "hawk-prv.h"
/* set ALIGN to twice the pointer size to prevent unaligned memory access by
* instructions dealing with data larger than the system word size. e.g. movaps on x86_64
*
* in the following run, movaps tries to write to the address 0x7fffea722f78.
* since the instruction deals with 16-byte aligned data only, it triggered
* the general protection error.
*
$ gdb ~/xxx/bin/hawk
Program received signal SIGSEGV, Segmentation fault.
0x000000000042156a in set_global (rtx=rtx@entry=0x7fffea718ff8, idx=idx@entry=2,
var=var@entry=0x0, val=val@entry=0x1, assign=assign@entry=0) at ../../../lib/run.c:358
358 rtx->gbl.fnr = lv;
(gdb) print &rtx->gbl.fnr
$1 = (hawk_int_t *) 0x7fffea722f78
(gdb) disp /i 0x42156a
1: x/i 0x42156a
=> 0x42156a <set_global+874>: movaps %xmm2,0x9f80(%rbp)
*/
#define ALIGN (HAWK_SIZEOF_VOID_P * 2) /* this must be a power of 2 */
#define ALIGN HAWK_SIZEOF(hawk_oow_t) /* this must be a power of 2 */
#define MBLKHDRSIZE HAWK_SIZEOF(hawk_xma_mblk_t)
#define MINALLOCSIZE (ALIGN + ALIGN) /* as large as the free links in hawk_xma_fblk_t */
#define MINBLKLEN HAWK_SIZEOF(hawk_xma_fblk_t) /* need space for the free links when the block is freeed */
#define MBLKHDRSIZE (HAWK_SIZEOF(hawk_xma_mblk_t))
#define MINALLOCSIZE (HAWK_SIZEOF(hawk_xma_fblk_t) - HAWK_SIZEOF(hawk_xma_mblk_t))
#define FBLKMINSIZE (MBLKHDRSIZE + MINALLOCSIZE) /* or HAWK_SIZEOF(hawk_xma_fblk_t) - need space for the free links when the block is freeed */
/* NOTE: you must ensure that FBLKMINSIZE is equal to ALIGN or multiples of ALIGN */
#define SYS_TO_USR(b) ((hawk_uint8_t*)(b) + MBLKHDRSIZE)
#define USR_TO_SYS(b) ((hawk_uint8_t*)(b) - MBLKHDRSIZE)
@ -52,6 +72,14 @@
struct hawk_xma_mblk_t
{
hawk_oow_t prev_size;
/* the block size is shifted by 1 bit and the maximum value is
* offset by 1 bit because of the 'free' bit-field.
* i could keep 'size' without shifting with bit manipulation
* because the actual size is aligned and the last bit will
* never be 1. i don't think there is a practical use case where
* you need to allocate a huge chunk covering the entire
* address space of your machine. */
hawk_oow_t free: 1;
hawk_oow_t size: HAWK_XMA_SIZE_BITS;/**< block size */
};
@ -67,12 +95,18 @@ struct hawk_xma_fblk_t
hawk_xma_fblk_t* free_next; /**< link to the next free block */
};
/*#define VERIFY*/
#if defined(VERIFY)
static void DBG_VERIFY (hawk_xma_t* xma, const char* desc)
{
hawk_xma_mblk_t* tmp, * next;
hawk_oow_t cnt;
for (tmp = (hawk_xma_mblk_t*)xma->start, cnt = 0; (hawk_uint8_t*)tmp < xma->end; tmp = next, cnt++)
hawk_oow_t fsum, asum;
#if defined(HAWK_XMA_ENABLE_STAT)
hawk_oow_t isum;
#endif
for (tmp = (hawk_xma_mblk_t*)xma->start, cnt = 0, fsum = 0, asum = 0; (hawk_uint8_t*)tmp < xma->end; tmp = next, cnt++)
{
next = next_mblk(tmp);
@ -84,7 +118,18 @@ static void DBG_VERIFY (hawk_xma_t* xma, const char* desc)
{
HAWK_ASSERT (next->prev_size == tmp->size);
}
if (tmp->free) fsum += tmp->size;
else asum += tmp->size;
}
#if defined(HAWK_XMA_ENABLE_STAT)
isum = (xma->stat.nfree + xma->stat.nused) * MBLKHDRSIZE;
HAWK_ASSERT (asum == xma->stat.alloc);
HAWK_ASSERT (fsum == xma->stat.avail);
HAWK_ASSERT (isum == xma->stat.total - (xma->stat.alloc + xma->stat.avail));
HAWK_ASSERT (asum + fsum + isum == xma->stat.total);
#endif
}
#else
#define DBG_VERIFY(xma, desc)
@ -144,6 +189,7 @@ static HAWK_INLINE hawk_oow_t getxfi (hawk_xma_t* xma, hawk_oow_t size)
return xfi;
}
hawk_xma_t* hawk_xma_open (hawk_mmgr_t* mmgr, hawk_oow_t xtnsize, void* zoneptr, hawk_oow_t zonesize)
{
hawk_xma_t* xma;
@ -169,7 +215,7 @@ void hawk_xma_close (hawk_xma_t* xma)
int hawk_xma_init (hawk_xma_t* xma, hawk_mmgr_t* mmgr, void* zoneptr, hawk_oow_t zonesize)
{
hawk_xma_fblk_t* free;
hawk_xma_fblk_t* first;
hawk_oow_t xfi;
int internal = 0;
@ -179,7 +225,7 @@ int hawk_xma_init (hawk_xma_t* xma, hawk_mmgr_t* mmgr, void* zoneptr, hawk_oow_t
zonesize = HAWK_ALIGN_POW2(zonesize, ALIGN);
/* adjust 'zonesize' to be large enough to hold a single smallest block */
if (zonesize < MINBLKLEN) zonesize = MINBLKLEN;
if (zonesize < FBLKMINSIZE) zonesize = FBLKMINSIZE;
zoneptr = HAWK_MMGR_ALLOC(mmgr, zonesize);
if (HAWK_UNLIKELY(!zoneptr)) return -1;
@ -187,14 +233,14 @@ int hawk_xma_init (hawk_xma_t* xma, hawk_mmgr_t* mmgr, void* zoneptr, hawk_oow_t
internal = 1;
}
free = (hawk_xma_fblk_t*)zoneptr;
first = (hawk_xma_fblk_t*)zoneptr;
/* initialize the header part of the free chunk. the entire zone is a single free block */
free->prev_size = 0;
free->free = 1;
free->size = zonesize - MBLKHDRSIZE; /* size excluding the block header */
free->free_prev = HAWK_NULL;
free->free_next = HAWK_NULL;
first->prev_size = 0;
first->free = 1;
first->size = zonesize - MBLKHDRSIZE; /* size excluding the block header */
first->free_prev = HAWK_NULL;
first->free_next = HAWK_NULL;
HAWK_MEMSET (xma, 0, HAWK_SIZEOF(*xma));
xma->_mmgr = mmgr;
@ -203,13 +249,13 @@ int hawk_xma_init (hawk_xma_t* xma, hawk_mmgr_t* mmgr, void* zoneptr, hawk_oow_t
/* at this point, the 'free' chunk is a only block available */
/* get the free block index */
xfi = getxfi(xma, free->size);
xfi = getxfi(xma, first->size);
/* locate it into an apporopriate slot */
xma->xfree[xfi] = free;
xma->xfree[xfi] = first;
/* let it be the head, which is natural with only a block */
xma->start = (hawk_uint8_t*)free;
xma->start = (hawk_uint8_t*)first;
xma->end = xma->start + zonesize;
xma->internal = internal;
xma->internal = 1;
/* initialize some statistical variables */
#if defined(HAWK_XMA_ENABLE_STAT)
@ -267,6 +313,7 @@ static HAWK_INLINE void detach_from_freelist (hawk_xma_t* xma, hawk_xma_fblk_t*
{
/* the previous item does not exist. the block is the first
* item in the free list. */
hawk_oow_t xfi = getxfi(xma, b->size);
HAWK_ASSERT (b == xma->xfree[xfi]);
/* let's update the free list head */
@ -291,7 +338,7 @@ static hawk_xma_fblk_t* alloc_from_freelist (hawk_xma_t* xma, hawk_oow_t xfi, ha
detach_from_freelist (xma, cand);
rem = cand->size - size;
if (rem >= MINBLKLEN)
if (rem >= FBLKMINSIZE)
{
hawk_xma_mblk_t* y, * z;
@ -299,10 +346,10 @@ static hawk_xma_fblk_t* alloc_from_freelist (hawk_xma_t* xma, hawk_oow_t xfi, ha
* another block. let's split it
*/
/* shrink the size of the 'free' block */
/* shrink the size of the 'cand' block */
cand->size = size;
/* let 'y' point to the remaining part */
/* let 'tmp' point to the remaining part */
y = next_mblk(cand); /* get the next adjacent block */
/* initialize some fields */
@ -350,7 +397,7 @@ static hawk_xma_fblk_t* alloc_from_freelist (hawk_xma_t* xma, hawk_oow_t xfi, ha
void* hawk_xma_alloc (hawk_xma_t* xma, hawk_oow_t size)
{
hawk_xma_fblk_t* free;
hawk_xma_fblk_t* cand;
hawk_oow_t xfi;
DBG_VERIFY (xma, "alloc start");
@ -366,60 +413,60 @@ void* hawk_xma_alloc (hawk_xma_t* xma, hawk_oow_t size)
if (xfi < FIXED && xma->xfree[xfi])
{
/* try the best fit */
free = xma->xfree[xfi];
cand = xma->xfree[xfi];
HAWK_ASSERT (free->free != 0);
HAWK_ASSERT (free->size == size);
HAWK_ASSERT (cand->free != 0);
HAWK_ASSERT (cand->size == size);
detach_from_freelist (xma, free);
free->free = 0;
detach_from_freelist (xma, cand);
cand->free = 0;
#if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.nfree--;
xma->stat.nused++;
xma->stat.alloc += free->size;
xma->stat.avail -= free->size;
xma->stat.alloc += cand->size;
xma->stat.avail -= cand->size;
#endif
}
else if (xfi == XFIMAX(xma))
{
/* huge block */
free = alloc_from_freelist(xma, XFIMAX(xma), size);
if (!free) return HAWK_NULL;
cand = alloc_from_freelist(xma, XFIMAX(xma), size);
if (!cand) return HAWK_NULL;
}
else
{
if (xfi >= FIXED)
{
/* get the block from its own large chain */
free = alloc_from_freelist(xma, xfi, size);
if (!free)
cand = alloc_from_freelist(xma, xfi, size);
if (!cand)
{
/* borrow a large block from the huge block chain */
free = alloc_from_freelist(xma, XFIMAX(xma), size);
cand = alloc_from_freelist(xma, XFIMAX(xma), size);
}
}
else
{
/* borrow a small block from the huge block chain */
free = alloc_from_freelist(xma, XFIMAX(xma), size);
if (!free) xfi = FIXED - 1;
cand = alloc_from_freelist(xma, XFIMAX(xma), size);
if (!cand) xfi = FIXED - 1;
}
if (!free)
if (!cand)
{
/* try each large block chain left */
for (++xfi; xfi < XFIMAX(xma) - 1; xfi++)
{
free = alloc_from_freelist(xma, xfi, size);
if (free) break;
cand = alloc_from_freelist(xma, xfi, size);
if (cand) break;
}
if (!free) return HAWK_NULL;
if (!cand) return HAWK_NULL;
}
}
DBG_VERIFY (xma, "alloc end");
return SYS_TO_USR(free);
return SYS_TO_USR(cand);
}
static void* _realloc_merge (hawk_xma_t* xma, void* b, hawk_oow_t size)
@ -438,11 +485,13 @@ static void* _realloc_merge (hawk_xma_t* xma, void* b, hawk_oow_t size)
hawk_xma_mblk_t* n;
hawk_oow_t rem;
req = size - blk->size;
req = size - blk->size; /* required size additionally */
n = next_mblk(blk);
/* check if the next adjacent block is available */
if ((hawk_uint8_t*)n >= xma->end || !n->free || req > n->size) return HAWK_NULL; /* no! */
/* TODO: check more blocks if the next block is free but small in size.
* check the previous adjacent blocks also */
HAWK_ASSERT (blk->size == n->prev_size);
@ -450,24 +499,24 @@ static void* _realloc_merge (hawk_xma_t* xma, void* b, hawk_oow_t size)
detach_from_freelist (xma, (hawk_xma_fblk_t*)n);
rem = (MBLKHDRSIZE + n->size) - req;
if (rem >= MINBLKLEN)
if (rem >= FBLKMINSIZE)
{
/*
* the remaining part of the next block is large enough
* to hold a block. break the next block.
*/
hawk_xma_mblk_t* tmp;
hawk_xma_mblk_t* y, * z;
blk->size += req;
tmp = next_mblk(blk);
tmp->free = 1;
tmp->size = rem - MBLKHDRSIZE;
tmp->prev_size = blk->size;
attach_to_freelist (xma, (hawk_xma_fblk_t*)tmp);
y = next_mblk(blk);
y->free = 1;
y->size = rem - MBLKHDRSIZE;
y->prev_size = blk->size;
attach_to_freelist (xma, (hawk_xma_fblk_t*)y);
n = next_mblk(tmp);
if ((hawk_uint8_t*)n < xma->end) n->prev_size = tmp->size;
z = next_mblk(y);
if ((hawk_uint8_t*)z < xma->end) z->prev_size = y->size;
#if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.alloc += req;
@ -476,12 +525,14 @@ static void* _realloc_merge (hawk_xma_t* xma, void* b, hawk_oow_t size)
}
else
{
hawk_xma_mblk_t* z;
/* the remaining part of the next block is too small to form an indepent block.
* utilize the whole block by merging to the resizing block */
blk->size += MBLKHDRSIZE + n->size;
n = next_mblk(blk);
if ((hawk_uint8_t*)n < xma->end) n->prev_size = blk->size;
z = next_mblk(blk);
if ((hawk_uint8_t*)z < xma->end) z->prev_size = blk->size;
#if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.nfree--;
@ -494,58 +545,59 @@ static void* _realloc_merge (hawk_xma_t* xma, void* b, hawk_oow_t size)
{
/* shrink the block */
hawk_oow_t rem = blk->size - size;
if (rem >= MINBLKLEN)
if (rem >= FBLKMINSIZE)
{
hawk_xma_mblk_t* tmp;
hawk_xma_mblk_t* n;
n = next_mblk(blk);
/* the leftover is large enough to hold a block of minimum size.
* split the current block. let 'tmp' point to the leftover. */
/* the leftover is large enough to hold a block of minimum size.split the current block */
if ((hawk_uint8_t*)n < xma->end && n->free)
{
/* let the leftover block merge with the next block */
hawk_xma_mblk_t* y, * z;
/* make the leftover block merge with the next block */
detach_from_freelist (xma, (hawk_xma_fblk_t*)n);
blk->size = size;
tmp = next_mblk(blk);
tmp->free = 1;
tmp->size = rem + n->size;
tmp->prev_size = blk->size;
y = next_mblk(blk); /* update y to the leftover block with the new block size set above */
y->free = 1;
y->size = rem + n->size; /* add up the adjust block - (rem + MBLKHDRSIZE(n) + n->size) - MBLKHDRSIZE(y) */
y->prev_size = blk->size;
/* add 'tmp' to the free list */
attach_to_freelist (xma, (hawk_xma_fblk_t*)tmp);
n = next_mblk(tmp);
if ((hawk_uint8_t*)n < xma->end) n->prev_size = tmp->size;
/* add 'y' to the free list */
attach_to_freelist (xma, (hawk_xma_fblk_t*)y);
z = next_mblk(y); /* get adjacent block to the merged block */
if ((hawk_uint8_t*)z < xma->end) z->prev_size = y->size;
#if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.alloc -= rem;
/* rem - MBLKHDRSIZE(tmp) + MBLKHDRSIZE(n) */
xma->stat.avail += rem;
xma->stat.avail += rem; /* rem - MBLKHDRSIZE(y) + MBLKHDRSIZE(n) */
#endif
}
else
{
hawk_xma_mblk_t* y;
/* link the leftover block to the free list */
blk->size = size;
tmp = next_mblk(blk);
tmp->free = 1;
tmp->size = rem - MBLKHDRSIZE;
tmp->prev_size = blk->size;
y = next_mblk(blk); /* update y to the leftover block with the new block size set above */
y->free = 1;
y->size = rem - MBLKHDRSIZE;
y->prev_size = blk->size;
attach_to_freelist (xma, (hawk_xma_fblk_t*)tmp);
/*n = next_mblk(tmp);
if ((hawk_uint8_t*)n < xma->end)*/ n->prev_size = tmp->size;
attach_to_freelist (xma, (hawk_xma_fblk_t*)y);
/*n = next_mblk(y);
if ((hawk_uint8_t*)n < xma->end)*/ n->prev_size = y->size;
#if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.nfree++;
xma->stat.alloc -= rem;
xma->stat.avail += tmp->size;
xma->stat.avail += y->size;
#endif
}
}
@ -625,7 +677,7 @@ void hawk_xma_free (hawk_xma_t* xma, void* b)
*
*/
hawk_xma_mblk_t* z;
hawk_xma_mblk_t* z = next_mblk(y);
hawk_oow_t ns = MBLKHDRSIZE + blk->size + MBLKHDRSIZE;
hawk_oow_t bs = ns + y->size;
@ -704,17 +756,16 @@ void hawk_xma_free (hawk_xma_t* xma, void* b)
*/
#if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.avail += MBLKHDRSIZE + blk->size;
//xma->stat.avail = 0;
#endif
detach_from_freelist (xma, (hawk_xma_fblk_t*)x);
x->size += MBLKHDRSIZE + blk->size;
//HAWK_ASSERT (y == next_mblk(x));
HAWK_ASSERT (y == next_mblk(x));
if ((hawk_uint8_t*)y < xma->end) y->prev_size = x->size;
attach_to_freelist (xma, (hawk_xma_fblk_t*)x);
}
else
{