Skip to content

Commit 04e1d7d

Browse files
committed
[kernel/signal] fix: respect suspend state when delivering signals
Native signal delivery resumed every suspended thread, including RT_UNINTERRUPTIBLE IPC waiters. This could remove a waiter from a semaphore, mutex, event, mailbox, or message queue wait list without granting the corresponding resource, causing -RT_EINTR or inconsistent higher-level state. Inspect pending signals and suspend state under scheduler ownership. Wake interruptible waiters for common signals, and wake killable waiters only for SIGKILL and SIGSTOP according to RT-Thread suspend semantics. Defer signals not allowed by the current wait mode. Release the signal lock before waking the target thread. Also make scheduler-side pending-signal preprocessing respect the suspend mode, preventing SMP suspend-to-schedule races. Keep rt_signal_wait() blocked for non-matching signals and preserve the remaining timeout. Allow masked signals and NULL siginfo, handle suspend failures without starting a timer, and preserve the outer interrupted wait result when a signal handler invokes other kernel APIs. Add regression coverage for RT-Thread native signal semantics, including masked signals, non-matching signal waits, NULL siginfo, and RT_KILLABLE SIGSTOP handling. The parent implementation fails the regression test because uninterruptible and killable waits complete early after SIGUSR1, and signal_wait returns early for a non-matching signal. Validation: - UP QEMU: core.signal passed. - Dual-core SMP QEMU: core.signal passed. - scons -C bsp/qemu-vexpress-a9 -j$(nproc) passed. Signed-off-by: Hui Su <3164683437@qq.com>
1 parent 8234a36 commit 04e1d7d

4 files changed

Lines changed: 679 additions & 122 deletions

File tree

include/rtdef.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,11 @@ typedef struct rt_timer *rt_timer_t;
587587
typedef unsigned long rt_sigset_t;
588588
typedef siginfo_t rt_siginfo_t;
589589
typedef void (*rt_sighandler_t)(int signo);
590+
#ifdef RT_USING_MUSLLIBC
591+
#define RT_SIG_MASK(signo) ((rt_sigset_t)1 << ((signo) - 1))
592+
#else
593+
#define RT_SIG_MASK(signo) ((rt_sigset_t)1 << (signo))
594+
#endif
590595
#endif /* RT_USING_SIGNALS */
591596
/**@}*/
592597

src/scheduler_mp.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,30 @@ static rt_thread_t _prepare_context_switch_locked(int cpu_id,
713713
}
714714

715715
#ifdef RT_USING_SIGNALS
716+
/* Check whether a signal may wake the thread in its suspend state. */
717+
static rt_bool_t _sched_signal_wakeup_allowed(struct rt_thread *thread)
718+
{
719+
rt_uint8_t stat;
720+
rt_sigset_t pending;
721+
722+
stat = RT_SCHED_CTX(thread).stat;
723+
pending = thread->sig_pending & thread->sig_mask;
724+
725+
if (stat & RT_THREAD_STAT_SIGNAL_WAIT)
726+
{
727+
return RT_TRUE;
728+
}
729+
730+
if (!(stat & RT_SIGNAL_COMMON_WAKEUP_MASK))
731+
{
732+
return RT_TRUE;
733+
}
734+
735+
return !(stat & RT_SIGNAL_KILL_WAKEUP_MASK) &&
736+
(pending & (RT_SIG_MASK(SIGKILL) |
737+
RT_SIG_MASK(SIGSTOP)));
738+
}
739+
716740
/**
717741
* @brief Preprocess pending signals for a suspended thread
718742
*
@@ -727,7 +751,9 @@ static void _sched_thread_preprocess_signal(struct rt_thread *current_thread)
727751
if (rt_sched_thread_is_suspended(current_thread))
728752
{
729753
/* if current_thread signal is in pending */
730-
if ((RT_SCHED_CTX(current_thread).stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL_PENDING)
754+
if (((RT_SCHED_CTX(current_thread).stat & RT_THREAD_STAT_SIGNAL_MASK) &
755+
RT_THREAD_STAT_SIGNAL_PENDING) &&
756+
_sched_signal_wakeup_allowed(current_thread))
731757
{
732758
#ifdef RT_USING_SMART
733759
rt_thread_wakeup(current_thread);

0 commit comments

Comments
 (0)