diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-04-11 11:05:36 +0200 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-04-11 11:05:36 +0200 |
| commit | 3b9feeed120af45a2dc346592b328eb0b2e14911 (patch) | |
| tree | 805803a23c6e2e91fc002b8b8f1b2d9f73a1e298 /src | |
| parent | 6d3ca2df80b6df2e9aabb73210f9c09fd0df97a1 (diff) | |
| download | box64-3b9feeed120af45a2dc346592b328eb0b2e14911.tar.gz box64-3b9feeed120af45a2dc346592b328eb0b2e14911.zip | |
Improvement in internal mutex handling on signal, and [DYNAREC] multitasking changes to the JmpTable
Diffstat (limited to 'src')
| -rwxr-xr-x | src/box64context.c | 84 | ||||
| -rw-r--r-- | src/custommem.c | 82 | ||||
| -rwxr-xr-x | src/include/box64context.h | 5 | ||||
| -rw-r--r-- | src/include/custommem.h | 4 | ||||
| -rwxr-xr-x | src/include/threads.h | 3 | ||||
| -rwxr-xr-x | src/libtools/signals.c | 26 | ||||
| -rwxr-xr-x | src/libtools/threads.c | 29 |
7 files changed, 184 insertions, 49 deletions
diff --git a/src/box64context.c b/src/box64context.c index 1fd00750..182a079f 100755 --- a/src/box64context.c +++ b/src/box64context.c @@ -68,6 +68,77 @@ void free_tlsdatasize(void* p) void x64Syscall(x64emu_t *emu); +int unlockMutex() +{ + int ret = unlockCustommemMutex(); + int i; + #define GO(A, B) \ + i = checkMutex(&A); \ + if(i) { \ + pthread_mutex_unlock(&A); \ + ret|=(1<<B); \ + } + + GO(my_context->mutex_once, 5) + GO(my_context->mutex_once2, 6) + GO(my_context->mutex_trace, 7) + #ifdef DYNAREC + GO(my_context->mutex_dyndump, 8) + #else + GO(my_context->mutex_lock, 8) + #endif + GO(my_context->mutex_tls, 9) + GO(my_context->mutex_thread, 10) + #undef GO + + return ret; +} + +void relockMutex(int locks) +{ + relockCustommemMutex(locks); + #define GO(A, B) \ + if(locks&(1<<B)) \ + pthread_mutex_lock(&A); \ + + GO(my_context->mutex_once, 5) + GO(my_context->mutex_once2, 6) + GO(my_context->mutex_trace, 7) + #ifdef DYNAREC + GO(my_context->mutex_dyndump, 8) + #else + GO(my_context->mutex_lock, 8) + #endif + GO(my_context->mutex_tls, 9) + GO(my_context->mutex_thread, 10) + #undef GO +} + +static void init_mutexes(box64context_t* context) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + pthread_mutex_init(&context->mutex_once, &attr); + pthread_mutex_init(&context->mutex_once2, &attr); + pthread_mutex_init(&context->mutex_trace, &attr); +#ifndef DYNAREC + pthread_mutex_init(&context->mutex_lock, &attr); +#else + pthread_mutex_init(&context->mutex_dyndump, &attr); +#endif + pthread_mutex_init(&context->mutex_tls, &attr); + pthread_mutex_init(&context->mutex_thread, &attr); + + pthread_mutexattr_destroy(&attr); +} + +static void atfork_child_box64context(void) +{ + // (re)init mutex if it was lock before the fork + init_mutexes(my_context); +} + EXPORTDYN box64context_t *NewBox64Context(int argc) { @@ -96,16 +167,9 @@ box64context_t *NewBox64Context(int argc) context->argc = argc; context->argv = (char**)calloc(context->argc+1, sizeof(char*)); - pthread_mutex_init(&context->mutex_once, NULL); - pthread_mutex_init(&context->mutex_once2, NULL); - pthread_mutex_init(&context->mutex_trace, NULL); -#ifndef DYNAREC - pthread_mutex_init(&context->mutex_lock, NULL); -#else - pthread_mutex_init(&context->mutex_dyndump, NULL); -#endif - pthread_mutex_init(&context->mutex_tls, NULL); - pthread_mutex_init(&context->mutex_thread, NULL); + init_mutexes(context); + pthread_atfork(NULL, NULL, atfork_child_box64context); + pthread_key_create(&context->tlskey, free_tlsdatasize); diff --git a/src/custommem.c b/src/custommem.c index 634b849b..f4c0102d 100644 --- a/src/custommem.c +++ b/src/custommem.c @@ -21,6 +21,7 @@ #include <sys/mman.h> #include "custommem.h" #include "khash.h" +#include "threads.h" #ifdef DYNAREC #include "dynablock.h" #include "dynarec/arm64_lock.h" @@ -55,7 +56,7 @@ typedef struct blocklist_s { #define MMAPSIZE (256*1024) // allocate 256kb sized blocks -static pthread_mutex_t mutex_blocks = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t mutex_blocks; static int n_blocks = 0; // number of blocks for custom malloc static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc @@ -570,23 +571,25 @@ void addJumpTableIfDefault64(void* addr, void* jmp) uintptr_t*** tbl = (uintptr_t***)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t**)); for(int i=0; i<(1<<JMPTABL_SHIFT); ++i) tbl[i] = box64_jmptbldefault1; - box64_jmptbl3[idx3] = tbl; + if(arm64_lock_storeifref(&box64_jmptbl3[idx3], tbl, box64_jmptbldefault2)!=tbl) + free(tbl); } if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) { uintptr_t** tbl = (uintptr_t**)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t*)); for(int i=0; i<(1<<JMPTABL_SHIFT); ++i) tbl[i] = box64_jmptbldefault0; - box64_jmptbl3[idx3][idx2] = tbl; + if(arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2], tbl, box64_jmptbldefault1)!=tbl) + free(tbl); } if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) { uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t)); for(int i=0; i<(1<<JMPTABL_SHIFT); ++i) tbl[i] = (uintptr_t)arm64_next; - box64_jmptbl3[idx3][idx2][idx1] = tbl; + if(arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1], tbl, box64_jmptbldefault0)!=tbl) + free(tbl); } - if(box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)arm64_next) - box64_jmptbl3[idx3][idx2][idx1][idx0] = (uintptr_t)jmp; + arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1][idx0], jmp, arm64_next); } void setJumpTableDefault64(void* addr) { @@ -638,19 +641,22 @@ uintptr_t getJumpTableAddress64(uintptr_t addr) uintptr_t*** tbl = (uintptr_t***)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t**)); for(int i=0; i<(1<<JMPTABL_SHIFT); ++i) tbl[i] = box64_jmptbldefault1; - box64_jmptbl3[idx3] = tbl; + if(arm64_lock_storeifref(&box64_jmptbl3[idx3], tbl, box64_jmptbldefault2)!=tbl) + free(tbl); } if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) { uintptr_t** tbl = (uintptr_t**)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t*)); for(int i=0; i<(1<<JMPTABL_SHIFT); ++i) tbl[i] = box64_jmptbldefault0; - box64_jmptbl3[idx3][idx2] = tbl; + if(arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2], tbl, box64_jmptbldefault1)!=tbl) + free(tbl); } if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) { uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t)); for(int i=0; i<(1<<JMPTABL_SHIFT); ++i) tbl[i] = (uintptr_t)arm64_next; - box64_jmptbl3[idx3][idx2][idx1] = tbl; + if(arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1], tbl, box64_jmptbldefault0)!=tbl) + free(tbl); } return (uintptr_t)&box64_jmptbl3[idx3][idx2][idx1][idx0]; @@ -882,14 +888,57 @@ void* findBlockNearHint(void* hint, size_t size) } #undef LOWEST -static void atfork_child_custommem(void) +int unlockCustommemMutex() { - // unlock mutex if it was lock before the fork - pthread_mutex_unlock(&mutex_blocks); - pthread_mutex_unlock(&mutex_prot); + int ret = 0; + int i = 0; + #define GO(A, B) \ + i = checkMutex(&A); \ + if(i) { \ + pthread_mutex_unlock(&A); \ + ret|=(1<<B); \ + } + GO(mutex_blocks, 0) + GO(mutex_prot, 1) + #ifdef DYNAREC + GO(mutex_mmap, 2) + #endif + #undef GO + return ret; +} + +void relockCustommemMutex(int locks) +{ + #define GO(A, B) \ + if(locks&(1<<B)) \ + pthread_mutex_lock(&A); \ + + GO(mutex_blocks, 0) + GO(mutex_prot, 1) + #ifdef DYNAREC + GO(mutex_mmap, 2) + #endif + #undef GO +} + +static void init_mutexes(void) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + pthread_mutex_init(&mutex_blocks, &attr); + pthread_mutex_init(&mutex_prot, &attr); #ifdef DYNAREC - pthread_mutex_unlock(&mutex_mmap); + pthread_mutex_init(&mutex_mmap, &attr); #endif + + pthread_mutexattr_destroy(&attr); +} + +static void atfork_child_custommem(void) +{ + // (re)init mutex if it was lock before the fork + init_mutexes(); } void init_custommem_helper(box64context_t* ctx) @@ -898,9 +947,8 @@ void init_custommem_helper(box64context_t* ctx) return; inited = 1; memprot = kh_init(memprot); - pthread_mutex_init(&mutex_prot, NULL); + init_mutexes(); #ifdef DYNAREC - pthread_mutex_init(&mutex_mmap, NULL); #ifdef ARM64 if(box64_dynarec) for(int i=0; i<(1<<JMPTABL_SHIFT); ++i) { @@ -988,5 +1036,5 @@ void fini_custommem_helper(box64context_t *ctx) #endif free(p_blocks); pthread_mutex_destroy(&mutex_prot); - //pthread_mutex_destroy(&mutex_blocks); + pthread_mutex_destroy(&mutex_blocks); } diff --git a/src/include/box64context.h b/src/include/box64context.h index ffcacc36..4d48c816 100755 --- a/src/include/box64context.h +++ b/src/include/box64context.h @@ -200,4 +200,9 @@ int AddTLSPartition(box64context_t* context, int tlssize); void thread_set_emu(x64emu_t* emu); x64emu_t* thread_get_emu(); +// unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex +int unlockMutex(); +// relock the muxtex that were unlocked +void relockMutex(int locks); + #endif //__BOX64CONTEXT_H_ diff --git a/src/include/custommem.h b/src/include/custommem.h index 15f38596..1b86d251 100644 --- a/src/include/custommem.h +++ b/src/include/custommem.h @@ -52,6 +52,10 @@ void unlockDB(); void* find32bitBlock(size_t size); void* findBlockNearHint(void* hint, size_t size); +// unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex +int unlockCustommemMutex(); +// relock the muxtex that were unlocked +void relockCustommemMutex(int locks); void init_custommem_helper(box64context_t* ctx); void fini_custommem_helper(box64context_t* ctx); diff --git a/src/include/threads.h b/src/include/threads.h index fa9d64ab..19d3c9bc 100755 --- a/src/include/threads.h +++ b/src/include/threads.h @@ -20,4 +20,7 @@ void fini_pthread_helper(box64context_t* context); // prepare an "emuthread structure" in pet and return address of function pointer for a "thread creation routine" void* my_prepare_thread(x64emu_t *emu, void* f, void* arg, int ssize, void** pet); +//check if a mutex is locked by current thread (works only for PTHREAD_MUTEX_ERRORCHECK typed mutex) +int checkMutex(void* m); + #endif //_THREADS_H_ \ No newline at end of file diff --git a/src/libtools/signals.c b/src/libtools/signals.c index a0126748..5c66522e 100755 --- a/src/libtools/signals.c +++ b/src/libtools/signals.c @@ -434,8 +434,8 @@ uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr) void my_sigactionhandler_oldcode(int32_t sig, siginfo_t* info, void * ucntx, int* old_code, void* cur_db) { - // need to create some x64_ucontext???? - pthread_mutex_unlock(&my_context->mutex_trace); // just in case + int Locks = unlockMutex(); + printf_log(LOG_DEBUG, "Sigactionhanlder for signal #%d called (jump to %p/%s)\n", sig, (void*)my_context->signals[sig], GetNativeName((void*)my_context->signals[sig])); uintptr_t restorer = my_context->restorer[sig]; @@ -643,6 +643,7 @@ void my_sigactionhandler_oldcode(int32_t sig, siginfo_t* info, void * ucntx, int *old_code = -1; // re-init the value to allow another segfault at the same place if(used_stack) // release stack new_ss->ss_flags = 0; + relockMutex(Locks); longjmp(ejb->jmpbuf, 1); } printf_log(LOG_INFO, "Warning, context has been changed in Sigactionhanlder%s\n", (sigcontext->uc_mcontext.gregs[X64_RIP]!=sigcontext_copy.uc_mcontext.gregs[X64_RIP])?" (EIP changed)":""); @@ -681,12 +682,15 @@ void my_sigactionhandler_oldcode(int32_t sig, siginfo_t* info, void * ucntx, int #undef GO printf_log(LOG_DEBUG, "Sigactionhanlder main function returned (exit=%d, restorer=%p)\n", exits, (void*)restorer); - if(exits) + if(exits) { + relockMutex(Locks); exit(ret); + } if(restorer) RunFunctionHandler(&exits, 0, restorer, 0); if(used_stack) // release stack new_ss->ss_flags = 0; + relockMutex(Locks); } void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) @@ -706,6 +710,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) void * pc = NULL; // unknow arch... #warning Unhandled architecture #endif + int Locks = unlockMutex(); uint32_t prot = getProtection((uintptr_t)addr); #ifdef DYNAREC dynablock_t* db = NULL; @@ -742,12 +747,17 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) ejb->emu->ip.q[0] = getX64Address(db, (uintptr_t)pc); ejb->emu->eflags.x64 = p->uc_mcontext.regs[26]; dynarec_log(LOG_DEBUG, "Auto-SMC detected, getting out of current Dynablock!\n"); + relockMutex(Locks); longjmp(ejb->jmpbuf, 2); } dynarec_log(LOG_INFO, "Warning, Auto-SMC (%p for db %p/%p) detected, but jmpbuffer not ready!\n", (void*)addr, db, (void*)db->x64_addr); } // done - if(prot&PROT_WRITE) return; // if there is no write permission, don't return and continue to program signal handling + if(prot&PROT_WRITE) { + // if there is no write permission, don't return and continue to program signal handling + relockMutex(Locks); + return; + } } else if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&(PROT_READ|PROT_WRITE))) { db = FindDynablockFromNativeAddress(pc); db_searched = 1; @@ -757,6 +767,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) if(addr && pc && db) { // probably a glitch due to intensive multitask... dynarec_log(/*LOG_DEBUG*/LOG_INFO, "SIGSEGV with Access error on %p for %p , db=%p, retrying\n", pc, addr, db); + relockMutex(Locks); return; // try again } } @@ -771,6 +782,10 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) printf_log(log_minimum, "%04d|Double %s (code=%d, pc=%p, addr=%p)!\n", GetTID(), signame, old_code, old_pc, old_addr); exit(-1); } else { + if(sig==SIGSEGV && info->si_code==2 && ((prot&~PROT_CUSTOM)==5 || (prot&~PROT_CUSTOM)==7)) { + relockMutex(Locks); + return; // that's probably just a multi-task glitch, like seen in terraria + } #ifdef DYNAREC if(!db_searched) db = FindDynablockFromNativeAddress(pc); @@ -840,8 +855,7 @@ exit(-1); else printf_log(log_minimum, "\n"); } - if(sig==SIGSEGV && info->si_code==2 && ((prot&~PROT_CUSTOM)==5 || (prot&~PROT_CUSTOM)==7)) - return; // that's probably just a multi-task glitch, like seen in terraria + relockMutex(Locks); if(my_context->signals[sig] && my_context->signals[sig]!=1) { if(my_context->is_sigaction[sig]) my_sigactionhandler_oldcode(sig, info, ucntx, &old_code, db); diff --git a/src/libtools/threads.c b/src/libtools/threads.c index 82f558f4..5e969807 100755 --- a/src/libtools/threads.c +++ b/src/libtools/threads.c @@ -922,21 +922,6 @@ emu_jmpbuf_t* GetJmpBuf() return ejb; } -static void atfork_child(void) -{ - //unlock all potential mutex, this is a new fork! - pthread_mutex_unlock(&my_context->mutex_once); - pthread_mutex_unlock(&my_context->mutex_once2); - pthread_mutex_unlock(&my_context->mutex_trace); - #ifndef DYNAREC - pthread_mutex_unlock(&my_context->mutex_lock); - #else - pthread_mutex_unlock(&my_context->mutex_dyndump); - #endif - pthread_mutex_unlock(&my_context->mutex_tls); - pthread_mutex_unlock(&my_context->mutex_thread); -} - void init_pthread_helper() { InitCancelThread(); @@ -949,7 +934,6 @@ void init_pthread_helper() unaligned_mutex = kh_init(mutex); #endif #endif - pthread_atfork(NULL, NULL, atfork_child); } void fini_pthread_helper(box64context_t* context) @@ -986,3 +970,16 @@ void fini_pthread_helper(box64context_t* context) pthread_setspecific(thread_key, NULL); } } + +int checkMutex(void* m) +{ + pthread_mutex_t* mutex = (pthread_mutex_t*)m; + int ret = pthread_mutex_trylock(mutex); + if(ret==0) { + pthread_mutex_unlock(mutex); + return 0; + } + if(ret==EDEADLK) + return 1; + return 0; +} |