1
0
Fork 0
forked from nuttx/nuttx-update

Squashed commit of the following:

drivers/serial/Kconfig:  It is no longer necessary to restrict Ctrl-C handling to the FLAT build

    sched/signal:  Add a new configuration option to select signal default actions, separate handling of signal default actions from both task startup logic and from the serial TTY Ctrl-C logic.  Add a signal set in the group structure to keep track of what signals have been set to the default action.  In dispatching signals in PROTECTED or KERNEL mode, use this signal set to determine if the default signal handler is attached and dispatch the signal in kernel mode for the default actions.
This commit is contained in:
Gregory Nutt 2018-08-27 11:40:09 -06:00
parent 798922b9c6
commit c0d234a474
12 changed files with 372 additions and 89 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

300
sched/signal/sig_default.c Normal file
View file

@ -0,0 +1,300 @@
/****************************************************************************
* sched/signal/sig_default.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <string.h>
#include <signal.h>
#include <assert.h>
#include <nuttx/sched.h>
#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);
}

View file

@ -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

View file

@ -44,6 +44,7 @@
#include <nuttx/compiler.h>
#include <stdint.h>
#include <stdbool.h>
#include <queue.h>
#include <sched.h>
@ -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);

View file

@ -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 <gnutt@nuttx.org>
*
* 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 */