Squashed commit of the following:

drivers/serial:  Add Ctrl-C/Ctrl-X support.  This is an initial working implementation that still requires that several details be resolved.

    sched/task/task_start.c: Add default signal action to SIGKILL.
This commit is contained in:
ligd 2018-08-26 08:49:08 -06:00 committed by Gregory Nutt
parent 729a65f3ab
commit 11f8dc735c
9 changed files with 286 additions and 23 deletions

12
TODO
View File

@ -1,4 +1,4 @@
NuttX TODO List (Last updated June 21, 2018)
NuttX TODO List (Last updated August 26, 2018)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This file summarizes known NuttX bugs, limitations, inconsistencies with
@ -21,7 +21,7 @@ nuttx/:
(5) Binary loaders (binfmt/)
(16) Network (net/, drivers/net)
(4) USB (drivers/usbdev, drivers/usbhost)
(2) Other drivers (drivers/)
(1) Other drivers (drivers/)
(12) Libraries (libc/, libm/)
(10) File system/Generic drivers (fs/, drivers/)
(10) Graphics Subsystem (graphics/)
@ -2138,14 +2138,6 @@ o Other drivers (drivers/)
debug if you could see all of the SYSLOG output up to the
time of the crash. But not essential.
Title: ADD SUPPORT FOR CONTROL-C
Description: Add support for control-C interrupts and perhaps other
interrupts generated from a keyboard.
Status: Open
Priority: Low. This would make working with tasks at the NSH terminal
more like working with processes via a Bash shell. That is
a feature enhancement.
o Linux/Cywgin simulation (arch/sim)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -19,6 +19,18 @@ config SERIAL_CONSOLE
bool
default n
config SERIAL_SIGKILL_CHAR
int "Serial parse SIGKILL characters"
default 3 if SERIAL_CONSOLE
default 4 if !SERIAL_CONSOLE
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.
REVISIT: Traditionally Ctrl-C would generate SIGINT. Ctrl-D is the
End-of-File character that should close the stream.
menuconfig 16550_UART
bool "16550 UART Chip support"
default n

View File

@ -1,7 +1,7 @@
/************************************************************************************
* drivers/serial/serial.c
*
* Copyright (C) 2007-2009, 2011-2013, 2016-2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011-2013, 2016-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -703,14 +703,7 @@ static int uart_close(FAR struct file *filep)
* a thread currently blocking on any of them.
*/
nxsem_reset(&dev->xmitsem, 0);
nxsem_reset(&dev->recvsem, 0);
nxsem_reset(&dev->xmit.sem, 1);
nxsem_reset(&dev->recv.sem, 1);
#ifndef CONFIG_DISABLE_POLL
nxsem_reset(&dev->pollsem, 1);
#endif
uart_reset_sem(dev);
uart_givesem(&dev->closesem);
return OK;
}
@ -1376,6 +1369,25 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
}
break;
#endif
#ifdef CONFIG_SERIAL_SIGKILL_CHAR
case TIOCSCTTY:
{
/* REVISIT: This only applies to console devices (TTYs). In
* reality, this feature should be controlled by TERMIOS ISIG
* c_lflag setting.
*/
if (dev->isconsole)
{
/* Save the PID of the recipient of the SIGKILL signal. */
dev->pid = (pid_t)arg;
DEBUGASSERT((unsigned long)dev->pid = arg);
}
}
break;
#endif
}
}
@ -1584,6 +1596,12 @@ errout:
int uart_register(FAR const char *path, FAR uart_dev_t *dev)
{
#ifdef CONFIG_SERIAL_SIGKILL_CHAR
/* Initialize of the task that will receive SIGKILL signals. */
dev->pid = -1;
#endif
/* Initialize semaphores */
nxsem_init(&dev->xmit.sem, 0, 1);
@ -1728,3 +1746,23 @@ void uart_connected(FAR uart_dev_t *dev, bool connected)
leave_critical_section(flags);
}
#endif
/************************************************************************************
* Name: uart_reset_sem
*
* Description:
* This function is called when need reset uart semphore, this may used in kill one
* process, but this process was reading/writing with the semphore.
*
************************************************************************************/
void uart_reset_sem(FAR uart_dev_t *dev)
{
nxsem_reset(&dev->xmitsem, 0);
nxsem_reset(&dev->recvsem, 0);
nxsem_reset(&dev->xmit.sem, 1);
nxsem_reset(&dev->recv.sem, 1);
#ifndef CONFIG_DISABLE_POLL
nxsem_reset(&dev->pollsem, 1);
#endif
}

View File

