about summary refs log tree commit diff stats
path: root/src/dynarec/dynablock.c
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-11-11 20:47:10 +0100
committerptitSeb <sebastien.chev@gmail.com>2021-11-11 20:47:10 +0100
commit6a1b9e050a488cb5b2e1217fd3a01e484c3d7bb7 (patch)
treeee38007ce576f32a13b6c8f9ec298002300d74ba /src/dynarec/dynablock.c
parent6675b43dd0d7eb567227bea204ee663b1e7aab4a (diff)
downloadbox64-6a1b9e050a488cb5b2e1217fd3a01e484c3d7bb7.tar.gz
box64-6a1b9e050a488cb5b2e1217fd3a01e484c3d7bb7.zip
[DYNAREC] Changed Dynarec a bit to try stabilise program using many threads and a JIT (help RimWorld Linux, but not enough to be 100% stable)
Diffstat (limited to 'src/dynarec/dynablock.c')
-rwxr-xr-xsrc/dynarec/dynablock.c61
1 files changed, 36 insertions, 25 deletions
diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c
index 469357a7..8a1a37e2 100755
--- a/src/dynarec/dynablock.c
+++ b/src/dynarec/dynablock.c
@@ -56,12 +56,14 @@ dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
     return ret;
 }
 
-void FreeDynablock(dynablock_t* db)
+void FreeDynablock(dynablock_t* db, int need_lock)
 {
     if(db) {
-        dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size, db->parent, db->father, db->sons_size, db->gone);
         if(db->gone)
             return; // already in the process of deletion!
+        dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size, db->parent, db->father, db->sons_size, db->gone);
+        if(need_lock)
+            pthread_mutex_lock(&my_context->mutex_dyndump);
         db->done = 0;
         db->gone = 1;
         // remove from direct if there
@@ -77,16 +79,18 @@ void FreeDynablock(dynablock_t* db)
         // remove and free the sons
         for (int i=0; i<db->sons_size; ++i) {
             dynablock_t *son = (dynablock_t*)arm64_lock_xchg(&db->sons[i], 0);
-            FreeDynablock(son);
+            FreeDynablock(son, 0);
         }
         // only the father free the DynarecMap
         if(!db->father) {
             dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
             FreeDynarecMap(db, (uintptr_t)db->block, db->size);
+            free(db->sons);
+            free(db->instsize);
         }
-        free(db->sons);
-        free(db->instsize);
         free(db);
+        if(need_lock)
+            pthread_mutex_unlock(&my_context->mutex_dyndump);
     }
 }
 
@@ -100,7 +104,7 @@ void FreeDynablockList(dynablocklist_t** dynablocks)
     if((*dynablocks)->direct) {
         for (int i=0; i<(*dynablocks)->textsz; ++i) {
             if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father) 
-                FreeDynablock((*dynablocks)->direct[i]);
+                FreeDynablock((*dynablocks)->direct[i], 1);
         }
         free((*dynablocks)->direct);
     }
@@ -117,7 +121,7 @@ void MarkDynablock(dynablock_t* db)
             db = db->father;    // mark only father
         if(db->need_test)
             return; // already done
-        db->need_test = 1;  // test only blocks that can be marked (and so deleted)
+        db->need_test = 1;
         setJumpTableDefault64(db->x64_addr);
         for(int i=0; i<db->sons_size; ++i)
             setJumpTableDefault64(db->sons[i]->x64_addr);
@@ -199,7 +203,7 @@ int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t si
             }
         // purge the list
         kh_foreach_value(blocks, db,
-            FreeDynablock(db);
+            FreeDynablock(db, 1);
         );
         kh_destroy(dynablocks, blocks);
         // check emptyness
@@ -268,6 +272,7 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
     if (!*created)
         return block;
     
