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$ * $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 Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
@ -27,11 +27,31 @@
#include <hawk-xma.h> #include <hawk-xma.h>
#include "hawk-prv.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 MBLKHDRSIZE HAWK_SIZEOF(hawk_xma_mblk_t) #define MINALLOCSIZE (HAWK_SIZEOF(hawk_xma_fblk_t) - HAWK_SIZEOF(hawk_xma_mblk_t))
#define MINALLOCSIZE (ALIGN + ALIGN) /* as large as the free links in hawk_xma_fblk_t */ #define FBLKMINSIZE (MBLKHDRSIZE + MINALLOCSIZE) /* or HAWK_SIZEOF(hawk_xma_fblk_t) - need space for the free links when the block is freeed */
#define MINBLKLEN 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 SYS_TO_USR(b) ((hawk_uint8_t*)(b) + MBLKHDRSIZE)
#define USR_TO_SYS(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 struct hawk_xma_mblk_t
{ {
hawk_oow_t prev_size; 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 free: 1;
hawk_oow_t size: HAWK_XMA_SIZE_BITS;/**< block size */ 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 */ hawk_xma_fblk_t* free_next; /**< link to the next free block */
}; };
/*#define VERIFY*/
#if defined(VERIFY) #if defined(VERIFY)
static void DBG_VERIFY (hawk_xma_t* xma, const char* desc) static void DBG_VERIFY (hawk_xma_t* xma, const char* desc)
{ {
hawk_xma_mblk_t* tmp, * next; hawk_xma_mblk_t* tmp, * next;
hawk_oow_t cnt; 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); 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); 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 #else
#define DBG_VERIFY(xma, desc) #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; 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* hawk_xma_open (hawk_mmgr_t* mmgr, hawk_oow_t xtnsize, void* zoneptr, hawk_oow_t zonesize)
{ {
hawk_xma_t* xma; 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) 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; hawk_oow_t xfi;
int internal = 0; 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); zonesize = HAWK_ALIGN_POW2(zonesize, ALIGN);
/* adjust 'zonesize' to be large enough to hold a single smallest block */ /* 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); zoneptr = HAWK_MMGR_ALLOC(mmgr, zonesize);
if (HAWK_UNLIKELY(!zoneptr)) return -1; 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; 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 */ /* initialize the header part of the free chunk. the entire zone is a single free block */
free->prev_size = 0; first->prev_size = 0;
free->free = 1; first->free = 1;
free->size = zonesize - MBLKHDRSIZE; /* size excluding the block header */ first->size = zonesize - MBLKHDRSIZE; /* size excluding the block header */
free->free_prev = HAWK_NULL; first->free_prev = HAWK_NULL;
free->free_next = HAWK_NULL; first->free_next = HAWK_NULL;
HAWK_MEMSET (xma, 0, HAWK_SIZEOF(*xma)); HAWK_MEMSET (xma, 0, HAWK_SIZEOF(*xma));
xma->_mmgr = mmgr; 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 */ /* at this point, the 'free' chunk is a only block available */
/* get the free block index */ /* get the free block index */
xfi = getxfi(xma, free->size); xfi = getxfi(xma, first->size);
/* locate it into an apporopriate slot */ /* 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 */ /* 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->end = xma->start + zonesize;
xma->internal = internal; xma->internal = 1;
/* initialize some statistical variables */ /* initialize some statistical variables */
#if defined(HAWK_XMA_ENABLE_STAT) #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 /* the previous item does not exist. the block is the first
* item in the free list. */ * item in the free list. */
hawk_oow_t xfi = getxfi(xma, b->size); hawk_oow_t xfi = getxfi(xma, b->size);
HAWK_ASSERT (b == xma->xfree[xfi]); HAWK_ASSERT (b == xma->xfree[xfi]);
/* let's update the free list head */ /* 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); detach_from_freelist (xma, cand);
rem = cand->size - size; rem = cand->size - size;
if (rem >= MINBLKLEN) if (rem >= FBLKMINSIZE)
{ {
hawk_xma_mblk_t* y, * z; 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 * another block. let's split it
*/ */
/* shrink the size of the 'free' block */ /* shrink the size of the 'cand' block */
cand->size = size; 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 */ y = next_mblk(cand); /* get the next adjacent block */
/* initialize some fields */ /* 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) 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; hawk_oow_t xfi;
DBG_VERIFY (xma, "alloc start"); 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]) if (xfi < FIXED && xma->xfree[xfi])
{ {
/* try the best fit */ /* try the best fit */
free = xma->xfree[xfi]; cand = xma->xfree[xfi];
HAWK_ASSERT (free->free != 0); HAWK_ASSERT (cand->free != 0);
HAWK_ASSERT (free->size == size); HAWK_ASSERT (cand->size == size);
detach_from_freelist (xma, free); detach_from_freelist (xma, cand);
free->free = 0; cand->free = 0;
#if defined(HAWK_XMA_ENABLE_STAT) #if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.nfree--; xma->stat.nfree--;
xma->stat.nused++; xma->stat.nused++;
xma->stat.alloc += free->size; xma->stat.alloc += cand->size;
xma->stat.avail -= free->size; xma->stat.avail -= cand->size;
#endif #endif
} }
else if (xfi == XFIMAX(xma)) else if (xfi == XFIMAX(xma))
{ {
/* huge block */ /* huge block */
free = alloc_from_freelist(xma, XFIMAX(xma), size); cand = alloc_from_freelist(xma, XFIMAX(xma), size);
if (!free) return HAWK_NULL; if (!cand) return HAWK_NULL;
} }
else else
{ {
if (xfi >= FIXED) if (xfi >= FIXED)
{ {
/* get the block from its own large chain */ /* get the block from its own large chain */
free = alloc_from_freelist(xma, xfi, size); cand = alloc_from_freelist(xma, xfi, size);
if (!free) if (!cand)
{ {
/* borrow a large block from the huge block chain */ /* 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 else
{ {
/* borrow a small block from the huge block chain */ /* borrow a small block from the huge block chain */
free = alloc_from_freelist(xma, XFIMAX(xma), size); cand = alloc_from_freelist(xma, XFIMAX(xma), size);
if (!free) xfi = FIXED - 1; if (!cand) xfi = FIXED - 1;
} }
if (!free) if (!cand)
{ {
/* try each large block chain left */ /* try each large block chain left */
for (++xfi; xfi < XFIMAX(xma) - 1; xfi++) for (++xfi; xfi < XFIMAX(xma) - 1; xfi++)
{ {
free = alloc_from_freelist(xma, xfi, size); cand = alloc_from_freelist(xma, xfi, size);
if (free) break; if (cand) break;
} }
if (!free) return HAWK_NULL; if (!cand) return HAWK_NULL;
} }
} }
DBG_VERIFY (xma, "alloc end"); 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) 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_xma_mblk_t* n;
hawk_oow_t rem; hawk_oow_t rem;
req = size - blk->size; req = size - blk->size; /* required size additionally */
n = next_mblk(blk); n = next_mblk(blk);
/* check if the next adjacent block is available */ /* check if the next adjacent block is available */
if ((hawk_uint8_t*)n >= xma->end || !n->free || req > n->size) return HAWK_NULL; /* no! */ 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); 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); detach_from_freelist (xma, (hawk_xma_fblk_t*)n);
rem = (MBLKHDRSIZE + n->size) - req; rem = (MBLKHDRSIZE + n->size) - req;
if (rem >= MINBLKLEN) if (rem >= FBLKMINSIZE)
{ {
/* /*
* the remaining part of the next block is large enough * the remaining part of the next block is large enough
* to hold a block. break the next block. * to hold a block. break the next block.
*/ */
hawk_xma_mblk_t* tmp; hawk_xma_mblk_t* y, * z;
blk->size += req; blk->size += req;
tmp = next_mblk(blk); y = next_mblk(blk);
tmp->free = 1; y->free = 1;
tmp->size = rem - MBLKHDRSIZE; y->size = rem - MBLKHDRSIZE;
tmp->prev_size = blk->size; y->prev_size = blk->size;
attach_to_freelist (xma, (hawk_xma_fblk_t*)tmp); attach_to_freelist (xma, (hawk_xma_fblk_t*)y);
n = next_mblk(tmp); z = next_mblk(y);
if ((hawk_uint8_t*)n < xma->end) n->prev_size = tmp->size; if ((hawk_uint8_t*)z < xma->end) z->prev_size = y->size;
#if defined(HAWK_XMA_ENABLE_STAT) #if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.alloc += req; xma->stat.alloc += req;
@ -476,12 +525,14 @@ static void* _realloc_merge (hawk_xma_t* xma, void* b, hawk_oow_t size)
} }
else else
{ {
hawk_xma_mblk_t* z;
/* the remaining part of the next block is too small to form an indepent block. /* 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 */ * utilize the whole block by merging to the resizing block */
blk->size += MBLKHDRSIZE + n->size; blk->size += MBLKHDRSIZE + n->size;
n = next_mblk(blk); z = next_mblk(blk);
if ((hawk_uint8_t*)n < xma->end) n->prev_size = blk->size; if ((hawk_uint8_t*)z < xma->end) z->prev_size = blk->size;
#if defined(HAWK_XMA_ENABLE_STAT) #if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.nfree--; xma->stat.nfree--;
@ -494,58 +545,59 @@ static void* _realloc_merge (hawk_xma_t* xma, void* b, hawk_oow_t size)
{ {
/* shrink the block */ /* shrink the block */
hawk_oow_t rem = blk->size - size; hawk_oow_t rem = blk->size - size;
if (rem >= MINBLKLEN) if (rem >= FBLKMINSIZE)
{ {
hawk_xma_mblk_t* tmp;
hawk_xma_mblk_t* n; hawk_xma_mblk_t* n;
n = next_mblk(blk); n = next_mblk(blk);
/* the leftover is large enough to hold a block of minimum size. /* the leftover is large enough to hold a block of minimum size.split the current block */
* split the current block. let 'tmp' point to the leftover. */
if ((hawk_uint8_t*)n < xma->end && n->free) 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); detach_from_freelist (xma, (hawk_xma_fblk_t*)n);
blk->size = size; blk->size = size;
tmp = next_mblk(blk); y = next_mblk(blk); /* update y to the leftover block with the new block size set above */
tmp->free = 1; y->free = 1;
tmp->size = rem + n->size; y->size = rem + n->size; /* add up the adjust block - (rem + MBLKHDRSIZE(n) + n->size) - MBLKHDRSIZE(y) */
tmp->prev_size = blk->size; y->prev_size = blk->size;
/* add 'tmp' to the free list */ /* add 'y' to the free list */
attach_to_freelist (xma, (hawk_xma_fblk_t*)tmp); 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); /* 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) #if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.alloc -= rem; xma->stat.alloc -= rem;
/* rem - MBLKHDRSIZE(tmp) + MBLKHDRSIZE(n) */ xma->stat.avail += rem; /* rem - MBLKHDRSIZE(y) + MBLKHDRSIZE(n) */
xma->stat.avail += rem;
#endif #endif
} }
else else
{ {
hawk_xma_mblk_t* y;
/* link the leftover block to the free list */ /* link the leftover block to the free list */
blk->size = size; blk->size = size;
tmp = next_mblk(blk); y = next_mblk(blk); /* update y to the leftover block with the new block size set above */
tmp->free = 1; y->free = 1;
tmp->size = rem - MBLKHDRSIZE; y->size = rem - MBLKHDRSIZE;
tmp->prev_size = blk->size; y->prev_size = blk->size;
attach_to_freelist (xma, (hawk_xma_fblk_t*)tmp); attach_to_freelist (xma, (hawk_xma_fblk_t*)y);
/*n = next_mblk(tmp); /*n = next_mblk(y);
if ((hawk_uint8_t*)n < xma->end)*/ n->prev_size = tmp->size; if ((hawk_uint8_t*)n < xma->end)*/ n->prev_size = y->size;
#if defined(HAWK_XMA_ENABLE_STAT) #if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.nfree++; xma->stat.nfree++;
xma->stat.alloc -= rem; xma->stat.alloc -= rem;
xma->stat.avail += tmp->size; xma->stat.avail += y->size;
#endif #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 ns = MBLKHDRSIZE + blk->size + MBLKHDRSIZE;
hawk_oow_t bs = ns + y->size; 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) #if defined(HAWK_XMA_ENABLE_STAT)
xma->stat.avail += MBLKHDRSIZE + blk->size; xma->stat.avail += MBLKHDRSIZE + blk->size;
//xma->stat.avail = 0;
#endif #endif
detach_from_freelist (xma, (hawk_xma_fblk_t*)x); detach_from_freelist (xma, (hawk_xma_fblk_t*)x);
x->size += MBLKHDRSIZE + blk->size; 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; if ((hawk_uint8_t*)y < xma->end) y->prev_size = x->size;
attach_to_freelist (xma, (hawk_xma_fblk_t*)x); attach_to_freelist (xma, (hawk_xma_fblk_t*)x);
} }
else else
{ {