diff --git a/Pal/src/host/Linux/db_exception.c b/Pal/src/host/Linux/db_exception.c index 89b6d295..32d7d489 100644 --- a/Pal/src/host/Linux/db_exception.c +++ b/Pal/src/host/Linux/db_exception.c @@ -266,17 +266,15 @@ static void _DkTerminateSighandler (int signum, siginfo_t * info, if (event_num == -1) return; - uintptr_t rip = uc->uc_mcontext.gregs[REG_RIP]; + PAL_TCB_LINUX * tcb = get_tcb_linux(); // If the signal arrives in the middle of a PAL call, add the event // to pending in the current TCB. - if (ADDR_IN_PAL(rip)) { - PAL_TCB_LINUX * tcb = get_tcb_linux(); + if (atomic_read(&tcb->in_pal)) { assert(tcb); - if (!tcb->pending_event) { - // Use the preserved pending event slot - tcb->pending_event = event_num; - } else { + // try to use the preserved pending event slot + int old = 0; + if (__atomic_compare_exchange_n(&tcb->pending_event, &old, event_num,false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { // If there is already a pending event, add the new event to the queue. // (a relatively rare case.) struct event_queue * ev = malloc(sizeof(*ev)); @@ -309,6 +307,11 @@ static void _DkPipeSighandler (int signum, siginfo_t * info, return; } +void __enter_pal_call(void) { + PAL_TCB_LINUX * tcb = get_tcb_linux(); + assert(tcb); + atomic_inc(&tcb->in_pal); +} /* * __check_pending_event(): checks the existence of a pending event in the TCB * and handles the event consequently. @@ -317,9 +320,12 @@ void __check_pending_event (void) { PAL_TCB_LINUX * tcb = get_tcb_linux(); assert(tcb); - if (tcb->pending_event) { - int event = tcb->pending_event; - tcb->pending_event = 0; + + if (atomic_add_return(-1, &tcb->in_pal)) + return; + + int event = __atomic_exchange_n(&tcb->pending_event, 0, __ATOMIC_RELAXED); + if (event) { _DkGenericSignalHandle(event, NULL, NULL); if (!LISTP_EMPTY(&tcb->pending_queue)) { diff --git a/Pal/src/host/Linux/pal_host.h b/Pal/src/host/Linux/pal_host.h index 4c73da68..aede813e 100644 --- a/Pal/src/host/Linux/pal_host.h +++ b/Pal/src/host/Linux/pal_host.h @@ -179,8 +179,11 @@ typedef struct pal_handle #define HANDLE_TYPE(handle) ((handle)->hdr.type) +extern void __enter_pal_call(void); extern void __check_pending_event (void); +#define ENTER_PAL_CALL(name) __enter_pal_call() + #define LEAVE_PAL_CALL() do { __check_pending_event(); } while (0) #define LEAVE_PAL_CALL_RETURN(retval) \ diff --git a/Pal/src/host/Linux/pal_linux.h b/Pal/src/host/Linux/pal_linux.h index 90ed5409..df4d878b 100644 --- a/Pal/src/host/Linux/pal_linux.h +++ b/Pal/src/host/Linux/pal_linux.h @@ -191,7 +191,9 @@ typedef struct pal_tcb_linux { PAL_TCB common; struct { /* private to Linux PAL */ - int pending_event; + struct atomic_int in_pal; + int pending_event; /* needs to be accessed by atomic + * operation */ LISTP_TYPE(event_queue) pending_queue; PAL_HANDLE handle; void * alt_stack;