+    pthread_mutex_lock(&my_context->mutex_dyndump);
     if(!dynablocks->direct) {
         dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
         if(arm64_lock_storeifnull(&dynablocks->direct, p)!=p)
@@ -282,12 +287,14 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
     dynablock_t* tmp = (dynablock_t*)arm64_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
     if(tmp !=  block) {
         // a block appeard!
+        pthread_mutex_unlock(&my_context->mutex_dyndump);
         free(block);
         *created = 0;
         return tmp;
     }
 
     *created = 1;
+    pthread_mutex_lock(&my_context->mutex_dyndump);
     return block;
 }
 
@@ -303,7 +310,7 @@ void cancelFillBlock()
     return NULL if block is not found / cannot be created. 
     Don't create if create==0
 */
-static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current)
+static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
 {
     // try the quickest way first: get parent of current and check if ok!
     dynablocklist_t *dynablocks = NULL;
@@ -332,19 +339,19 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
     if(!created)
         return block;   // existing block...
 
-    #if 0
-    if(box64_dynarec_dump)
-        pthread_mutex_lock(&my_context->mutex_dyndump);
-    #endif
     // fill the block
     block->x64_addr = (void*)addr;
-    pthread_mutex_lock(&my_context->mutex_dyndump);
+    if(need_lock)
+        pthread_mutex_lock(&my_context->mutex_dyndump);
     if(sigsetjmp(&dynarec_jmpbuf, 1)) {
         printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
+        if(need_lock)
+            pthread_mutex_unlock(&my_context->mutex_dyndump);
         return NULL;
     }
     void* ret = FillBlock64(block, filladdr);
-    pthread_mutex_unlock(&my_context->mutex_dyndump);
+    if(need_lock)
+        pthread_mutex_unlock(&my_context->mutex_dyndump);
     if(!ret) {
         dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
         void* old = (void*)arm64_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
@@ -355,10 +362,6 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
         free(block);
         block = NULL;
     }
-    #if 0
-    if(box64_dynarec_dump)
-        pthread_mutex_unlock(&my_context->mutex_dyndump);
-    #endif
     // check size
     if(block && block->x64_size) {
         int blocksz = block->x64_size;
@@ -388,19 +391,22 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
 
 dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
 {
-    dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current);
+    dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
     if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
+        if(pthread_mutex_trylock(&my_context->mutex_dyndump))
+            return NULL;
         dynablock_t *father = db->father?db->father:db;
         uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
         if(hash!=father->hash) {
+            father->done = 0;   // invalidating the block
             dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
             // no more current if it gets invalidated too
             if(*current && father->x64_addr>=(*current)->x64_addr && (father->x64_addr+father->x64_size)<(*current)->x64_addr)
                 *current = NULL;
             // Free father, it's now invalid!
-            FreeDynablock(father);
+            FreeDynablock(father, 0);
             // start again... (will create a new block)
-            db = internalDBGetBlock(emu, addr, addr, create, *current);
+            db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
         } else {
             father->need_test = 0;
             protectDB((uintptr_t)father->x64_addr, father->x64_size);
@@ -409,6 +415,7 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t**
             for(int i=0; i<father->sons_size; ++i)
                 addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
         }
+        pthread_mutex_unlock(&my_context->mutex_dyndump);
     } 
     return db;
 }
@@ -417,16 +424,19 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
 {
     dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
     int create = 1;
-    dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
+    dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1);
     if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
+        if(pthread_mutex_trylock(&my_context->mutex_dyndump))
+            return NULL;
         dynablock_t *father = db->father?db->father:db;
         uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
         if(hash!=father->hash) {
+            father->done = 0;   // invalidating the block
             dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
             // Free father, it's now invalid!
-            FreeDynablock(father);
+            FreeDynablock(father, 0);
             // start again... (will create a new block)
-            db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
+            db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
         } else {
             father->need_test = 0;
             protectDB((uintptr_t)father->x64_addr, father->x64_size);
@@ -435,6 +445,7 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
             for(int i=0; i<father->sons_size; ++i)
                 addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
         }
+        pthread_mutex_unlock(&my_context->mutex_dyndump);
     } 
     return db;
 }