mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-07 09:26:11 -10:00
[SIGNAL] Added partial deferred signal support (#3892)
* [SIGNAL] Added partial deferred signal support The cold startup time of `wine explorer` on my 3B6000 dropped from 21s to 13s. * Try to fix wow64 build
This commit is contained in:
1 parent
ef7852773b
commit
5873363e4c
8 files changed
+172
-21
No files matched your search
+53
-18
@@ -16,6 +16,9 @@
|
||||
#include "callback.h"
|
||||
#include "x64trace.h"
|
||||
#include "custommem.h"
|
||||
#ifndef _WIN32
|
||||
#include "signals.h"
|
||||
#endif
|
||||
#include "khash.h"
|
||||
#include "threads.h"
|
||||
#include "rbtree.h"
|
||||
@@ -562,24 +565,57 @@ static uintptr_t defered_prot_p = 0;
|
||||
static size_t defered_prot_sz = 0;
|
||||
static uint32_t defered_prot_prot = 0;
|
||||
static mem_flag_t defered_prot_flags = MEM_ALLOCATED;
|
||||
static sigset_t critical_prot = {0};
|
||||
static void setProtection_generic(uintptr_t addr, size_t sz, uint32_t prot, mem_flag_t flags);
|
||||
#define LOCK_PROT() sigset_t old_sig = {0}; pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig); mutex_lock(&mutex_prot)
|
||||
#define LOCK_PROT_READ() sigset_t old_sig = {0}; pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig); mutex_lock(&mutex_prot)
|
||||
#define LOCK_PROT_FAST() mutex_lock(&mutex_prot)
|
||||
#define UNLOCK_PROT() if(defered_prot_p) { \
|
||||
uintptr_t p = defered_prot_p; size_t sz = defered_prot_sz; uint32_t prot = defered_prot_prot; mem_flag_t f = defered_prot_flags;\
|
||||
defered_prot_p = 0; \
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL); \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
setProtection_generic(p, sz, prot, f); \
|
||||
} else { \
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL); \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
}
|
||||
#define UNLOCK_PROT_READ() mutex_unlock(&mutex_prot); pthread_sigmask(SIG_SETMASK, &old_sig, NULL)
|
||||
#define UNLOCK_PROT_FAST() mutex_unlock(&mutex_prot)
|
||||
|
||||
#ifdef _WIN32
|
||||
void enter_critical_section(void) {}
|
||||
void leave_critical_section(void) {}
|
||||
#endif
|
||||
|
||||
static void setProtection_generic(uintptr_t addr, size_t sz, uint32_t prot, mem_flag_t flags);
|
||||
#define LOCK_PROT() \
|
||||
do { \
|
||||
enter_critical_section(); \
|
||||
mutex_lock(&mutex_prot); \
|
||||
} while (0)
|
||||
|
||||
#define LOCK_PROT_READ() \
|
||||
do { \
|
||||
enter_critical_section(); \
|
||||
mutex_lock(&mutex_prot); \
|
||||
} while (0)
|
||||
|
||||
#define LOCK_PROT_FAST() \
|
||||
do { \
|
||||
mutex_lock(&mutex_prot); \
|
||||
} while (0)
|
||||
|
||||
#define UNLOCK_PROT() \
|
||||
do { \
|
||||
if (defered_prot_p) { \
|
||||
uintptr_t p = defered_prot_p; \
|
||||
size_t sz = defered_prot_sz; \
|
||||
uint32_t prot = defered_prot_prot; \
|
||||
mem_flag_t f = defered_prot_flags; \
|
||||
defered_prot_p = 0; \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
leave_critical_section(); \
|
||||
setProtection_generic(p, sz, prot, f); \
|
||||
} else { \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
leave_critical_section(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define UNLOCK_PROT_READ() \
|
||||
do { \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
leave_critical_section(); \
|
||||
} while (0)
|
||||
|
||||
#define UNLOCK_PROT_FAST() \
|
||||
do { \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
} while (0)
|
||||
|
||||
#ifdef TRACE_MEMSTAT
|
||||
static uint64_t customMalloc_allocated = 0;
|
||||
@@ -3095,7 +3131,6 @@ void init_custommem_helper(box64context_t* ctx)
|
||||
for(int i=0; i<n_blocks; ++i)
|
||||
rb_set(blockstree, (uintptr_t)p_blocks[i].block, (uintptr_t)p_blocks[i].block+p_blocks[i].size, i);
|
||||
memprot = rbtree_init("memprot");
|
||||
sigfillset(&critical_prot);
|
||||
#ifdef DYNAREC
|
||||
if(BOX64ENV(dynarec)) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
|
||||
@@ -41,6 +41,17 @@ static uint32_t x86emu_parity_tab[8] =
|
||||
0x69969669,
|
||||
};
|
||||
|
||||
static void reset_deferred_signal(x64emu_t* emu)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
emu->critical_section = 0;
|
||||
emu->deferred_signal_processing = 0;
|
||||
emu->deferred_signal_count = 0;
|
||||
memset((void*)emu->deferred_signal_pending, 0, sizeof(emu->deferred_signal_pending));
|
||||
memset(emu->deferred_siginfo, 0, sizeof(emu->deferred_siginfo));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
|
||||
{
|
||||
emu->context = context;
|
||||
@@ -90,6 +101,7 @@ static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t s
|
||||
emu->mxcsr.x32 = 0x1f80;
|
||||
// want some new jmpbuf for error recovery
|
||||
emu->flags.need_jmpbuf = 1;
|
||||
reset_deferred_signal(emu);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
@@ -219,6 +231,7 @@ void CloneEmu(x64emu_t *newemu, const x64emu_t* emu)
|
||||
newemu->quit = emu->quit;
|
||||
newemu->error = emu->error;
|
||||
newemu->x64emu_parity_tab = emu->x64emu_parity_tab;
|
||||
reset_deferred_signal(newemu);
|
||||
}
|
||||
|
||||
void CopyEmu(x64emu_t *newemu, const x64emu_t* emu)
|
||||
@@ -247,6 +260,7 @@ void CopyEmu(x64emu_t *newemu, const x64emu_t* emu)
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
newemu->error = emu->error;
|
||||
reset_deferred_signal(newemu);
|
||||
}
|
||||
|
||||
box64context_t* GetEmuContext(x64emu_t* emu)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "regs.h"
|
||||
#include "os.h"
|
||||
#include "box64context.h"
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct x64_ucontext_s x64_ucontext_t;
|
||||
#ifdef BOX32
|
||||
@@ -135,6 +136,13 @@ typedef struct x64emu_s {
|
||||
tlsdatasize_t *tlsdata;
|
||||
// other informations
|
||||
int type; // EMUTYPE_xxx define
|
||||
#ifndef _WIN32
|
||||
volatile sig_atomic_t critical_section;
|
||||
volatile sig_atomic_t deferred_signal_processing;
|
||||
volatile sig_atomic_t deferred_signal_count;
|
||||
volatile sig_atomic_t deferred_signal_pending[MAX_SIGNAL+1];
|
||||
siginfo_t deferred_siginfo[MAX_SIGNAL+1];
|
||||
#endif
|
||||
#ifdef BOX32
|
||||
int libc_err; // copy of errno from libc
|
||||
int libc_herr; // copy of h_errno from libc
|
||||
|
||||
@@ -287,6 +287,7 @@ int AddTLSPartition(box64context_t* context, int tlssize);
|
||||
// defined in fact in threads.c
|
||||
void thread_set_emu(x64emu_t* emu);
|
||||
void thread_forget_emu();
|
||||
x64emu_t* thread_get_emu_no_create(void);
|
||||
x64emu_t* thread_get_emu(void);
|
||||
|
||||
// relock the muxtex that were unlocked
|
||||
|
||||
@@ -71,6 +71,11 @@ int my___sigaction(x64emu_t* emu, int signum, const x64_sigaction_t *act, x64_si
|
||||
|
||||
int my_syscall_rt_sigaction(x64emu_t* emu, int signum, const x64_sigaction_restorer_t *act, x64_sigaction_restorer_t *oldact, int sigsetsize);
|
||||
|
||||
void enter_critical_section();
|
||||
void leave_critical_section();
|
||||
int defer_signal(x64emu_t* emu, int signum, siginfo_t* info);
|
||||
void cancel_deferred_signal_processing(x64emu_t* emu);
|
||||
|
||||
void init_signal_helper(box64context_t* context);
|
||||
void fini_signal_helper(void);
|
||||
|
||||
|
||||
@@ -771,6 +771,7 @@ int my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, sigin
|
||||
#ifdef DYNAREC
|
||||
dynablock_leave_runtime((dynablock_t*)cur_db);
|
||||
#endif
|
||||
cancel_deferred_signal_processing(emu);
|
||||
#ifdef ANDROID
|
||||
siglongjmp(*emu->jmpbuf, skip);
|
||||
#else
|
||||
@@ -817,6 +818,10 @@ int my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, sigin
|
||||
|
||||
void my32_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
{
|
||||
sig = signal_to_x64(sig);
|
||||
x64emu_t* emu = thread_get_emu_no_create();
|
||||
if (defer_signal(emu, sig, info))
|
||||
return;
|
||||
#ifdef DYNAREC
|
||||
ucontext_t *p = (ucontext_t *)ucntx;
|
||||
#ifdef ARM64
|
||||
@@ -835,7 +840,7 @@ void my32_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
void* db = NULL;
|
||||
#endif
|
||||
|
||||
my_sigactionhandler_oldcode_32(NULL, sig, 0, info, ucntx, NULL, db);
|
||||
my_sigactionhandler_oldcode_32(emu, sig, 0, info, ucntx, NULL, db);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+78
-1
@@ -258,9 +258,80 @@ x64emu_t* getEmuSignal(x64emu_t* emu, ucontext_t* p, dynablock_t* db)
|
||||
}
|
||||
#endif
|
||||
|
||||
void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void* ucntx, int* old_code, void* cur_db, uintptr_t x64pc);
|
||||
#ifdef BOX32
|
||||
int my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db);
|
||||
#endif
|
||||
|
||||
static int is_signal_deferrable(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case X64_SIGSEGV:
|
||||
case X64_SIGBUS:
|
||||
case X64_SIGILL:
|
||||
case X64_SIGABRT:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int defer_signal(x64emu_t* emu, int signum, siginfo_t* info)
|
||||
{
|
||||
if (!emu || signum < 0 || signum > MAX_SIGNAL || !is_signal_deferrable(signum) || emu->critical_section <= 0)
|
||||
return 0;
|
||||
|
||||
if (info)
|
||||
emu->deferred_siginfo[signum] = *info;
|
||||
else
|
||||
memset(&emu->deferred_siginfo[signum], 0, sizeof(emu->deferred_siginfo[signum]));
|
||||
emu->deferred_siginfo[signum].si_signo = signum;
|
||||
if (!emu->deferred_signal_pending[signum])
|
||||
++emu->deferred_signal_count;
|
||||
emu->deferred_signal_pending[signum] = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cancel_deferred_signal_processing(x64emu_t* emu)
|
||||
{
|
||||
if (!emu) return;
|
||||
emu->critical_section = 0;
|
||||
emu->deferred_signal_processing = 0;
|
||||
}
|
||||
|
||||
void enter_critical_section()
|
||||
{
|
||||
x64emu_t* emu = thread_get_emu_no_create();
|
||||
if (emu) ++emu->critical_section;
|
||||
}
|
||||
|
||||
void leave_critical_section()
|
||||
{
|
||||
x64emu_t* emu = thread_get_emu_no_create();
|
||||
if (!emu || emu->critical_section <= 0)
|
||||
return;
|
||||
if (--emu->critical_section || !emu->deferred_signal_count || emu->deferred_signal_processing)
|
||||
return;
|
||||
|
||||
emu->deferred_signal_processing = 1;
|
||||
while (emu->deferred_signal_count) {
|
||||
int handled = 0;
|
||||
for (int sig = 1; sig <= MAX_SIGNAL; ++sig) {
|
||||
if (!emu->deferred_signal_pending[sig])
|
||||
continue;
|
||||
siginfo_t info = emu->deferred_siginfo[sig];
|
||||
emu->deferred_signal_pending[sig] = 0;
|
||||
--emu->deferred_signal_count;
|
||||
handled = 1;
|
||||
my_sigactionhandler_oldcode(emu, sig, 0, &info, NULL, NULL, NULL, R_RIP);
|
||||
}
|
||||
if (!handled) {
|
||||
emu->deferred_signal_count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
emu->deferred_signal_processing = 0;
|
||||
}
|
||||
|
||||
int my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db)
|
||||
{
|
||||
int Locks = unlockMutex();
|
||||
@@ -520,6 +591,7 @@ int my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigin
|
||||
#ifdef DYNAREC
|
||||
dynablock_leave_runtime((dynablock_t*)cur_db);
|
||||
#endif
|
||||
cancel_deferred_signal_processing(emu);
|
||||
#ifdef ANDROID
|
||||
siglongjmp(*emu->jmpbuf, skip);
|
||||
#else
|
||||
@@ -841,6 +913,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
#if defined(RV64) || defined(PPC64LE)
|
||||
emu->xSPSave = emu->old_savedsp;
|
||||
#endif
|
||||
cancel_deferred_signal_processing(emu);
|
||||
#ifdef ANDROID
|
||||
siglongjmp(*(JUMPBUFF*)emu->jmpbuf, 3);
|
||||
#else
|
||||
@@ -915,6 +988,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
#if defined(RV64) || defined(PPC64LE)
|
||||
emu->xSPSave = emu->old_savedsp;
|
||||
#endif
|
||||
cancel_deferred_signal_processing(emu);
|
||||
#ifdef ANDROID
|
||||
siglongjmp(*(JUMPBUFF*)emu->jmpbuf, 2);
|
||||
#else
|
||||
@@ -1259,13 +1333,16 @@ dynarec_log(/*LOG_DEBUG*/LOG_INFO, "%04d|Repeated SIGSEGV with Access error on %
|
||||
void my_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
{
|
||||
sig = signal_to_x64(sig);
|
||||
x64emu_t* emu = thread_get_emu_no_create();
|
||||
if (defer_signal(emu, sig, info))
|
||||
return;
|
||||
void* pc = NULL;
|
||||
#ifdef DYNAREC
|
||||
ucontext_t *p = (ucontext_t *)ucntx;
|
||||
pc = (void*)CONTEXT_PC(p);
|
||||
#endif
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(pc);
|
||||
x64emu_t* emu = thread_get_emu();
|
||||
if (!emu) emu = thread_get_emu();
|
||||
uintptr_t x64pc = R_RIP;
|
||||
if(db)
|
||||
x64pc = getX64Address(db, (uintptr_t)pc);
|
||||
|
||||
@@ -256,7 +256,13 @@ void thread_set_emu(x64emu_t* emu)
|
||||
pthread_setspecific(thread_key, et);
|
||||
}
|
||||
|
||||
x64emu_t* thread_get_emu()
|
||||
x64emu_t* thread_get_emu_no_create(void)
|
||||
{
|
||||
emuthread_t* et = (emuthread_t*)pthread_getspecific(thread_key);
|
||||
return et ? et->emu : NULL;
|
||||
}
|
||||
|
||||
x64emu_t* thread_get_emu(void)
|
||||
{
|
||||
emuthread_t *et = (emuthread_t*)pthread_getspecific(thread_key);
|
||||
if(!et) {
|
||||
|
||||
Reference in new issue
Block a user