diff --git a/headers/private/kernel/ksignal.h b/headers/private/kernel/ksignal.h index 4727053c8d..6b096dcf78 100644 --- a/headers/private/kernel/ksignal.h +++ b/headers/private/kernel/ksignal.h @@ -36,6 +36,10 @@ using BKernel::Thread; #define SYSCALL_RESTART_PARAMETER_SIZE 32 // kernel-internal signals +#define SIGNAL_DEBUG_THREAD 62 + // Debug a thread. Used together with the B_THREAD_DEBUG_STOP thread debug + // flag. Continues the thread, if suspended, but has no effect otherwise. + // Non-blockable. #define SIGNAL_CANCEL_THREAD 63 // Cancel a thread. Non-blockable. #define SIGNAL_CONTINUE_THREAD 64 diff --git a/src/system/kernel/debug/user_debugger.cpp b/src/system/kernel/debug/user_debugger.cpp index fabfecd62d..0d74fcd881 100644 --- a/src/system/kernel/debug/user_debugger.cpp +++ b/src/system/kernel/debug/user_debugger.cpp @@ -2903,39 +2903,24 @@ _user_debug_thread(thread_id threadID) if ((thread->debug_info.flags & B_THREAD_DEBUG_NUB_THREAD) != 0) return B_NOT_ALLOWED; - // already marked stopped? - if ((thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) != 0) + // already marked stopped or being told to stop? + if ((thread->debug_info.flags + & (B_THREAD_DEBUG_STOPPED | B_THREAD_DEBUG_STOP)) != 0) { return B_OK; + } // set the flag that tells the thread to stop as soon as possible atomic_or(&thread->debug_info.flags, B_THREAD_DEBUG_STOP); update_thread_user_debug_flag(thread); - // resume/interrupt the thread, if necessary + // send the thread a SIGNAL_DEBUG_THREAD, so it is interrupted (or + // continued) threadDebugInfoLocker.Unlock(); - SpinLocker schedulerLocker(thread->scheduler_lock); + ReadSpinLocker teamLocker(thread->team_lock); + SpinLocker locker(thread->team->signal_lock); - switch (thread->state) { - case B_THREAD_SUSPENDED: - // thread suspended: wake it up - scheduler_enqueue_in_run_queue(thread); - break; - - default: - // thread may be waiting: interrupt it - thread_interrupt(thread, false); - // TODO: If the thread is already in the kernel and e.g. - // about to acquire a semaphore (before - // thread_prepare_to_block()), we won't interrupt it. - // Maybe we should rather send a signal (SIGTRAP). - schedulerLocker.Unlock(); - - schedulerLocker.SetTo(thread_get_current_thread()->scheduler_lock, - false); - scheduler_reschedule_if_necessary_locked(); - break; - } + send_signal_to_thread_locked(thread, SIGNAL_DEBUG_THREAD, NULL, 0); return B_OK; } diff --git a/src/system/kernel/signal.cpp b/src/system/kernel/signal.cpp index 84a51658d1..8305e0bf95 100644 --- a/src/system/kernel/signal.cpp +++ b/src/system/kernel/signal.cpp @@ -45,13 +45,15 @@ #define BLOCKABLE_SIGNALS \ (~(KILL_SIGNALS | SIGNAL_TO_MASK(SIGSTOP) \ + | SIGNAL_TO_MASK(SIGNAL_DEBUG_THREAD) \ | SIGNAL_TO_MASK(SIGNAL_CONTINUE_THREAD) \ | SIGNAL_TO_MASK(SIGNAL_CANCEL_THREAD))) #define STOP_SIGNALS \ (SIGNAL_TO_MASK(SIGSTOP) | SIGNAL_TO_MASK(SIGTSTP) \ | SIGNAL_TO_MASK(SIGTTIN) | SIGNAL_TO_MASK(SIGTTOU)) #define CONTINUE_SIGNALS \ - (SIGNAL_TO_MASK(SIGCONT) | SIGNAL_TO_MASK(SIGNAL_CONTINUE_THREAD)) + (SIGNAL_TO_MASK(SIGCONT) | SIGNAL_TO_MASK(SIGNAL_CONTINUE_THREAD) \ + | SIGNAL_TO_MASK(SIGNAL_DEBUG_THREAD)) #define DEFAULT_IGNORE_SIGNALS \ (SIGNAL_TO_MASK(SIGCHLD) | SIGNAL_TO_MASK(SIGWINCH) \ | SIGNAL_TO_MASK(SIGCONT) \ @@ -1038,6 +1040,11 @@ handle_signals(Thread* thread) notify_debugger(thread, signal, handler, false); continue; + case SIGNAL_DEBUG_THREAD: + // ignore -- used together with B_THREAD_DEBUG_STOP, which + // is handled above + continue; + case SIGNAL_CANCEL_THREAD: // set up the signal handler handler.sa_handler = thread->cancel_function; @@ -1425,6 +1432,19 @@ send_signal_to_thread_locked(Thread* thread, uint32 signalNumber, break; } + case SIGNAL_DEBUG_THREAD: + { + // Wake up thread if it was suspended, otherwise interrupt it. + thread->going_to_suspend = false; + + SpinLocker locker(thread->scheduler_lock); + if (thread->state == B_THREAD_SUSPENDED) + scheduler_enqueue_in_run_queue(thread); + else + thread_interrupt(thread, false); + + break; + } case SIGNAL_CONTINUE_THREAD: { // wake up thread, and interrupt its current syscall