[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:
Yang Liu authored and GitHub committed 2026-05-25 12:09:21 +02:00
1 parent ef7852773b
commit 5873363e4c
8 files changed
+172 -21

No files matched your search

+53 -18
View File
@@ -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
+14
View File
@@ -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)
+8
View File
@@ -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
+1
View File
@@ -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
+5
View File
@@ -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);
+6 -1
View File
@@ -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
View File
@@ -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);
+7 -1
View File
@@ -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) {