diff options
Diffstat (limited to 'src/custommem.c')
| -rw-r--r-- | src/custommem.c | 161 |
1 files changed, 125 insertions, 36 deletions
diff --git a/src/custommem.c b/src/custommem.c index f77b005c..d2b752c0 100644 --- a/src/custommem.c +++ b/src/custommem.c @@ -42,12 +42,17 @@ static uintptr_t box64_jmptbldefault0[1<<JMPTABL_SHIFT0]; // lock addresses KHASH_SET_INIT_INT64(lockaddress) static kh_lockaddress_t *lockaddress = NULL; +#ifdef USE_CUSTOM_MUTEX static uint32_t mutex_prot; static uint32_t mutex_blocks; #else static pthread_mutex_t mutex_prot; static pthread_mutex_t mutex_blocks; #endif +#else +static pthread_mutex_t mutex_prot; +static pthread_mutex_t mutex_blocks; +#endif #if defined(PAGE64K) #define MEMPROT_SHIFT 16 #define MEMPROT_SHIFT2 (16+16) @@ -111,14 +116,14 @@ typedef struct blockmark_s { #define PREV_BLOCK(b) (blockmark_t*)(((uintptr_t)(b) - (b)->prev.size) - sizeof(blockmark_t)) #define LAST_BLOCK(b, s) (blockmark_t*)(((uintptr_t)(b)+(s))-sizeof(blockmark_t)) -static void printBlock(blockmark_t* b, void* start) +void printBlock(blockmark_t* b, void* start) { - printf_log(LOG_INFO, "========== Block is:\n"); + printf_log(LOG_NONE, "========== Block is:\n"); do { - printf_log(LOG_INFO, "%c%p, fill=%d, size=0x%x (prev=%d/0x%x)\n", b==start?'*':' ', b, b->next.fill, b->next.size, b->prev.fill, b->prev.size); + printf_log(LOG_NONE, "%c%p, fill=%d, size=0x%x (prev=%d/0x%x)\n", b==start?'*':' ', b, b->next.fill, b->next.size, b->prev.fill, b->prev.size); b = NEXT_BLOCK(b); } while(b->next.x32); - printf_log(LOG_INFO, "===================\n"); + printf_log(LOG_NONE, "===================\n"); } // get first subblock free in block. Return NULL if no block, else first subblock free (mark included), filling size @@ -182,6 +187,8 @@ static size_t getMaxFreeBlock(void* block, size_t block_size, void* start) } } +#define THRESHOLD (128-2*sizeof(blockmark_t)) + static void* allocBlock(void* block, void *sub, size_t size, void** pstart) { (void)block; @@ -191,25 +198,26 @@ static void* allocBlock(void* block, void *sub, size_t size, void** pstart) s->next.fill = 1; // check if a new mark is worth it - if(s->next.size>size+2*sizeof(blockmark_t)) + if(s->next.size>size+2*sizeof(blockmark_t)+THRESHOLD) { + size_t old_size = s->next.size; s->next.size = size; - blockmark_t *m = NEXT_BLOCK(s); // this is new n - m->prev.fill = 1; - if(n!=m) { - // new mark + blockmark_t *m = NEXT_BLOCK(s); + m->prev.fill = 1; m->prev.size = s->next.size; m->next.fill = 0; - m->next.size = ((uintptr_t)n - (uintptr_t)m) - sizeof(blockmark_t); + m->next.size = old_size - (size + sizeof(blockmark_t)); n->prev.fill = 0; n->prev.size = m->next.size; + n = m; + } else { + n->prev.fill = 1; } if(pstart && sub==*pstart) { // get the next free block - m = (blockmark_t*)*pstart; - while(m->next.fill) - m = NEXT_BLOCK(m); - *pstart = (void*)m; + while(n->next.fill) + n = NEXT_BLOCK(n); + *pstart = (void*)n; } return (void*)((uintptr_t)sub + sizeof(blockmark_t)); } @@ -223,7 +231,7 @@ static size_t freeBlock(void *block, void* sub, void** pstart) s->next.fill = 0; n->prev.fill = 0; // check if merge with previous - if (s->prev.x32 && !s->prev.fill) { + if (m!=s && s->prev.x32 && !s->prev.fill) { // remove s... m->next.size += s->next.size + sizeof(blockmark_t); n->prev.size = m->next.size; @@ -236,7 +244,7 @@ static size_t freeBlock(void *block, void* sub, void** pstart) s->next.size += n->next.size + sizeof(blockmark_t); n2->prev.size = s->next.size; } - if(pstart && (uintptr_t)*pstart>(uintptr_t)sub) { + if(pstart && (uintptr_t)*pstart>(uintptr_t)s) { *pstart = (void*)s; } // return free size at current block (might be bigger) @@ -259,7 +267,7 @@ static int expandBlock(void* block, void* sub, size_t newsize) if((size_t)(s->next.size + n->next.size + sizeof(blockmark_t)) < newsize) return 0; // free space too short // ok, doing the alloc! - if((s->next.size+n->next.size+sizeof(blockmark_t))-newsize<2*sizeof(blockmark_t)) + if((s->next.size+n->next.size+sizeof(blockmark_t))-newsize<THRESHOLD+2*sizeof(blockmark_t)) s->next.size += n->next.size+sizeof(blockmark_t); else s->next.size = newsize+sizeof(blockmark_t); @@ -284,7 +292,61 @@ static size_t sizeBlock(void* sub) return s->next.size; } -#define THRESHOLD (128-2*sizeof(blockmark_t)) +// return 1 if block is coherent, 0 if not (and printf the issues) +int printBlockCoherent(int i) +{ + if(i<0 || i>=n_blocks) { + printf_log(LOG_NONE, "Error, %d should be between 0 and %d\n", i, n_blocks); + return 0; + } + int ret = 1; + blockmark_t* m = (blockmark_t*)p_blocks[i].block; + // check if first is correct + blockmark_t* first = getNextFreeBlock(m); + if(p_blocks[i].first && p_blocks[i].first!=first) {printf_log(LOG_NONE, "First %p and stored first %p differs for block %d\n", first, p_blocks[i].first, i); ret = 0;} + // check if maxfree is correct, with no hint + size_t maxfree = getMaxFreeBlock(m, p_blocks[i].size, NULL); + if(maxfree != p_blocks[i].maxfree) {printf_log(LOG_NONE, "Maxfree without hint %zd and stored maxfree %zd differs for block %d\n", maxfree, p_blocks[i].maxfree, i); ret = 0;} + // check if maxfree from first is correct + maxfree = getMaxFreeBlock(m, p_blocks[i].size, p_blocks[i].first); + if(maxfree != p_blocks[i].maxfree) {printf_log(LOG_NONE, "Maxfree with hint %zd and stored maxfree %zd differs for block %d\n", maxfree, p_blocks[i].maxfree, i); ret = 0;} + // check chain + blockmark_t* last = (blockmark_t*)(((uintptr_t)m)+p_blocks[i].size-sizeof(blockmark_t)); + while(m<last) { + blockmark_t* n = NEXT_BLOCK(m); + if(!m->next.fill && !n->next.fill && n!=last) { + printf_log(LOG_NONE, "Chain contains 2 subsequent free blocks %p (%d) and %p (%d) for block %d\n", m, m->next.size, n, n->next.size, i); + ret = 0; + } + m = n; + } + if(m!=last) { + printf_log(LOG_NONE, "Last block %p is behond expexted block %p for block %d\n", m, last, i); + ret = 0; + } + + return ret; +} + +void testAllBlocks() +{ + size_t total = 0; + size_t fragmented_free = 0; + size_t max_free = 0; + for(int i=0; i<n_blocks; ++i) { + printBlockCoherent(i); + total += p_blocks[i].size; + if(max_free<p_blocks[i].maxfree) + max_free = p_blocks[i].maxfree; + blockmark_t* m = (blockmark_t*)p_blocks[i].block; + while(m->next.x32) { + if(!m->next.fill) + fragmented_free += m->next.size; + m = NEXT_BLOCK(m); + } + } + printf_log(LOG_NONE, "Total %d blocks, for %zd allocated memory, max_free %zd, toatal fragmented free %zd\n", n_blocks, total, max_free, fragmented_free); +} static size_t roundSize(size_t size) { @@ -315,9 +377,7 @@ void* customMalloc(size_t size) if(sub) { if(rsize-size<THRESHOLD) size = rsize; - void* ret = allocBlock(p_blocks[i].block, sub, size, NULL); - if(sub==p_blocks[i].first) - p_blocks[i].first = getNextFreeBlock(sub); + void* ret = allocBlock(p_blocks[i].block, sub, size, &p_blocks[i].first); if(rsize==p_blocks[i].maxfree) p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first); mutex_unlock(&mutex_blocks); @@ -354,8 +414,8 @@ void* customMalloc(size_t size) n->prev.fill = 0; n->prev.size = m->next.size; // alloc 1st block - void* ret = allocBlock(p_blocks[i].block, p, size, NULL); - p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL); + void* ret = allocBlock(p_blocks[i].block, p, size, &p_blocks[i].first); + p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first); mutex_unlock(&mutex_blocks); return ret; } @@ -378,7 +438,7 @@ void* customRealloc(void* p, size_t size) && (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) { void* sub = (void*)(addr-sizeof(blockmark_t)); if(expandBlock(p_blocks[i].block, sub, size)) { - if(sub<p_blocks[i].first && p+size<p_blocks[i].first) + if(sub<p_blocks[i].first && p+size>=p_blocks[i].first) p_blocks[i].first = getNextFreeBlock(sub); p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first); mutex_unlock(&mutex_blocks); @@ -406,10 +466,7 @@ void customFree(void* p) if ((addr>(uintptr_t)p_blocks[i].block) && (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) { void* sub = (void*)(addr-sizeof(blockmark_t)); - void* n = NEXT_BLOCK((blockmark_t*)sub); - size_t newfree = freeBlock(p_blocks[i].block, sub, NULL); - if(sub<=p_blocks[i].first) - p_blocks[i].first = getPrevFreeBlock(n); + size_t newfree = freeBlock(p_blocks[i].block, sub, &p_blocks[i].first); if(p_blocks[i].maxfree < newfree) p_blocks[i].maxfree = newfree; mutex_unlock(&mutex_blocks); return; @@ -558,10 +615,7 @@ void FreeDynarecMap(uintptr_t addr) if ((addr>(uintptr_t)list->chunks[i].block) && (addr<((uintptr_t)list->chunks[i].block+list->chunks[i].size))) { void* sub = (void*)(addr-sizeof(blockmark_t)); - void* n = NEXT_BLOCK((blockmark_t*)sub); - size_t newfree = freeBlock(list->chunks[i].block, sub, NULL); - if(sub<=list->chunks[i].first) - list->chunks[i].first = getPrevFreeBlock(n); + size_t newfree = freeBlock(list->chunks[i].block, sub, &list->chunks[i].first); if(list->chunks[i].maxfree < newfree) list->chunks[i].maxfree = newfree; return; @@ -1047,7 +1101,13 @@ void setProtection(uintptr_t addr, size_t size, uint32_t prot) void setProtection_mmap(uintptr_t addr, size_t size, uint32_t prot) { - setProtection(addr, size, prot|PROT_MMAP); + if(prot) + setProtection(addr, size, prot|PROT_MMAP); + else { + mutex_lock(&mutex_prot); + addMapMem(addr, addr+size-1); + mutex_unlock(&mutex_prot); + } } void refreshProtection(uintptr_t addr) @@ -1311,7 +1371,7 @@ int unlockCustommemMutex() { int ret = 0; int i = 0; - #ifdef DYNAREC + #ifdef USE_CUSTOM_MUTEX uint32_t tid = (uint32_t)GetTID(); #define GO(A, B) \ i = (native_lock_storeifref2_d(&A, 0, tid)==tid); \ @@ -1344,7 +1404,7 @@ void relockCustommemMutex(int locks) static void init_mutexes(void) { - #ifdef DYNAREC + #ifdef USE_CUSTOM_MUTEX native_lock_store(&mutex_blocks, 0); native_lock_store(&mutex_prot, 0); #else @@ -1364,6 +1424,34 @@ static void atfork_child_custommem(void) init_mutexes(); } +void reserveHighMem() +{ + char* p = getenv("BOX64_RESERVE_HIGH"); + if(!p || p[0]=='0') + return; // don't reserve by default + intptr_t cur = 1LL<<47; + mapmem_t* m = mapmem; + while(m && (m->end<cur)) { + m = m->next; + } + while (m) { + uintptr_t addr = 0, end = 0; + if(m->begin>cur) { + void* ret = mmap64((void*)cur, m->begin-cur, 0, MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE|MAP_NORESERVE, -1, 0); + printf_log(LOG_DEBUG, "Reserve %p-%p => %p (%s)\n", (void*)cur, m->begin, ret, strerror(errno)); + printf_log(LOG_DEBUG, "mmap %p-%p\n", m->begin, m->end); + if(ret!=(void*)-1) { + addr = cur; + end = m->begin; + } + } + cur = m->end + 1; + m = m->next; + if(addr) + addMapMem(addr, end); + } +} + void init_custommem_helper(box64context_t* ctx) { (void)ctx; @@ -1392,6 +1480,7 @@ void init_custommem_helper(box64context_t* ctx) mapmem->begin = 0x0; mapmem->end = (uintptr_t)LOWEST - 1; loadProtectionFromMap(); + reserveHighMem(); // check if PageSize is correctly defined if(box64_pagesize != (1<<MEMPROT_SHIFT)) { printf_log(LOG_NONE, "Error: PageSize configuration is wrong: configured with %d, but got %zd\n", 1<<MEMPROT_SHIFT, box64_pagesize); @@ -1478,7 +1567,7 @@ void fini_custommem_helper(box64context_t *ctx) box_free(p_blocks[i].block); #endif box_free(p_blocks); - #ifndef DYNAREC + #ifndef USE_CUSTOM_MUTEX pthread_mutex_destroy(&mutex_prot); pthread_mutex_destroy(&mutex_blocks); #endif |