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:
parent
729a65f3ab
commit
11f8dc735c
12
TODO
12
TODO
@ -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)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user