sched/signal: Add support for partially disabling signals

Signals in NuttX serve two primary purposes:

    1. Synchronization and wake-up:
    Signals can be used to block threads on specific signal sets and later
    wake them up by delivering the corresponding signals to those threads.

    2. Asynchronous notification:
    Signals can also be used to install callback handlers for specific signals, allowing threads to
    asynchronously invoke those handlers when the signals are delivered.

This change introduces the ability to partially disable signal functionality: to disable only signal functions for
Asynchronous notification, keeping functions for Synchronization and wake-up.
This enables finer-grained control over signal usage while preserving existing behavior for supported use cases.

Co-authored-by: Guo Shichao guoshichao@xiaomi.com
Signed-off-by: Chengdong Wang wangchengdong@lixiang.com
This commit is contained in:
wangchengdong
2026-01-11 20:44:45 +08:00
committed by Alan C. Assis
parent ac3d964973
commit 0ea686bc5b
21 changed files with 159 additions and 68 deletions

View File

@@ -56,8 +56,9 @@
static bool syslog_safe_to_block(void)
{
#ifdef CONFIG_ENABLE_ALL_SIGNALS
FAR const struct tcb_s *rtcb;
#endif
/* It's not safe to block in interrupts or when executing the idle loop */
if (up_interrupt_context() || sched_idletask())
@@ -67,11 +68,13 @@ static bool syslog_safe_to_block(void)
/* It's not safe to block if a signal is being delivered */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
rtcb = nxsched_self();
if (rtcb->sigdeliver != NULL)
{
return false;
}
#endif
return true;
}

View File