@ -1,7 +1,7 @@
/************************************************************************************
* drivers/serial/serial_dma.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved.
* Author: Max Neklyudov <macscomp@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
@ -48,6 +48,67 @@
#ifdef CONFIG_SERIAL_DMA
/************************************************************************************
* Private Functions
************************************************************************************/
/************************************************************************************
* Name: uart_check_sigkill
*
* Description:
* Check if the SIGKILL character is in the contiguous Rx DMA buffer region.
*
************************************************************************************/
#ifdef CONFIG_SIG_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)
{
return true;
}
}
return false;
}
#endif
/************************************************************************************
* Name: uart_recvchars_sigkill
*
* Description:
* Check if the SIGKILL character is anywhere in the newly received DMA buffer.
*
* REVISIT: We must also remove the SIGKILL character from the Rx buffer. It
* should not be read as normal data by the caller.
*
************************************************************************************/
#ifdef CONFIG_SIG_SIGKILL
static bool uart_recvchars_sigkill(FAR uart_dev_t *dev)
{
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
if (xfer->nbytes <= xfer->length)
{
return uart_check_sigkill(xfer->buffer, xfer->nbytes);
}
else
{
if (uart_check_sigkill(xfer->buffer, xfer->length))
{
return true;
}
return uart_check_sigkill(xfer->nbuffer, xfer->nbytes - xfer->length);
}
}
#endif
/************************************************************************************
* Public Functions
************************************************************************************/
@ -250,6 +311,16 @@ 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
bool needkill = false;
/* Check if the SIGKILL character is anywhere in the newly received DMA buffer. */
if (dev->pid >= 0 && uart_recvchars_sigkill(dev))
{
needkill = true;
}
#endif
/* Move head for nbytes. */
@ -265,6 +336,16 @@ void uart_recvchars_done(FAR uart_dev_t *dev)
{
uart_datareceived(dev);
}
#ifdef CONFIG_SIG_SIGKILL
/* Send the SIGKILL signal if needed */
if (needkill)
{
kill(dev->pid, SIGKILL);
uart_reset_sem(dev);
}
#endif
}
#endif /* CONFIG_SERIAL_DMA */

View File

@ -1,7 +1,7 @@
/************************************************************************************
* drivers/serial/serial_io.c
*
* Copyright (C) 2007-2009, 2011, 2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011, 2015, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -122,6 +122,9 @@ void uart_recvchars(FAR uart_dev_t *dev)
FAR struct uart_buffer_s *rxbuf = &dev->recv;
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
unsigned int watermark;
#endif
#ifdef CONFIG_SIG_SIGKILL
bool needkill = false;
#endif
unsigned int status;
int nexthead = rxbuf->head + 1;
@ -194,8 +197,24 @@ void uart_recvchars(FAR uart_dev_t *dev)
#endif
#endif
/* Get this next character from the hardware */
ch = uart_receive(dev, &status);
#ifdef CONFIG_SIG_SIGKILL
/* Is this the special character that will generate the SIGKILL signal? */
if (dev->pid >= 0 && ch == CONFIG_SERIAL_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.
*/
needkill = true;
}
else
#endif
/* If the RX buffer becomes full, then the serial data is discarded. This is
* necessary because on most serial hardware, you must read the data in order
* to clear the RX interrupt. An option on some hardware might be to simply
@ -229,4 +248,14 @@ void uart_recvchars(FAR uart_dev_t *dev)
{
uart_datareceived(dev);
}
#ifdef CONFIG_SIG_SIGKILL
/* Send the SIGKILL signal if needed */
if (needkill)
{
kill(dev->pid, SIGKILL);
uart_reset_sem(dev);
}
#endif
}

View File

@ -1,7 +1,7 @@
/************************************************************************************
* include/nuttx/serial/serial.h
*
* Copyright (C) 2007-2008, 2012-2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2008, 2012-2015, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -288,6 +288,10 @@ struct uart_dev_s
tcflag_t tc_lflag; /* Local modes */
#endif
#ifdef CONFIG_SERIAL_SIGKILL_CHAR
pid_t pid; /* Thread PID to receive SIGKILL signals (-1 if none) */
#endif
/* Semaphores */
sem_t closesem; /* Locks out new open while close is in progress */
@ -481,6 +485,17 @@ void uart_recvchars_dma(FAR uart_dev_t *dev);
void uart_recvchars_done(FAR uart_dev_t *dev);
#endif
/************************************************************************************
* Name: uart_reset_sem
*
* Description:
* This function is called when need reset uart semphore, this may used in kill one
* process, but this process was reading/writing with the semphore.
*
************************************************************************************/
void uart_reset_sem(FAR uart_dev_t *dev);
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -1,7 +1,7 @@
/********************************************************************************
* include/signal.h
*
* Copyright (C) 2007-2009, 2011, 2013-2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011, 2013-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -169,6 +169,14 @@
# endif
#endif
#ifdef CONFIG_SIG_SIGKILL
# ifndef CONFIG_SIG_KILL
# define SIGKILL 9 /* Sent when ctrl-c event (vs. standard SIGINT) */
# else
# define SIGKILL CONFIG_SIG_KILL
# endif
#endif
/* The following are non-standard signal definitions */
#ifndef CONFIG_DISABLE_PTHREAD

View File

@ -1184,6 +1184,15 @@ 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"
default n
depends on !DISABLE_SIGNALS
---help---
Whether support Ctrl-c/x event, or kill -9 cmd.
NOTE: SIGINT is normally sent by Ctrl-C in other systems.
menu "Signal Numbers"
depends on !DISABLE_SIGNALS
@ -1223,6 +1232,16 @@ config SIG_POLL
The SIGPOLL signal is sent to a process when an asynchronous I/O
event occurs (meaning it has been polled). Default: 5
config SIG_KILL
int "SIGKILL"
default 9
depends on SIG_SIGKILL
---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.
config SIG_SIGCONDTIMEDOUT
int "SIGCONDTIMEDOUT"
default 16

View File

@ -42,22 +42,85 @@
#include <stdlib.h>
#include <sched.h>
#include <debug.h>
#include <string.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include "group/group.h"
#include "sched/sched.h"
#include "task/task.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* This is an artificial limit to detect error conditions where an argv[]
* list is not properly terminated.
*/
#define MAX_START_ARGS 256
/****************************************************************************
* 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
****************************************************************************/
@ -86,6 +149,12 @@ void task_start(void)
DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD);
/* Set up default signal actions */
#ifdef CONFIG_SIG_SIGKILL
task_setup_sigkill();
#endif
/* Execute the start hook if one has been registered */
#ifdef CONFIG_SCHED_STARTHOOK