diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 677be26bc24..ac5b7776144 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -19,14 +19,22 @@ config SERIAL_CONSOLE bool default n -config SERIAL_SIGKILL_CHAR +config TTY_SIGKILL + bool "Support SIGKILL" + default n + select SIG_DEFAULT + depends on !DISABLE_SIGNALS + ---help--- + Whether support Ctrl-c/x event + +config TTY_SIGKILL_CHAR int "Serial parse SIGKILL characters" default 3 if SERIAL_CONSOLE default 4 if !SERIAL_CONSOLE - depends on SIG_SIGKILL && BUILD_FLAT + depends on SIG_SIGKILL ---help--- Use ASCII 3 (Ctrl-c) or 4 (ctrl-d) inputs to determine whether to - send a SIGKILL event. Other charcters may also be selected. + send a SIGKILL event. Other characters may also be selected. REVISIT: Traditionally Ctrl-C would generate SIGINT. Ctrl-D is the End-of-File character that should close the stream. diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index eec172c9702..918476c8d6c 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -1372,7 +1372,7 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) break; #endif -#ifdef CONFIG_SERIAL_SIGKILL_CHAR +#ifdef CONFIG_TTY_SIGKILL_CHAR /* Make the given terminal the controlling terminal of the calling process */ case TIOCSCTTY: @@ -1600,7 +1600,7 @@ errout: int uart_register(FAR const char *path, FAR uart_dev_t *dev) { -#ifdef CONFIG_SERIAL_SIGKILL_CHAR +#ifdef CONFIG_TTY_SIGKILL_CHAR /* Initialize of the task that will receive SIGKILL signals. */ dev->pid = -1; diff --git a/drivers/serial/serial_dma.c b/drivers/serial/serial_dma.c index 17d6f6a56ac..76ad770b560 100644 --- a/drivers/serial/serial_dma.c +++ b/drivers/serial/serial_dma.c @@ -60,14 +60,14 @@ * ************************************************************************************/ -#ifdef CONFIG_SIG_SIGKILL +#ifdef CONFIG_TTY_SIGKILL static bool uart_check_sigkill(const char *buf, size_t size) { size_t i; for (i = 0; i < size; i++) { - if (buf[i] == CONFIG_SERIAL_SIGKILL_CHAR) + if (buf[i] == CONFIG_TTY_SIGKILL_CHAR) { return true; } @@ -88,7 +88,7 @@ static bool uart_check_sigkill(const char *buf, size_t size) * ************************************************************************************/ -#ifdef CONFIG_SIG_SIGKILL +#ifdef CONFIG_TTY_SIGKILL static bool uart_recvchars_sigkill(FAR uart_dev_t *dev) { FAR struct uart_dmaxfer_s *xfer = &dev->dmarx; @@ -324,7 +324,7 @@ void uart_recvchars_done(FAR uart_dev_t *dev) FAR struct uart_dmaxfer_s *xfer = &dev->dmarx; FAR struct uart_buffer_s *rxbuf = &dev->recv; size_t nbytes = xfer->nbytes; -#ifdef CONFIG_SIG_SIGKILL +#ifdef CONFIG_TTY_SIGKILL bool needkill = false; /* Check if the SIGKILL character is anywhere in the newly received DMA buffer. */ @@ -350,7 +350,7 @@ void uart_recvchars_done(FAR uart_dev_t *dev) uart_datareceived(dev); } -#ifdef CONFIG_SIG_SIGKILL +#ifdef CONFIG_TTY_SIGKILL /* Send the SIGKILL signal if needed */ if (needkill) diff --git a/drivers/serial/serial_io.c b/drivers/serial/serial_io.c index 785cc6bc06b..b430fab3441 100644 --- a/drivers/serial/serial_io.c +++ b/drivers/serial/serial_io.c @@ -123,7 +123,7 @@ void uart_recvchars(FAR uart_dev_t *dev) #ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS unsigned int watermark; #endif -#ifdef CONFIG_SIG_SIGKILL +#ifdef CONFIG_TTY_SIGKILL bool needkill = false; #endif unsigned int status; @@ -201,10 +201,10 @@ void uart_recvchars(FAR uart_dev_t *dev) ch = uart_receive(dev, &status); -#ifdef CONFIG_SIG_SIGKILL +#ifdef CONFIG_TTY_SIGKILL /* Is this the special character that will generate the SIGKILL signal? */ - if (dev->pid >= 0 && ch == CONFIG_SERIAL_SIGKILL_CHAR) + if (dev->pid >= 0 && ch == CONFIG_TTY_SIGKILL_CHAR) { /* Yes.. not the the kill is needed and do not put the character into * the Rx buffer. It should not be read as normal data. @@ -249,7 +249,7 @@ void uart_recvchars(FAR uart_dev_t *dev) uart_datareceived(dev); } -#ifdef CONFIG_SIG_SIGKILL +#ifdef CONFIG_TTY_SIGKILL /* Send the SIGKILL signal if needed */ if (needkill) diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 050d26b63f5..45ea27c39ec 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -518,6 +518,9 @@ struct task_group_s sq_queue_t tg_sigactionq; /* List of actions for signals */ sq_queue_t tg_sigpendingq; /* List of pending signals */ +#ifdef CONFIG_SIG_DEFAULT + sigset_t tg_sigdefault; /* Set of signals set to the default action */ +#endif #endif #ifndef CONFIG_DISABLE_ENVIRON diff --git a/include/signal.h b/include/signal.h index 77e6785c8fb..883349bd750 100644 --- a/include/signal.h +++ b/include/signal.h @@ -116,7 +116,7 @@ * all the consequences of _exit() except that the status made available * to wait() and waitpid() indicates abnormal termination by the * specified signal. - * A Abnormal termination of the process. Additionally ith the XSI + * A Abnormal termination of the process. Additionally with the XSI * extension, implementation-defined abnormal termination actions, such * as creation of a core file, may occur. * I Ignore the signal. @@ -169,7 +169,7 @@ # endif #endif -#ifdef CONFIG_SIG_SIGKILL +#ifdef CONFIG_SIG_DEFAULT # ifndef CONFIG_SIG_KILL # define SIGKILL 9 /* Sent when ctrl-c event (vs. standard SIGINT) */ # else diff --git a/sched/Kconfig b/sched/Kconfig index 268a28a7c62..949bbf6dc5e 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -1172,6 +1172,8 @@ config SCHED_ONEXIT_MAX endmenu # RTOS hooks +menu "Signal Configuration" + config SIG_EVTHREAD bool "Support SIGEV_THHREAD" default n @@ -1184,14 +1186,14 @@ config SIG_EVTHREAD different mechanism would need to be development to support this feature on the PROTECTED or KERNEL build. -config SIG_SIGKILL - bool "Support SIGKILL" +config SIG_DEFAULT + bool "Default signal actions" default n depends on !DISABLE_SIGNALS ---help--- - Whether support Ctrl-c/x event, or kill -9 cmd. + Enable to support default signal actions. - NOTE: SIGINT is normally sent by Ctrl-C in other systems. + NOTE: SIGKILL is the only signal currently supported. menu "Signal Numbers" depends on !DISABLE_SIGNALS @@ -1235,12 +1237,10 @@ config SIG_POLL config SIG_KILL int "SIGKILL" default 9 - depends on SIG_SIGKILL + depends on SIG_DEFAULT ---help--- - The SIGKILL signal is sent to a process when Ctrl-c/x event, - or cmd kill -9 xx happened. - - NOTE: SIGINT is normally sent by Ctrl-C in other systems. + The SIGKILL signal is sent to cause a task termination event (only + if CONFIG_SIG_DEFAULT=y) config SIG_SIGCONDTIMEDOUT int "SIGCONDTIMEDOUT" @@ -1260,6 +1260,7 @@ config SIG_SIGWORK used for SIGWORK. Default: 17 endmenu # Signal Numbers +endmenu # Signal Configuration menu "POSIX Message Queue Options" depends on !DISABLE_MQUEUE diff --git a/sched/signal/Make.defs b/sched/signal/Make.defs index f752a0b74cd..984016b24e9 100644 --- a/sched/signal/Make.defs +++ b/sched/signal/Make.defs @@ -44,6 +44,10 @@ CSRCS += sig_removependingsignal.c sig_releasependingsignal.c sig_lowest.c CSRCS += sig_mqnotempty.c sig_cleanup.c sig_dispatch.c sig_deliver.c CSRCS += sig_pause.c sig_nanosleep.c sig_usleep.c sig_sleep.c +ifeq ($(CONFIG_SIG_DEFAULT),y) +CSRCS += sig_default.c +endif + ifeq ($(CONFIG_SIG_EVTHREAD),y) CSRCS += sig_notification.c endif diff --git a/sched/signal/sig_default.c b/sched/signal/sig_default.c new file mode 100644 index 00000000000..0596a82b999 --- /dev/null +++ b/sched/signal/sig_default.c @@ -0,0 +1,300 @@ +/**************************************************************************** + * sched/signal/sig_default.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "signal/signal.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This table is used to make the default action for a signal to the correct + * signal handler. + */ + +#if 0 /* Not used */ +static const struct _sa_sigaction_t g_defactions[MAX_SIGNO + 1] = +{ + /* To be provided */ +} +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* TODO: Take into account pthread-specific signal behaviors */ + +/* Default Actions: + * + * - Abnormal termination of the process. The process is terminated with + * all the consequences of _exit() except that the status made available + * to wait() and waitpid() indicates abnormal termination by the + * specified signal. + * - Abnormal termination of the process. Additionally with the XSI + * extension, implementation-defined abnormal termination actions, such + * as creation of a core file, may occur. + * - Ignore the signal. + * - Stop the process. + * - Continue the process, if it is stopped; otherwise, ignore the signal. + */ + +/**************************************************************************** + * Name: nxsig_abnormal_termination + * + * Description: + * This is the abnormal termination default action for the SIGKILL signal. + * + * Input Parameters: + * Standard signal handler parameters + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void nxsig_abnormal_termination(int signo, FAR siginfo_t *siginfo, + FAR void *arg) +{ +#ifdef HAVE_GROUP_MEMBERS + FAR struct tcb_s *tcb = (FAR struct tcb_s *)this_task(); + + /* Kill of of the children of the task */ + + group_killchildren(tcb); +#endif + + /* And exit to terminate the task */ + + exit(EXIT_FAILURE); +} + +/**************************************************************************** + * Name: nxsig_setup_default_action + * + * Description: + * Setup the default action for the SIGKILL signal + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void nxsig_setup_default_action(FAR struct tcb_s *tcb, + _sa_sigaction_t action, int signo) +{ + FAR struct task_group_s *group; + struct sigaction sa; + + DEBUGASSERT(tcb != NULL && tcb->group != NULL && GOOD_SIGNO(signo)); + group = tcb->group; + + /* Attach the signal handler */ + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = action; + sa.sa_flags = SA_SIGINFO; + (void)sigaction(SIGKILL, &sa, NULL); + + /* Indicate that the default signal handler has been attached */ + + (void)sigaddset(&group->tg_sigdefault, signo); +} + +/**************************************************************************** + * Name: nxsig_setup_default_action + * + * Description: + * Setup the default action for the SIGKILL signal + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void nxsig_unsetup_default_action(FAR struct tcb_s *tcb, int signo) +{ + FAR struct task_group_s *group; + + DEBUGASSERT(tcb != NULL && tcb->group != NULL && GOOD_SIGNO(signo)); + group = tcb->group; + + /* Indicate that the default signal handler has been replaced */ + + (void)sigdelset(&group->tg_sigdefault, signo); +} + +/**************************************************************************** + * Name: nxsig_default_action + * + * Description: + * Look up the default action associated with this signal + * + * Input Parameters: + * signo - The signal number to use in the query + * + * Returned Value: + * The default handler associated with this signal + * + ****************************************************************************/ + +static _sa_sigaction_t nxsig_default_action(int signo) +{ +#if 0 /* Not implemented */ + return g_defactions[signo]; +#else + /* Currently only SIGKILL and the abnormal exit signal action are supported */ + + return signo == SIGKILL ? nxsig_abnormal_termination : NULL; +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxsig_isdefault + * + * Description: + * Return true if the specified signal is set to the default action. + * + * Input Parameters: + * tcb - Identifies the thread associated with the default handler + * signo - The signal number to be queried + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * on failure. + * + ****************************************************************************/ + +bool nxsig_isdefault(FAR struct tcb_s *tcb, int signo) +{ + FAR struct task_group_s *group; + int ret; + + DEBUGASSERT(tcb != NULL && tcb->group != NULL && GOOD_SIGNO(signo)); + group = tcb->group; + + /* Return true if the signo is marked as using the default action. Return + * false in all other cases. + */ + + ret = sigismember(&group->tg_sigdefault, signo); + return ret < 0 ? false : (bool)ret; +} + +/**************************************************************************** + * Name: nxsig_setdefault + * + * Description: + * Set the default action for the specified signal + * + * Input Parameters: + * tcb - Identifies the thread associated with the default handler + * signo - The signal number whose behavior will be modified. + * defaction - True: the default action is in place + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int nxsig_default(FAR struct tcb_s *tcb, int signo, bool defaction) +{ + /* Are we setting or unsetting the default action? */ + + if (defaction) + { + /* We are setting the default action. Look up the default action + * associated with signo. + */ + + _sa_sigaction_t handler = nxsig_default_action(signo); + if (handler != NULL) + { + nxsig_setup_default_action(tcb, handler, signo); + } + } + else + { + /* We are unsetting the default action */ + + nxsig_unsetup_default_action(tcb, SIGKILL); + } + + return OK; +} + +/**************************************************************************** + * Name: nxsig_default_initialize + * + * Description: + * Set all signals to their default action. + * + * Input Parameters: + * tcb - Identifies the thread associated with the default handlers + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int nxsig_default_initialize(FAR struct tcb_s *tcb) +{ + /* Currently only SIGKILL is supported */ + + return nxsig_default(tcb, SIGKILL, true); +} diff --git a/sched/signal/sig_deliver.c b/sched/signal/sig_deliver.c index 34728d69882..e945ed291cd 100644 --- a/sched/signal/sig_deliver.c +++ b/sched/signal/sig_deliver.c @@ -110,13 +110,26 @@ void nxsig_deliver(FAR struct tcb_s *stcb) stcb->sigprocmask = savesigprocmask | sigq->mask | SIGNO2SET(sigq->info.si_signo); - /* Deliver the signal. In the kernel build this has to be handled - * differently if we are dispatching to a signal handler in a user- - * space task or thread; we have to switch to user-mode before - * calling the task. - */ + /* Deliver the signal. */ #if defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL) + /* In the kernel build this has to be handled differently if we are + * dispatching to a signal handler in a user-space task or thread; we + * have to switch to user-mode before calling the task. + */ + +#ifdef CONFIG_SIG_DEFAULT + /* The default signal action handlers, however always reside in the + * kernel address space, regardless of configuration. + */ + + if (nxsig_isdefault(stcb, sigq->info.si_signo)) + { + (*sigq->action.sighandler)(sigq->info.si_signo, &sigq->info, + NULL); + } + else +#endif if ((stcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) { /* The sigq_t pointed to by sigq resides in kernel space. So we diff --git a/sched/signal/signal.h b/sched/signal/signal.h index 7d9d678c24f..0b15225d02d 100644 --- a/sched/signal/signal.h +++ b/sched/signal/signal.h @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -169,6 +170,14 @@ void nxsig_alloc_actionblock(void); void nxsig_release_action(FAR sigactq_t *sigact); +/* sig_default.c */ + +#ifdef CONFIG_SIG_DEFAULT +bool nxsig_isdefault(FAR struct tcb_s *tcb, int signo); +int nxsig_default(FAR struct tcb_s *tcb, int signo, bool defaction); +int nxsig_default_initialize(FAR struct tcb_s *tcb); +#endif + /* sig_pending.c */ sigset_t nxsig_pendingset(FAR struct tcb_s *stcb); diff --git a/sched/task/task_start.c b/sched/task/task_start.c index 74156753fb6..cb985df306a 100644 --- a/sched/task/task_start.c +++ b/sched/task/task_start.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/task/task_start.c * - * Copyright (C) 2007-2010, 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2010, 2013, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -49,6 +49,7 @@ #include "group/group.h" #include "sched/sched.h" +#include "signal/signal.h" #include "task/task.h" /**************************************************************************** @@ -65,62 +66,6 @@ * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: task_sigkill_action - * - * Description: - * This is the default action for the SIGKILL signal. - * - * REVISIT: I think there is an issue here in the PROTECTED and KERNEL - * build modes. In those cases, the signal handler will go through a - * trampoline that drops to user mode for execution of the signal handler. - * In the PROTECTED mode, this will forward the call to here in user mode - * which will result in a crash. The behavior in KERNEL mode in - * indeterminate. - * - * Input Parameters: - * Standard signal handler parameters - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_SIG_SIGKILL -static void task_sigkill_action(int signo, siginfo_t *siginfo, void *arg) -{ -#ifdef HAVE_GROUP_MEMBERS - FAR struct task_tcb_s *tcb = (FAR struct task_tcb_s *)this_task(); - group_killchildren(tcb); -#endif - exit(EXIT_FAILURE); -} - -/**************************************************************************** - * Name: task_setup_sigkill - * - * Description: - * Setup the default action for the SIGKILL signal - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - -static inline void task_setup_sigkill(void) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = task_sigkill_action; - sa.sa_flags = SA_SIGINFO; - sigaction(SIGKILL, &sa, NULL); -} -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -149,10 +94,10 @@ void task_start(void) DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); +#ifdef CONFIG_SIG_DEFAULT /* Set up default signal actions */ -#ifdef CONFIG_SIG_SIGKILL - task_setup_sigkill(); + nxsig_default_initialize(&tcb->cmn); #endif /* Execute the start hook if one has been registered */