about summary refs log tree commit diff stats
path: root/src/custommem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/custommem.c')
-rw-r--r--src/custommem.c161
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