diff --git a/TODO b/TODO index 60325f7ccbb..0c2487d00cc 100644 --- a/TODO +++ b/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) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 236c6a9a4af..b0f0697bc69 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -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 diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index dc3efb73bb2..494ce01beb7 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -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 * * 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 +} diff --git a/drivers/serial/serial_dma.c b/drivers/serial/serial_dma.c index f363f9ed0aa..1238182bb8f 100644 --- a/drivers/serial/serial_dma.c +++ b/drivers/serial/serial_dma.c @@ -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 * * 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 */ diff --git a/drivers/serial/serial_io.c b/drivers/serial/serial_io.c index 9d28d64b74e..785cc6bc06b 100644 --- a/drivers/serial/serial_io.c +++ b/drivers/serial/serial_io.c @@ -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 * * 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 } diff --git a/include/nuttx/serial/serial.h b/include/nuttx/serial/serial.h index a5a29f25690..67bfe313a72 100644 --- a/include/nuttx/serial/serial.h +++ b/include/nuttx/serial/serial.h @@ -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 * * 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) } diff --git a/include/signal.h b/include/signal.h index d54ded2feaa..77e6785c8fb 100644 --- a/include/signal.h +++ b/include/signal.h @@ -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 * * 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 diff --git a/sched/Kconfig b/sched/Kconfig index 498a8fd362b..268a28a7c62 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -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 diff --git a/sched/task/task_start.c b/sched/task/task_start.c index a0c88329e52..74156753fb6 100644 --- a/sched/task/task_start.c +++ b/sched/task/task_start.c @@ -42,22 +42,85 @@ #include #include #include +#include #include #include +#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