diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index 926baafcf1..6ac2bcbcef 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -455,6 +455,10 @@ struct Thread : TeamThreadIteratorEntry, KernelReferenceable { // non-0 after a return from _user_sigsuspend(), containing the inverted // original signal mask, reset in handle_signals(); only accessed by // this thread + sigset_t old_sig_block_mask; + // the old sig_block_mask to be restored when returning to userland + // when THREAD_FLAGS_OLD_SIGMASK is set + ucontext_t* user_signal_context; // only accessed by this thread addr_t signal_stack_base; // only accessed by this thread size_t signal_stack_size; // only accessed by this thread @@ -844,5 +848,7 @@ using BKernel::ProcessGroupList; #define THREAD_FLAGS_COMPAT_MODE 0x2000 // the thread runs a compatibility mode (for instance IA32 on x86_64). #endif +#define THREAD_FLAGS_OLD_SIGMASK 0x4000 + // the thread has an old sigmask to be restored #endif /* _KERNEL_THREAD_TYPES_H */ diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index fdab209879..cc103c2db9 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -1938,6 +1938,16 @@ dump_thread_list(int argc, char **argv) } +static void +update_thread_sigmask_on_exit(Thread* thread) +{ + if ((thread->flags & THREAD_FLAGS_OLD_SIGMASK) != 0) { + thread->flags &= ~THREAD_FLAGS_OLD_SIGMASK; + sigprocmask(SIG_SETMASK, &thread->old_sig_block_mask, NULL); + } +} + + // #pragma mark - private kernel API @@ -2318,6 +2328,8 @@ thread_at_kernel_exit(void) disable_interrupts(); + update_thread_sigmask_on_exit(thread); + // track kernel time bigtime_t now = system_time(); SpinLocker threadTimeLocker(thread->time_lock); @@ -2339,6 +2351,8 @@ thread_at_kernel_exit_no_signals(void) TRACE(("thread_at_kernel_exit_no_signals: exit thread %" B_PRId32 "\n", thread->id)); + update_thread_sigmask_on_exit(thread); + // track kernel time bigtime_t now = system_time(); SpinLocker threadTimeLocker(thread->time_lock); diff --git a/src/system/kernel/wait_for_objects.cpp b/src/system/kernel/wait_for_objects.cpp index 1461e1e149..4eea735e3a 100644 --- a/src/system/kernel/wait_for_objects.cpp +++ b/src/system/kernel/wait_for_objects.cpp @@ -475,15 +475,21 @@ common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet, // set new signal mask sigset_t oldSigMask; - if (sigMask != NULL) + if (sigMask != NULL) { sigprocmask(SIG_SETMASK, sigMask, &oldSigMask); + if (!kernel) { + Thread *thread = thread_get_current_thread(); + thread->old_sig_block_mask = oldSigMask; + thread->flags |= THREAD_FLAGS_OLD_SIGMASK; + } + } // wait for something to happen status = acquire_sem_etc(sync->sem, 1, B_CAN_INTERRUPT | (timeout >= 0 ? B_ABSOLUTE_TIMEOUT : 0), timeout); // restore the old signal mask - if (sigMask != NULL) + if (sigMask != NULL && kernel) sigprocmask(SIG_SETMASK, &oldSigMask, NULL); PRINT(("common_select(): acquire_sem_etc() returned: %lx\n", status)); @@ -927,7 +933,12 @@ _user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet, sigset_t sigMask; int result; - syscall_restart_handle_timeout_pre(timeout); + if (timeout >= 0) { + timeout += system_time(); + // deal with overflow + if (timeout < 0) + timeout = B_INFINITE_TIMEOUT; + } if (numFDs < 0 || !check_max_fds(numFDs)) return B_BAD_VALUE; @@ -994,8 +1005,7 @@ _user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet, || (errorSet != NULL && user_memcpy(userErrorSet, errorSet, bytes) < B_OK))) { result = B_BAD_ADDRESS; - } else - syscall_restart_handle_timeout_post(result, timeout); + } err: free(readSet); @@ -1013,16 +1023,19 @@ _user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout) size_t bytes; int result; - syscall_restart_handle_timeout_pre(timeout); + if (timeout >= 0) { + timeout += system_time(); + // deal with overflow + if (timeout < 0) + timeout = B_INFINITE_TIMEOUT; + } if (numFDs < 0) return B_BAD_VALUE; if (numFDs == 0) { // special case: no FDs - result = common_poll(NULL, 0, timeout, false); - return result < 0 - ? syscall_restart_handle_timeout_post(result, timeout) : result; + return common_poll(NULL, 0, timeout, false); } if (!check_max_fds(numFDs)) @@ -1047,9 +1060,7 @@ _user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout) if (numFDs > 0 && user_memcpy(userfds, fds, bytes) != 0) { if (result >= 0) result = B_BAD_ADDRESS; - } else - syscall_restart_handle_timeout_post(result, timeout); - + } err: free(fds);