mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 13:27:01 +08:00
drivers/serial: Add support for Ctrl-Z. This works just like the recently added Ctrl-C support except that SIGSTP is sent when the Ctrl-Z characters is encountered vs. SIGINT.
This commit is contained in:
+43
-5
@@ -165,17 +165,55 @@ config TTY_SIGINT
|
|||||||
should cause an immediate End-of-File result.
|
should cause an immediate End-of-File result.
|
||||||
|
|
||||||
config TTY_SIGINT_CHAR
|
config TTY_SIGINT_CHAR
|
||||||
int "Serial parse SIGINT characters"
|
hex "Serial parse SIGINT characters"
|
||||||
default 3 if SERIAL_CONSOLE
|
default 0x03 if SERIAL_CONSOLE
|
||||||
default 4 if !SERIAL_CONSOLE
|
default 0x04 if !SERIAL_CONSOLE
|
||||||
depends on TTY_SIGINT
|
depends on TTY_SIGINT
|
||||||
---help---
|
---help---
|
||||||
Use ASCII 3 (Ctrl-c) or 4 (ctrl-d) inputs to determine whether to
|
Use ASCII 0x03 (Ctrl-c) or 0x04 (ctrl-d) inputs to determine whether
|
||||||
send a SIGINT event. Other characters may also be selected.
|
to send a SIGINT event. Other characters may also be selected.
|
||||||
|
|
||||||
REVISIT: Traditionally Ctrl-C would generate SIGINT. Ctrl-D is the
|
REVISIT: Traditionally Ctrl-C would generate SIGINT. Ctrl-D is the
|
||||||
End-of-File character that should close the stream.
|
End-of-File character that should close the stream.
|
||||||
|
|
||||||
|
config TTY_SIGSTP
|
||||||
|
bool "Support SIGSTP"
|
||||||
|
default n
|
||||||
|
select CONFIG_SIG_SIGSTOP_ACTION
|
||||||
|
depends on !DISABLE_SIGNALS && SERIAL_TERMIOS
|
||||||
|
---help---
|
||||||
|
Whether support Ctrl-z event. Enabled automatically for console
|
||||||
|
devices. May be enabled for other serial devices using the ISIG bit
|
||||||
|
in the Termios c_lflag.
|
||||||
|
|
||||||
|
REVISIT: This implementation is compliant but incomplete. The
|
||||||
|
c_lflag ISIG bit normally enables/disables INTR, QUIT, SUSP, and
|
||||||
|
DSUSP character processing. The relationship between these names,
|
||||||
|
standard signals, and typical key presses are as follows:
|
||||||
|
|
||||||
|
INTR SIGINT Ctrl-C ETX(0x03) Interrupt
|
||||||
|
KILL SIGKILL Ctrl-U NAK(0x15) Kill
|
||||||
|
QUIT SIGQUIT Ctrl-\ FS (0x1c) Quit
|
||||||
|
SUSP SIGSTP Ctrl-Z SUB(0x1a) Suspend
|
||||||
|
DSUSP SIGSTP Ctrl-Y EM (0x19) Delayed suspend
|
||||||
|
|
||||||
|
Additional requirements:
|
||||||
|
- SIGKILL cannot be caught or ignored. Compared to SIGTERM which
|
||||||
|
is like SIGKILL but can be caught or ignored.
|
||||||
|
- SIGQUIT is like SIGINT but causes generation of a core dump
|
||||||
|
- SIGSTOP cannot be caught or ignored. SIGSTP is like SIGSTOP but
|
||||||
|
can be caught or ignored ignored.
|
||||||
|
- The delayed suspend (DSUSD) is like suspend (SUPD), except that
|
||||||
|
the suspension is delayed until the next read operation
|
||||||
|
|
||||||
|
config TTY_SIGSTP_CHAR
|
||||||
|
hex "Serial parse SIGSTP characters"
|
||||||
|
default 0x1a
|
||||||
|
depends on TTY_SIGSTP
|
||||||
|
---help---
|
||||||
|
Use ASCII 0x1a (Ctrl-z) input to determine whether to send a SIGSTP
|
||||||
|
event. Other characters may also be selected.
|
||||||
|
|
||||||
#
|
#
|
||||||
# Serial console selection
|
# Serial console selection
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1372,7 +1372,7 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
/* Make the given terminal the controlling terminal of the calling process */
|
/* Make the given terminal the controlling terminal of the calling process */
|
||||||
|
|
||||||
case TIOCSCTTY:
|
case TIOCSCTTY:
|
||||||
@@ -1436,7 +1436,7 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
dev->tc_oflag = termiosp->c_oflag;
|
dev->tc_oflag = termiosp->c_oflag;
|
||||||
dev->tc_lflag = termiosp->c_lflag;
|
dev->tc_lflag = termiosp->c_lflag;
|
||||||
|
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
/* If the ISIG flag has been cleared in c_lflag, then un-
|
/* If the ISIG flag has been cleared in c_lflag, then un-
|
||||||
* register the controlling terminal.
|
* register the controlling terminal.
|
||||||
*/
|
*/
|
||||||
@@ -1611,7 +1611,7 @@ errout:
|
|||||||
|
|
||||||
int uart_register(FAR const char *path, FAR uart_dev_t *dev)
|
int uart_register(FAR const char *path, FAR uart_dev_t *dev)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
/* Initialize of the task that will receive SIGINT signals. */
|
/* Initialize of the task that will receive SIGINT signals. */
|
||||||
|
|
||||||
dev->pid = (pid_t)-1;
|
dev->pid = (pid_t)-1;
|
||||||
|
|||||||
+45
-22
@@ -53,58 +53,81 @@
|
|||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Name: uart_check_sigint
|
* Name: uart_check_signo
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Check if the SIGINT character is in the contiguous Rx DMA buffer region.
|
* Check if the SIGINT or SIGSTP character is in the contiguous Rx DMA buffer
|
||||||
|
* region. The first signal associated with the first such character is returned.
|
||||||
|
*
|
||||||
|
* If there multiple such characters in the buffer, only the signal associated
|
||||||
|
* with the first is returned (this a bug!)
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* 0 if a signal-related character does not appear in the. Otherwise, SIGKILL or
|
||||||
|
* SIGSTP may be returned to indicate the appropriate signal action.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
static bool uart_check_sigint(const char *buf, size_t size)
|
static int uart_check_signo(const char *buf, size_t size)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_TTY_SIGINT
|
||||||
if (buf[i] == CONFIG_TTY_SIGINT_CHAR)
|
if (buf[i] == CONFIG_TTY_SIGINT_CHAR)
|
||||||
{
|
{
|
||||||
return true;
|
return SIGINT;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_TTY_SIGSTP
|
||||||
|
if (buf[i] == CONFIG_TTY_SIGSTP_CHAR)
|
||||||
|
{
|
||||||
|
return SIGSTP;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Name: uart_recvchars_sigkill
|
* Name: uart_recvchars_signo
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Check if the SIGINT character is anywhere in the newly received DMA buffer.
|
* Check if the SIGINT character is anywhere in the newly received DMA buffer.
|
||||||
*
|
*
|
||||||
* REVISIT: We must also remove the SIGINT character from the Rx buffer. It
|
* REVISIT: We must also remove the SIGINT/SIGSTP character from the Rx buffer. It
|
||||||
* should not be read as normal data by the caller.
|
* should not be read as normal data by the caller.
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
static bool uart_recvchars_sigkill(FAR uart_dev_t *dev)
|
static int uart_recvchars_signo(FAR uart_dev_t *dev)
|
||||||
{
|
{
|
||||||
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
|
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
|
||||||
|
int signo;
|
||||||
|
|
||||||
|
/* Check if the valid DMAed data is in one or two contiguous regions */
|
||||||
|
|
||||||
if (xfer->nbytes <= xfer->length)
|
if (xfer->nbytes <= xfer->length)
|
||||||
{
|
{
|
||||||
return uart_check_sigint(xfer->buffer, xfer->nbytes);
|
return uart_check_signo(xfer->buffer, xfer->nbytes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (uart_check_sigint(xfer->buffer, xfer->length))
|
/* REVISIT: Additional signals could be in the second region. */
|
||||||
|
|
||||||
|
signo = uart_check_signo(xfer->buffer, xfer->length);
|
||||||
|
if (signo != 0)
|
||||||
{
|
{
|
||||||
return true;
|
return signo;
|
||||||
}
|
}
|
||||||
|
|
||||||
return uart_check_sigint(xfer->nbuffer, xfer->nbytes - xfer->length);
|
return uart_check_signo(xfer->nbuffer, xfer->nbytes - xfer->length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -324,14 +347,14 @@ void uart_recvchars_done(FAR uart_dev_t *dev)
|
|||||||
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
|
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
|
||||||
FAR struct uart_buffer_s *rxbuf = &dev->recv;
|
FAR struct uart_buffer_s *rxbuf = &dev->recv;
|
||||||
size_t nbytes = xfer->nbytes;
|
size_t nbytes = xfer->nbytes;
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
bool needkill = false;
|
int signo = 0;
|
||||||
|
|
||||||
/* Check if the SIGINT character is anywhere in the newly received DMA buffer. */
|
/* Check if the SIGINT character is anywhere in the newly received DMA buffer. */
|
||||||
|
|
||||||
if (dev->pid >= 0 && uart_recvchars_sigkill(dev))
|
if (dev->pid >= 0)
|
||||||
{
|
{
|
||||||
needkill = true;
|
signo = uart_recvchars_signo(dev);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -350,12 +373,12 @@ void uart_recvchars_done(FAR uart_dev_t *dev)
|
|||||||
uart_datareceived(dev);
|
uart_datareceived(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
/* Send the SIGINT signal if needed */
|
/* Send the signal if necessary */
|
||||||
|
|
||||||
if (needkill)
|
if (signo != 0)
|
||||||
{
|
{
|
||||||
kill(dev->pid, SIGINT);
|
kill(dev->pid, signo);
|
||||||
uart_reset_sem(dev);
|
uart_reset_sem(dev);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -122,12 +122,12 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
FAR struct uart_buffer_s *rxbuf = &dev->recv;
|
FAR struct uart_buffer_s *rxbuf = &dev->recv;
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
unsigned int watermark;
|
unsigned int watermark;
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
|
||||||
bool needkill = false;
|
|
||||||
#endif
|
#endif
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
int nexthead = rxbuf->head + 1;
|
int nexthead = rxbuf->head + 1;
|
||||||
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
|
int signo = 0;
|
||||||
|
#endif
|
||||||
uint16_t nbytes = 0;
|
uint16_t nbytes = 0;
|
||||||
|
|
||||||
if (nexthead >= rxbuf->size)
|
if (nexthead >= rxbuf->size)
|
||||||
@@ -136,7 +136,7 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
/* Pre-calcuate the watermark level that we will need to test against. */
|
/* Pre-calculate the watermark level that we will need to test against. */
|
||||||
|
|
||||||
watermark = (CONFIG_SERIAL_IFLOWCONTROL_UPPER_WATERMARK * rxbuf->size) / 100;
|
watermark = (CONFIG_SERIAL_IFLOWCONTROL_UPPER_WATERMARK * rxbuf->size) / 100;
|
||||||
#endif
|
#endif
|
||||||
@@ -210,7 +210,27 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
* into the Rx buffer. It should not be read as normal data.
|
* into the Rx buffer. It should not be read as normal data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
needkill = true;
|
signo = SIGINT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_TTY_SIGSTP
|
||||||
|
/* Is this the special character that will generate the SIGSTP signal? */
|
||||||
|
|
||||||
|
if (dev->pid >= 0 && ch == CONFIG_TTY_SIGSTP_CHAR)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_TTY_SIGINT
|
||||||
|
/* Give precedence to SIGINT */
|
||||||
|
|
||||||
|
if (signo == 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* Note that the kill is needed and do not put the character
|
||||||
|
* into the Rx buffer. It should not be read as normal data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
signo = SIGSTP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
@@ -249,12 +269,12 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
uart_datareceived(dev);
|
uart_datareceived(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
/* Send the SIGINT signal if needed */
|
/* Send the signal if necessary */
|
||||||
|
|
||||||
if (needkill)
|
if (signo != 0)
|
||||||
{
|
{
|
||||||
kill(dev->pid, SIGINT);
|
kill(dev->pid, signo);
|
||||||
uart_reset_sem(dev);
|
uart_reset_sem(dev);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -286,8 +286,8 @@ struct uart_dev_s
|
|||||||
tcflag_t tc_iflag; /* Input modes */
|
tcflag_t tc_iflag; /* Input modes */
|
||||||
tcflag_t tc_oflag; /* Output modes */
|
tcflag_t tc_oflag; /* Output modes */
|
||||||
tcflag_t tc_lflag; /* Local modes */
|
tcflag_t tc_lflag; /* Local modes */
|
||||||
#ifdef CONFIG_TTY_SIGINT
|
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGSTP)
|
||||||
pid_t pid; /* Thread PID to receive SIGINT signals (-1 if none) */
|
pid_t pid; /* Thread PID to receive signals (-1 if none) */
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -240,6 +241,12 @@ static void nxsig_abnormal_termination(int signo)
|
|||||||
static void nxsig_stop_task(int signo)
|
static void nxsig_stop_task(int signo)
|
||||||
{
|
{
|
||||||
FAR struct tcb_s *rtcb = (FAR struct tcb_s *)this_task();
|
FAR struct tcb_s *rtcb = (FAR struct tcb_s *)this_task();
|
||||||
|
#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)
|
||||||
|
FAR struct task_group_s *group;
|
||||||
|
|
||||||
|
DEBUGASSERT(rtcb != NULL && rtcb->group != NULL);
|
||||||
|
group = rtcb->group;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Careful: In the multi-threaded task, the signal may be handled on a
|
/* Careful: In the multi-threaded task, the signal may be handled on a
|
||||||
* child pthread.
|
* child pthread.
|
||||||
@@ -254,7 +261,7 @@ static void nxsig_stop_task(int signo)
|
|||||||
group_suspendchildren(rtcb);
|
group_suspendchildren(rtcb);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Lock the scheudler so this thread is not pre-empted until after we
|
/* Lock the scheduler so this thread is not pre-empted until after we
|
||||||
* call sched_suspend().
|
* call sched_suspend().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -266,7 +273,7 @@ static void nxsig_stop_task(int signo)
|
|||||||
* waitpid flags.
|
* waitpid flags.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (group->tg_waitflags & WUNTRACED) != 0)
|
if ((group->tg_waitflags & WUNTRACED) != 0)
|
||||||
{
|
{
|
||||||
/* Return zero for exit status (we are not exiting, however) */
|
/* Return zero for exit status (we are not exiting, however) */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user