@@ -615,8 +615,9 @@ int up_backtrace(FAR struct tcb_s *tcb,
* handler now.
*
****************************************************************************/
#ifdef CONFIG_ENABLE_ALL_SIGNALS
void up_schedule_sigaction(FAR struct tcb_s *tcb);
#endif
/****************************************************************************
* Name: up_task_start
@@ -708,7 +709,8 @@ void up_pthread_start(pthread_trampoline_t startup,
*
****************************************************************************/
#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__)
#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__) && \
defined(CONFIG_ENABLE_ALL_SIGNALS)
void up_signal_dispatch(_sa_sigaction_t sighand, int signo,
FAR siginfo_t *info, FAR void *ucontext);
#endif

View File

@@ -514,8 +514,10 @@ struct task_group_s
/* POSIX Signal Control Fields ********************************************/
#ifdef CONFIG_ENABLE_ALL_SIGNALS
sq_queue_t tg_sigactionq; /* List of actions for signals */
sq_queue_t tg_sigpendingq; /* List of pending signals */
#endif /* CONFIG_ENABLE_ALL_SIGNALS */
#ifdef CONFIG_SIG_DEFAULT
sigset_t tg_sigdefault; /* Set of signals set to the default action */
#endif
@@ -660,10 +662,13 @@ struct tcb_s
/* POSIX Signal Control Fields ********************************************/
sigset_t sigprocmask; /* Signals that are blocked */
sigset_t sigwaitmask; /* Waiting for pending signals */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
sig_deliver_t sigdeliver;
sq_queue_t sigpendactionq; /* List of pending signal actions */
sq_queue_t sigpostedq; /* List of posted signals */
#endif /* CONFIG_ENABLE_ALL_SIGNALS*/
sigset_t sigprocmask; /* Signals that are blocked */
sigset_t sigwaitmask; /* Waiting for pending signals */
siginfo_t *sigunbinfo; /* Signal info when task unblocked */
/* Robust mutex support ***************************************************/
@@ -707,11 +712,6 @@ struct tcb_s
struct xcptcontext xcp; /* Interrupt register save area */
/* The following function pointer is non-zero if there are pending signals
* to be processed.
*/
sig_deliver_t sigdeliver;
#if CONFIG_TASK_NAME_SIZE > 0
char name[CONFIG_TASK_NAME_SIZE + 1]; /* Task name (with NUL terminator) */
#endif

View File

@@ -106,8 +106,10 @@ struct userspace_s
/* Signal handler trampoline */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
CODE void (*signal_handler)(_sa_sigaction_t sighand, int signo,
FAR siginfo_t *info, FAR void *ucontext);
#endif
/* User-space work queue support */

View File

@@ -154,8 +154,10 @@ SYSCALL_LOOKUP(nxsem_wait_slow, 1)
SYSCALL_LOOKUP(kill, 2)
SYSCALL_LOOKUP(tgkill, 3)
#ifdef CONFIG_ENABLE_ALL_SIGNALS
SYSCALL_LOOKUP(sigaction, 3)
SYSCALL_LOOKUP(sigpending, 1)
#endif
SYSCALL_LOOKUP(sigprocmask, 3)
SYSCALL_LOOKUP(sigqueue, 3)
SYSCALL_LOOKUP(sigsuspend, 1)

View File

@@ -274,7 +274,7 @@
"sigemptyset","signal.h","","int","FAR sigset_t *"
"sigfillset","signal.h","","int","FAR sigset_t *"
"sigismember","signal.h","","int","FAR const sigset_t *","int"
"signal","signal.h","","_sa_handler_t","int","_sa_handler_t"
"signal","signal.h","defined(CONFIG_ENABLE_ALL_SIGNALS)","_sa_handler_t","int","_sa_handler_t"
"sleep","unistd.h","","unsigned int","unsigned int"
"snprintf","stdio.h","","int","FAR char *","size_t","FAR const IPTR char *","..."
"sprintf","stdio.h","","int","FAR char *","FAR const IPTR char *","..."
1 __assert assert.h void FAR const char * int FAR const char *
274 sigemptyset signal.h int FAR sigset_t *
275 sigfillset signal.h int FAR sigset_t *
276 sigismember signal.h int FAR const sigset_t * int
277 signal signal.h defined(CONFIG_ENABLE_ALL_SIGNALS) _sa_handler_t int _sa_handler_t
278 sleep unistd.h unsigned int unsigned int
279 snprintf stdio.h int FAR char * size_t FAR const IPTR char *
280 sprintf stdio.h int FAR char * FAR const IPTR char * ...

View File

@@ -20,27 +20,28 @@
#
# ##############################################################################
target_sources(
c
PRIVATE sig_addset.c
sig_delset.c
sig_emptyset.c
sig_fillset.c
sig_nandset.c
sig_andset.c
sig_orset.c
sig_xorset.c
sig_isemptyset.c
sig_killpg.c
sig_altstack.c
sig_interrupt.c
sig_hold.c
sig_ignore.c
sig_ismember.c
sig_pause.c
sig_psignal.c
sig_raise.c
sig_relse.c
sig_set.c
sig_signal.c
sig_wait.c)
set(SRCS
sig_addset.c
sig_delset.c
sig_emptyset.c
sig_fillset.c
sig_nandset.c
sig_andset.c
sig_orset.c
sig_xorset.c
sig_isemptyset.c
sig_killpg.c
sig_altstack.c
sig_hold.c
sig_ismember.c
sig_pause.c
sig_psignal.c
sig_raise.c
sig_relse.c
sig_wait.c)
if(CONFIG_ENABLE_ALL_SIGNALS)
list(APPEND SRCS sig_ignore.c sig_interrupt.c sig_set.c sig_signal.c)
endif()
target_sources(c PRIVATE ${SRCS})

View File

@@ -24,9 +24,13 @@
CSRCS += sig_addset.c sig_delset.c sig_emptyset.c sig_fillset.c
CSRCS += sig_nandset.c sig_andset.c sig_orset.c sig_xorset.c
CSRCS += sig_isemptyset.c sig_killpg.c sig_altstack.c sig_interrupt.c
CSRCS += sig_hold.c sig_ignore.c sig_ismember.c sig_pause.c sig_psignal.c
CSRCS += sig_raise.c sig_relse.c sig_set.c sig_signal.c sig_wait.c
CSRCS += sig_isemptyset.c sig_killpg.c sig_altstack.c
CSRCS += sig_hold.c sig_ismember.c sig_pause.c sig_psignal.c
CSRCS += sig_raise.c sig_relse.c sig_wait.c
ifeq ($(CONFIG_ENABLE_ALL_SIGNALS),y)
CSRCS += sig_ignore.c sig_interrupt.c sig_set.c sig_signal.c
endif
# Add the signal directory to the build

View File

@@ -1547,6 +1547,39 @@ endmenu # RTOS hooks
menu "Signal Configuration"
choice
prompt "Signal support level"
default ENABLE_ALL_SIGNALS if !DEFAULT_SMALL
default ENABLE_PARTIAL_SIGNALS if DEFAULT_SMALL
config ENABLE_ALL_SIGNALS
bool "Enable full signal support"
---help---
Enable full POSIX signal support, including signal handling,
thread cancellation, timers, and process-related notifications.
This option provides the most complete signal functionality,
but increases code size and resource usage.
Typical use cases:
- Applications relying on POSIX signals or timers
- Systems where memory and CPU resources are sufficient
config ENABLE_PARTIAL_SIGNALS
bool "Enable partial signal support"
---help---
Disable process-related signal functionality while keeping
basic signal handling support.
This option provides a balance between reduced resource usage
and limited signal functionality.
Typical use cases:
- Applications using basic signals without fork/exec
- Resource-constrained real-time systems
endchoice
config SIG_PREALLOC_ACTIONS
int "Number of pre-allocated sigactions"
default 4

View File

@@ -86,7 +86,9 @@ static inline void group_release(FAR struct task_group_s *group)
/* Release pending signals */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
nxsig_release(group);
#endif
#ifndef CONFIG_DISABLE_PTHREAD
/* Release pthread resources */

View File

@@ -77,7 +77,9 @@ static int group_signal_handler(pid_t pid, FAR void *arg)
{
FAR struct group_signal_s *info = (FAR struct group_signal_s *)arg;
FAR struct tcb_s *tcb;
#ifdef CONFIG_ENABLE_ALL_SIGNALS
FAR sigactq_t *sigact;
#endif
int ret;
/* Get the TCB associated with the group member */
@@ -141,6 +143,7 @@ static int group_signal_handler(pid_t pid, FAR void *arg)
/* Is there also a action associated with the task group? */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
sigact = nxsig_find_action(tcb->group, info->siginfo->si_signo);
if (sigact)
{
@@ -164,6 +167,7 @@ static int group_signal_handler(pid_t pid, FAR void *arg)
return 1; /* Terminate the search */
}
}
#endif
}
return 0; /* Keep searching */

