diff --git a/hawk/lib/xma.c b/hawk/lib/xma.c index 7845cfbe..5bd8279e 100644 --- a/hawk/lib/xma.c +++ b/hawk/lib/xma.c @@ -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 #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 : 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 {