View File

@@ -644,7 +644,9 @@ void nx_start(void)
/* Initialize the signal facility (if in link) */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
nxsig_initialize();
#endif
#if !defined(CONFIG_DISABLE_MQUEUE) || !defined(CONFIG_DISABLE_MQUEUE_SYSV)
/* Initialize the named message queue facility (if in link) */

View File

@@ -21,27 +21,16 @@
# ##############################################################################
set(SRCS
sig_initialize.c
sig_action.c
sig_procmask.c
sig_pending.c
sig_suspend.c
sig_kill.c
sig_tgkill.c
sig_queue.c
sig_waitinfo.c
sig_timedwait.c
sig_findaction.c
sig_allocpendingsigaction.c
sig_releasependingsigaction.c
sig_unmaskpendingsignal.c
sig_removependingsignal.c
sig_releasependingsignal.c
sig_lowest.c
sig_notification.c
sig_cleanup.c
sig_dispatch.c
sig_deliver.c
sig_pause.c
sig_nanosleep.c
sig_usleep.c
@@ -49,6 +38,23 @@ set(SRCS
sig_ppoll.c
sig_pselect.c)
if(CONFIG_ENABLE_ALL_SIGNALS)
list(
APPEND
SRCS
sig_action.c
sig_allocpendingsigaction.c
sig_cleanup.c
sig_deliver.c
sig_findaction.c
sig_initialize.c
sig_pending.c
sig_releasependingsigaction.c
sig_releasependingsignal.c
sig_removependingsignal.c
sig_unmaskpendingsignal.c)
endif()
if(CONFIG_SIG_DEFAULT)
list(APPEND SRCS sig_default.c)
endif()

View File

@@ -20,15 +20,16 @@
#
############################################################################
CSRCS += sig_initialize.c
CSRCS += sig_action.c sig_procmask.c sig_pending.c sig_suspend.c
CSRCS += sig_kill.c sig_tgkill.c sig_queue.c sig_waitinfo.c sig_timedwait.c
CSRCS += sig_findaction.c sig_allocpendingsigaction.c
CSRCS += sig_releasependingsigaction.c sig_unmaskpendingsignal.c
CSRCS += sig_removependingsignal.c sig_releasependingsignal.c sig_lowest.c
CSRCS += sig_notification.c sig_cleanup.c sig_dispatch.c sig_deliver.c
CSRCS += sig_pause.c sig_nanosleep.c sig_usleep.c sig_sleep.c
CSRCS += sig_ppoll.c sig_pselect.c
CSRCS += sig_dispatch.c sig_kill.c sig_lowest.c sig_nanosleep.c
CSRCS += sig_notification.c sig_pause.c sig_ppoll.c sig_procmask.c
CSRCS += sig_pselect.c sig_queue.c sig_sleep.c sig_suspend.c sig_tgkill.c
CSRCS += sig_timedwait.c sig_usleep.c sig_waitinfo.c
ifeq ($(CONFIG_ENABLE_ALL_SIGNALS),y)
CSRCS += sig_action.c sig_allocpendingsigaction.c sig_cleanup.c sig_deliver.c
CSRCS += sig_findaction.c sig_initialize.c sig_pending.c sig_releasependingsigaction.c
CSRCS += sig_releasependingsignal.c sig_removependingsignal.c sig_unmaskpendingsignal.c
endif
ifeq ($(CONFIG_SIG_DEFAULT),y)
CSRCS += sig_default.c

View File

@@ -50,6 +50,7 @@
* Private Types
****************************************************************************/
#ifdef CONFIG_ENABLE_ALL_SIGNALS
struct sig_arg_s
{
pid_t pid;
@@ -437,6 +438,7 @@ static int nxsig_alloc_dyn_pending(FAR irqstate_t *flags)
return ret;
}
#endif
/****************************************************************************
* Public Functions
@@ -468,11 +470,13 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info,
bool group_dispatch)
{
FAR struct tcb_s *rtcb = this_task();
FAR sigactq_t *sigact;
irqstate_t flags;
int masked;
int ret = OK;
#ifdef CONFIG_ENABLE_ALL_SIGNALS
FAR sigactq_t *sigact;
FAR sigpendq_t *sigpend = NULL;
#endif
sinfo("TCB=%p pid=%d signo=%d code=%d value=%d masked=%s\n",
stcb, stcb->pid, info->si_signo, info->si_code,
@@ -497,10 +501,6 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info,
/************************** MASKED SIGNAL ACTIONS *************************/
/* Find if there is a group sigaction associated with this signal */
sigact = nxsig_find_action(stcb->group, info->si_signo);
flags = enter_critical_section();
/* Make sure that there is always at least one sigpednq and sigq structure
@@ -509,12 +509,14 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info,
* needs to be done here before using the task state or sigprocmask.
*/
#ifdef CONFIG_ENABLE_ALL_SIGNALS
ret = nxsig_alloc_dyn_pending(&flags);
if (ret < 0)
{
leave_critical_section(flags);
return ret;
}
#endif
masked = nxsig_ismember(&stcb->sigprocmask, info->si_signo);
@@ -582,16 +584,19 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info,
up_switch_context(this_task(), rtcb);
}
#ifdef CONFIG_LIB_SYSCALL
#ifdef CONFIG_ENABLE_ALL_SIGNALS
# ifdef CONFIG_LIB_SYSCALL
/* Must also add signal action if in system call */
if (masked == 0)
{
sigpend = nxsig_add_pendingsignal(stcb, info, group_dispatch);
}
# endif
#endif
}
#ifdef CONFIG_ENABLE_ALL_SIGNALS
/* Its not one we are waiting for... Add it to the list of pending
* signals.
*/
@@ -600,16 +605,22 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info,
{
sigpend = nxsig_add_pendingsignal(stcb, info, group_dispatch);
}
#endif
}
/************************* UNMASKED SIGNAL ACTIONS ************************/
else
{
#ifdef CONFIG_ENABLE_ALL_SIGNALS
/* Find if there is a group sigaction associated with this signal */
sigact = nxsig_find_action(stcb->group, info->si_signo);
/* Queue any sigaction's requested by this task. */
ret = nxsig_queue_action(stcb, sigact, info);
#endif
/* Deliver of the signal must be performed in a critical section */
/* Check if the task is waiting for an unmasked signal. If so, then
@@ -706,12 +717,14 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info,
leave_critical_section(flags);
#ifdef CONFIG_ENABLE_ALL_SIGNALS
/* Dispatch kernel action, if needed, in case a pending signal was added */
if (sigpend != NULL)
{
nxsig_dispatch_kernel_action(stcb, &sigpend->info);
}
#endif
/* In case nxsig_ismember failed due to an invalid signal number */

View File

@@ -145,7 +145,9 @@ int nxsig_procmask(int how, FAR const sigset_t *set, FAR sigset_t *oset)
/* Now, process any pending signals that were just unmasked */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
nxsig_unmask_pendingsignal();
#endif
}
return ret;

View File

@@ -334,8 +334,10 @@ int nxsig_timedwait(FAR const sigset_t *set, FAR struct siginfo *info,
FAR const struct timespec *timeout)
{
FAR struct tcb_s *rtcb;
#ifdef CONFIG_ENABLE_ALL_SIGNALS
sigset_t intersection;
FAR sigpendq_t *sigpend;
#endif
irqstate_t flags;
siginfo_t unbinfo;
int ret;
@@ -351,6 +353,7 @@ int nxsig_timedwait(FAR const sigset_t *set, FAR struct siginfo *info,
flags = enter_critical_section();
rtcb = this_task();
#ifdef CONFIG_ENABLE_ALL_SIGNALS
/* Check if there is a pending signal corresponding to one of the
* signals in the pending signal set argument.
*/
@@ -387,6 +390,7 @@ int nxsig_timedwait(FAR const sigset_t *set, FAR struct siginfo *info,
/* We will have to wait for a signal to be posted to this task. */
else
#endif
{
rtcb->sigunbinfo = (info == NULL) ? &unbinfo : info;

View File

@@ -120,7 +120,9 @@ typedef struct sigq_s sigq_t;
* structures buffers structures.
*/
#ifdef CONFIG_ENABLE_ALL_SIGNALS
extern sigactq_t g_sigactions[CONFIG_SIG_PREALLOC_ACTIONS];
#endif
/* The g_sigfreeaction data structure is a list of available signal action
* structures.
@@ -164,7 +166,9 @@ struct task_group_s;
/* sig_initializee.c */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
void nxsig_initialize(void);
#endif
/* sig_action.c */
@@ -190,8 +194,10 @@ int nxsig_dispatch(pid_t pid, FAR siginfo_t *info,
/* sig_cleanup.c */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
void nxsig_cleanup(FAR struct tcb_s *stcb);
void nxsig_release(FAR struct task_group_s *group);
#endif
/* sig_timedwait.c */

View File

@@ -455,7 +455,9 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status)
/* Deallocate anything left in the TCB's queues */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
nxsig_cleanup(tcb); /* Deallocate Signal lists */
#endif
#ifdef CONFIG_SCHED_DUMP_LEAK
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL)

View File

@@ -119,7 +119,9 @@ static void nxtask_reset_task(FAR struct tcb_s *tcb, bool remove)
/* Deallocate anything left in the TCB's signal queues */
#ifdef CONFIG_ENABLE_ALL_SIGNALS
nxsig_cleanup(tcb); /* Deallocate Signal lists */
#endif
sigemptyset(&tcb->sigprocmask); /* Reset sigprocmask */
/* Reset the current task priority */

View File

@@ -173,10 +173,10 @@
"shmdt","sys/shm.h","defined(CONFIG_MM_SHM)","int","FAR const void *"
"shmget","sys/shm.h","defined(CONFIG_MM_SHM)","int","key_t","size_t","int"
"shutdown","sys/socket.h","defined(CONFIG_NET)","int","int","int"
"sigaction","signal.h","","int","int","FAR const struct sigaction *","FAR struct sigaction *"
"signal","signal.h","","_sa_handler_t","int","_sa_handler_t"
"sigaction","signal.h","defined(CONFIG_ENABLE_ALL_SIGNALS)","int","int","FAR const struct sigaction *","FAR struct sigaction *"
"signal","signal.h","defined(CONFIG_ENABLE_ALL_SIGNALS)","_sa_handler_t","int","_sa_handler_t"
"signalfd","sys/signalfd.h","defined(CONFIG_SIGNAL_FD)","int","int","FAR const sigset_t *","int"
"sigpending","signal.h","","int","FAR sigset_t *"
"sigpending","signal.h","defined(CONFIG_ENABLE_ALL_SIGNALS)","int","FAR sigset_t *"
"sigprocmask","signal.h","","int","int","FAR const sigset_t *","FAR sigset_t *"
"sigqueue","signal.h","","int","int","int","union sigval|FAR void *|sival_ptr"
"sigsuspend","signal.h","","int","FAR const sigset_t *"
1 _assert assert.h void FAR const char * int FAR const char * FAR void *
173 shmdt sys/shm.h defined(CONFIG_MM_SHM) int FAR const void *
174 shmget sys/shm.h defined(CONFIG_MM_SHM) int key_t size_t int
175 shutdown sys/socket.h defined(CONFIG_NET) int int int
176 sigaction signal.h defined(CONFIG_ENABLE_ALL_SIGNALS) int int FAR const struct sigaction * FAR struct sigaction *
177 signal signal.h defined(CONFIG_ENABLE_ALL_SIGNALS) _sa_handler_t int _sa_handler_t
178 signalfd sys/signalfd.h defined(CONFIG_SIGNAL_FD) int int FAR const sigset_t * int
179 sigpending signal.h defined(CONFIG_ENABLE_ALL_SIGNALS) int FAR sigset_t *
180 sigprocmask signal.h int int FAR const sigset_t * FAR sigset_t *
181 sigqueue signal.h int int int union sigval|FAR void *|sival_ptr
182 sigsuspend signal.h int FAR const sigset_t *