summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/Makefile.am1
-rw-r--r--cpukit/include/rtems/libio.h116
-rw-r--r--cpukit/include/rtems/rtems/status.h9
-rw-r--r--cpukit/libcsupport/src/termios.c225
-rw-r--r--cpukit/libcsupport/src/termios_posix_isig_handler.c39
-rw-r--r--cpukit/rtems/src/statustext.c1
-rw-r--r--cpukit/rtems/src/statustoerrno.c1
-rw-r--r--testsuites/libtests/Makefile.am22
-rw-r--r--testsuites/libtests/configure.ac2
-rw-r--r--testsuites/libtests/termios10/init.c191
-rw-r--r--testsuites/libtests/termios10/termios10.doc23
-rw-r--r--testsuites/libtests/termios10/termios10.scn14
-rw-r--r--testsuites/libtests/termios11/termios11.doc23
-rw-r--r--testsuites/libtests/termios11/termios11.scn14
14 files changed, 634 insertions, 47 deletions
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 01ee40980f..7698fe5482 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -250,6 +250,7 @@ librtemscpu_a_SOURCES += libcsupport/src/termios_baudtable.c
librtemscpu_a_SOURCES += libcsupport/src/termios.c
librtemscpu_a_SOURCES += libcsupport/src/termiosinitialize.c
librtemscpu_a_SOURCES += libcsupport/src/termios_num2baud.c
+librtemscpu_a_SOURCES += libcsupport/src/termios_posix_isig_handler.c
librtemscpu_a_SOURCES += libcsupport/src/termios_setbestbaud.c
librtemscpu_a_SOURCES += libcsupport/src/termios_setinitialbaud.c
librtemscpu_a_SOURCES += libcsupport/src/__times.c
diff --git a/cpukit/include/rtems/libio.h b/cpukit/include/rtems/libio.h
index f3b0f2cbf9..b5362320e8 100644
--- a/cpukit/include/rtems/libio.h
+++ b/cpukit/include/rtems/libio.h
@@ -1880,6 +1880,8 @@ extern const rtems_filesystem_mount_configuration
*/
/**@{**/
+struct rtems_termios_tty;
+
typedef struct rtems_termios_callbacks {
int (*firstOpen)(int major, int minor, void *arg);
int (*lastClose)(int major, int minor, void *arg);
@@ -1907,6 +1909,114 @@ rtems_status_code rtems_termios_bufsize (
size_t raw_output /* raw output buffer size */
);
+/**
+ * @brief Type returned by all input processing (isig) methods
+ */
+typedef enum {
+ /**
+ * This indicates that the input character was processed
+ * and possibly placed into the buffer.
+ */
+ RTEMS_TERMIOS_ISIG_WAS_PROCESSED,
+ /**
+ * This indicates that the input character was not processed and
+ * subsequent processing is required.
+ */
+ RTEMS_TERMIOS_ISIG_WAS_NOT_PROCESSED,
+ /**
+ * This indicates that the character was processed and determined
+ * to be one that requires a signal to be raised (e.g. VINTR or
+ * VKILL). The tty must be in the right termios mode for this to
+ * occur. There is no further processing of this character required and
+ * the pending read() operation should be interrupted.
+ */
+ RTEMS_TERMIOS_ISIG_INTERRUPT_READ
+} rtems_termios_isig_status_code;
+
+/**
+ * @brief Type for ISIG (VINTR/VKILL) handler
+ *
+ * This type defines the interface to a method which will process
+ * VKILL and VINTR characters. The user can register a handler to
+ * override the default behavior which is to take no special action
+ * on these characters. The POSIX required behavior is to
+ * generate a SIGINTR or SIGQUIT signal. This behavior is implemented if
+ * the user registers the @ref rtems_termios_posix_isig_handler().
+ *
+ * @param c character that was input
+ * @param tty termios structure pointer for this input tty
+ *
+ * @return The value returned is according to that documented
+ * for @ref rtems_termios_isig_status_code.
+ */
+typedef rtems_termios_isig_status_code (*rtems_termios_isig_handler)(
+ unsigned char c,
+ struct rtems_termios_tty *tty
+);
+
+/**
+ * @brief Default handler for ISIG (VINTR/VKILL)
+ *
+ * This handler is installed by default by termios. It performs
+ * no actions on receiving the VINTR and VKILL characters. This is
+ * not POSIX conformant behavior but is the historical RTEMS behavior
+ * and avoid any default dependency on signal processing code.
+ *
+ * @param c character that was input
+ * @param tty termios structure pointer for this input tty
+ *
+ * The installed ISIG handler is only invoked if the character is
+ * (VKILL or VINTR) and ISIG is enabled. Thus the handler need only
+ * check the character and perform the appropriate action.
+ *
+ * @return The value returned is according to that documented
+ * for all methods adhering to @ref rtems_termios_isig_handler.
+ */
+rtems_termios_isig_status_code rtems_termios_default_isig_handler(
+ unsigned char c,
+ struct rtems_termios_tty *tty
+);
+
+/**
+ * @brief POSIX handler for ISIG (VINTR/VKILL)
+ *
+ * This handler is installed by the used to obtain POSIX behavior
+ * upon receiving the VINTR and VKILL characters. The POSIX required
+ * behavior is to generate a SIGINTR or SIGQUIT signal if ISIG is enabled.
+ *
+ * @param c character that was input
+ * @param tty termios structure pointer for this input tty
+ *
+ * @return The value returned is according to that documented
+ * for all methods adhering to @ref rtems_termios_isig_handler.
+ */
+rtems_termios_isig_status_code rtems_termios_posix_isig_handler(
+ unsigned char c,
+ struct rtems_termios_tty *tty
+);
+
+/**
+ * @brief Register handler for ISIG (VINTR/VKILL)
+ *
+ * This method is invoked to install an ISIG handler. This may be used
+ * to install @ref rtems_termios_posix_isig_handler() to obtain POSIX
+ * behavior or a custom handler. The handler
+ * @ref rtems_termios_default_isig_handler() is installed by default.
+ *
+ * @param handler entry point of the new ISIG handler
+ *
+ * @retval RTEMS_SUCCESSFUL if successful or error code if unsuccessful.
+ */
+rtems_status_code rtems_termios_register_isig_handler(
+ rtems_termios_isig_handler handler
+);
+
+int rtems_termios_enqueue_raw_characters(
+ void *ttyp,
+ const char *buf,
+ int len
+);
+
rtems_status_code rtems_termios_open (
rtems_device_major_number major,
rtems_device_minor_number minor,
@@ -1930,12 +2040,6 @@ rtems_status_code rtems_termios_ioctl(
void *arg
);
-int rtems_termios_enqueue_raw_characters(
- void *ttyp,
- const char *buf,
- int len
-);
-
int rtems_termios_dequeue_characters(
void *ttyp,
int len
diff --git a/cpukit/include/rtems/rtems/status.h b/cpukit/include/rtems/rtems/status.h
index 88ae576eac..7310fe905b 100644
--- a/cpukit/include/rtems/rtems/status.h
+++ b/cpukit/include/rtems/rtems/status.h
@@ -167,6 +167,12 @@ typedef enum {
*/
RTEMS_IO_ERROR = 27,
/**
+ * This is the status used internally to indicate a blocking device
+ * driver call has been interrupted and should be reflected to the
+ * called as an INTERRUPTED.
+ */
+ RTEMS_INTERRUPTED = 28,
+ /**
* This is the status is used internally to RTEMS when performing
* operations on behalf of remote tasks. This is referred to as
* proxying operations and this status indicates that the operation
@@ -174,7 +180,7 @@ typedef enum {
*
* @note This status will @b NOT be returned to the user.
*/
- RTEMS_PROXY_BLOCKING = 28
+ RTEMS_PROXY_BLOCKING = 29
} rtems_status_code;
/**
@@ -235,6 +241,7 @@ RTEMS_INLINE_ROUTINE bool rtems_are_statuses_equal(
* @retval ENODEV RTEMS_UNSATISFIED
* @retval ENOSYS RTEMS_NOT_IMPLEMENTED, RTEMS_NOT_CONFIGURED
* @retval ENOMEM RTEMS_NO_MEMORY
+ * @retval EINTR RTEMS_INTERRUPTED
*/
int rtems_status_code_to_errno(rtems_status_code sc);
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index 0fc9de452b..fedaa80ba0 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -1301,76 +1301,169 @@ iprocEarly (unsigned char c, rtems_termios_tty *tty)
}
/*
+ * This points to the currently registered method to perform
+ * ISIG processing of VKILL and VQUIT characters.
+ */
+static rtems_termios_isig_handler termios_isig_handler =
+ rtems_termios_default_isig_handler;
+
+/*
+ * This is the default method to process VKILL or VQUIT characters if
+ * ISIG processing is enabled. Note that it does nothing.
+ */
+rtems_termios_isig_status_code rtems_termios_default_isig_handler(
+ unsigned char c,
+ struct rtems_termios_tty *tty
+)
+{
+ return RTEMS_TERMIOS_ISIG_WAS_NOT_PROCESSED;
+}
+
+/*
+ * Register a method to process VKILL or VQUIT characters if
+ * ISIG processing is enabled.
+ */
+rtems_status_code rtems_termios_register_isig_handler(
+ rtems_termios_isig_handler handler
+)
+{
+ if (handler == NULL) {
+ return RTEMS_INVALID_ADDRESS;
+ }
+
+ termios_isig_handler = handler;
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Type returned by all input processing (iproc) methods
+ */
+typedef enum {
+ /**
+ * This indicates that the input character was processed
+ * and the results were placed into the buffer.
+ */
+ RTEMS_TERMIOS_IPROC_IN_BUFFER,
+ /**
+ * This indicates that the input character was processed
+ * and the result did not go into the buffer.
+ */
+ RTEMS_TERMIOS_IPROC_WAS_PROCESSED,
+ /**
+ * This indicates that the input character was not processed and
+ * subsequent processing is required.
+ */
+ RTEMS_TERMIOS_IPROC_WAS_NOT_PROCESSED,
+ /**
+ * This indicates that the character was processed and determined
+ * to be one that requires a signal to be raised (e.g. VINTR or
+ * VKILL). The tty must be in the right termios mode for this to
+ * occur. There is no further processing of this character required and
+ * the pending read() operation should be interrupted.
+ */
+ RTEMS_TERMIOS_IPROC_INTERRUPT_READ
+} rtems_termios_iproc_status_code;
+
+/*
* Process a single input character
*/
-static int
+static rtems_termios_iproc_status_code
iproc (unsigned char c, struct rtems_termios_tty *tty)
{
+ /*
+ * If signals are enabled, then allow possibility of VINTR causing
+ * SIGINTR and VQUIT causing SIGQUIT. Invoke user provided isig handler.
+ */
+ if ((tty->termios.c_lflag & ISIG)) {
+ if ((c == tty->termios.c_cc[VINTR]) || (c == tty->termios.c_cc[VQUIT])) {
+ rtems_termios_isig_status_code rc;
+ rc = (*termios_isig_handler)(c, tty);
+ if (rc == RTEMS_TERMIOS_ISIG_INTERRUPT_READ) {
+ return RTEMS_TERMIOS_IPROC_INTERRUPT_READ;
+ }
+ if (rc == RTEMS_TERMIOS_ISIG_WAS_PROCESSED) {
+ return RTEMS_TERMIOS_IPROC_IN_BUFFER;
+ }
+ _Assert(rc == RTEMS_TERMIOS_ISIG_WAS_NOT_PROCESSED);
+ }
+ }
+
+ /*
+ * Perform canonical character processing.
+ */
if ((c != '\0') && (tty->termios.c_lflag & ICANON)) {
if (c == tty->termios.c_cc[VERASE]) {
erase (tty, 0);
- return 0;
+ return RTEMS_TERMIOS_IPROC_WAS_PROCESSED;
}
else if (c == tty->termios.c_cc[VKILL]) {
erase (tty, 1);
- return 0;
+ return RTEMS_TERMIOS_IPROC_WAS_PROCESSED;
}
else if (c == tty->termios.c_cc[VEOF]) {
- return 1;
+ return RTEMS_TERMIOS_IPROC_IN_BUFFER;
} else if (c == '\n') {
if (tty->termios.c_lflag & (ECHO | ECHONL))
echo (c, tty);
tty->cbuf[tty->ccount++] = c;
- return 1;
+ return RTEMS_TERMIOS_IPROC_IN_BUFFER;
} else if ((c == tty->termios.c_cc[VEOL]) ||
(c == tty->termios.c_cc[VEOL2])) {
if (tty->termios.c_lflag & ECHO)
echo (c, tty);
tty->cbuf[tty->ccount++] = c;
- return 1;
+ return RTEMS_TERMIOS_IPROC_IN_BUFFER;
}
}
/*
+ * Perform non-canonical character processing.
+ *
* FIXME: Should do IMAXBEL handling somehow
*/
if (tty->ccount < (CBUFSIZE-1)) {
if (tty->termios.c_lflag & ECHO)
echo (c, tty);
tty->cbuf[tty->ccount++] = c;
+ return RTEMS_TERMIOS_IPROC_IN_BUFFER;
}
- return 0;
+ return RTEMS_TERMIOS_IPROC_WAS_NOT_PROCESSED;
}
/*
* Process input character, with semaphore.
*/
-static int
+static rtems_termios_iproc_status_code
siproc (unsigned char c, struct rtems_termios_tty *tty)
{
- int i;
+ rtems_termios_iproc_status_code rc;
/*
* Obtain output semaphore if character will be echoed
*/
if (tty->termios.c_lflag & (ECHO|ECHOE|ECHOK|ECHONL|ECHOPRT|ECHOCTL|ECHOKE)) {
rtems_mutex_lock (&tty->osem);
- i = iproc (c, tty);
+ rc = iproc (c, tty);
rtems_mutex_unlock (&tty->osem);
}
else {
- i = iproc (c, tty);
+ rc = iproc (c, tty);
}
- return i;
+ return rc;
}
-static int
+static rtems_termios_iproc_status_code
siprocPoll (unsigned char c, rtems_termios_tty *tty)
{
if (c == '\r' && (tty->termios.c_iflag & IGNCR) != 0) {
- return 0;
+ return RTEMS_TERMIOS_IPROC_WAS_NOT_PROCESSED;
}
+ /*
+ * iprocEarly is done at the interrupt level for interrupt driven
+ * devices so we need to perform those actions before processing
+ * the character.
+ */
c = iprocEarly (c, tty);
return siproc (c, tty);
}
@@ -1378,10 +1471,12 @@ siprocPoll (unsigned char c, rtems_termios_tty *tty)
/*
* Fill the input buffer by polling the device
*/
-static void
+static rtems_termios_iproc_status_code
fillBufferPoll (struct rtems_termios_tty *tty)
{
- int n;
+ int n;
+ rtems_termios_iproc_status_code rc;
+ rtems_termios_iproc_status_code retval = RTEMS_TERMIOS_IPROC_WAS_PROCESSED;
if (tty->termios.c_lflag & ICANON) {
for (;;) {
@@ -1389,8 +1484,14 @@ fillBufferPoll (struct rtems_termios_tty *tty)
if (n < 0) {
rtems_task_wake_after (1);
} else {
- if (siprocPoll (n, tty))
+ rc = siprocPoll (n, tty);
+ if (rc == RTEMS_TERMIOS_IPROC_IN_BUFFER) {
+ break;
+ }
+ if (rc == RTEMS_TERMIOS_IPROC_INTERRUPT_READ) {
+ retval = RTEMS_TERMIOS_IPROC_INTERRUPT_READ;
break;
+ }
}
}
} else {
@@ -1417,7 +1518,11 @@ fillBufferPoll (struct rtems_termios_tty *tty)
}
rtems_task_wake_after (1);
} else {
- siprocPoll (n, tty);
+ rc = siprocPoll (n, tty);
+ if (rc == RTEMS_TERMIOS_IPROC_INTERRUPT_READ) {
+ retval = RTEMS_TERMIOS_IPROC_INTERRUPT_READ;
+ break;
+ }
if (tty->ccount >= tty->termios.c_cc[VMIN])
break;
if (tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])
@@ -1425,12 +1530,13 @@ fillBufferPoll (struct rtems_termios_tty *tty)
}
}
}
+ return retval;
}
/*
* Fill the input buffer from the raw input queue
*/
-static void
+static rtems_termios_iproc_status_code
fillBufferQueue (struct rtems_termios_tty *tty)
{
rtems_termios_device_context *ctx = tty->device_context;
@@ -1448,8 +1554,9 @@ fillBufferQueue (struct rtems_termios_tty *tty)
while ((tty->rawInBuf.Head != tty->rawInBuf.Tail) &&
(tty->ccount < (CBUFSIZE-1))) {
- unsigned char c;
- unsigned int newHead;
+ unsigned char c;
+ unsigned int newHead;
+ rtems_termios_iproc_status_code rc;
newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
c = tty->rawInBuf.theBuf[newHead];
@@ -1479,12 +1586,21 @@ fillBufferQueue (struct rtems_termios_tty *tty)
/* continue processing new character */
if (tty->termios.c_lflag & ICANON) {
- if (siproc (c, tty)) {
- /* In canonical mode, input is made available line by line */
- return;
+ rc = siproc (c, tty);
+ /* If the read() should be interrupted, return */
+ if (rc == RTEMS_TERMIOS_IPROC_INTERRUPT_READ) {
+ return RTEMS_TERMIOS_IPROC_INTERRUPT_READ;
+ }
+ /* In canonical mode, input is made available line by line */
+ if (rc == RTEMS_TERMIOS_IPROC_IN_BUFFER) {
+ return RTEMS_TERMIOS_IPROC_IN_BUFFER;
}
} else {
- siproc (c, tty);
+ rc = siproc (c, tty);
+ /* If the read() should be interrupted, return */
+ if (rc == RTEMS_TERMIOS_IPROC_INTERRUPT_READ) {
+ return RTEMS_TERMIOS_IPROC_INTERRUPT_READ;
+ }
if (tty->ccount >= tty->termios.c_cc[VMIN])
wait = false;
}
@@ -1519,13 +1635,19 @@ fillBufferQueue (struct rtems_termios_tty *tty)
}
}
}
+ return RTEMS_TERMIOS_IPROC_WAS_PROCESSED;
}
-static uint32_t
-rtems_termios_read_tty (struct rtems_termios_tty *tty, char *buffer,
- uint32_t initial_count)
+static rtems_status_code
+rtems_termios_read_tty (
+ struct rtems_termios_tty *tty,
+ char *buffer,
+ uint32_t initial_count,
+ uint32_t *count_read
+)
{
- uint32_t count;
+ uint32_t count;
+ rtems_termios_iproc_status_code rc = RTEMS_TERMIOS_IPROC_WAS_PROCESSED;
count = initial_count;
@@ -1533,28 +1655,43 @@ rtems_termios_read_tty (struct rtems_termios_tty *tty, char *buffer,
tty->cindex = tty->ccount = 0;
tty->read_start_column = tty->column;
if (tty->handler.poll_read != NULL && tty->handler.mode == TERMIOS_POLLED)
- fillBufferPoll (tty);
+ rc = fillBufferPoll (tty);
else
- fillBufferQueue (tty);
+ rc = fillBufferQueue (tty);
}
+
+ /*
+ * If there are characters in the buffer, then copy them to the caller.
+ */
while (count && (tty->cindex < tty->ccount)) {
*buffer++ = tty->cbuf[tty->cindex++];
count--;
- }
+ }
tty->tty_rcvwakeup = false;
- return initial_count - count;
+ *count_read = initial_count - count;
+
+ /*
+ * fillBufferPoll and fillBufferQueue can indicate that the operation
+ * was interrupted. The isig handler can do nothing, have POSIX behavior
+ * and cause a signal, or a user defined action.
+ */
+ if (rc == RTEMS_TERMIOS_IPROC_INTERRUPT_READ) {
+ return RTEMS_INTERRUPTED;
+ }
+
+ return RTEMS_SUCCESSFUL;
}
rtems_status_code
rtems_termios_read (void *arg)
{
- rtems_libio_rw_args_t *args = arg;
+ rtems_libio_rw_args_t *args = arg;
struct rtems_termios_tty *tty = args->iop->data1;
+ rtems_status_code sc;
rtems_mutex_lock (&tty->isem);
if (rtems_termios_linesw[tty->t_line].l_read != NULL) {
- rtems_status_code sc;
sc = rtems_termios_linesw[tty->t_line].l_read(tty,args);
tty->tty_rcvwakeup = false;
@@ -1562,9 +1699,14 @@ rtems_termios_read (void *arg)
return sc;
}
- args->bytes_moved = rtems_termios_read_tty (tty, args->buffer, args->count);
+ sc = rtems_termios_read_tty(
+ tty,
+ args->buffer,
+ args->count,
+ &args->bytes_moved
+ );
rtems_mutex_unlock (&tty->isem);
- return RTEMS_SUCCESSFUL;
+ return sc;
}
/*
@@ -2022,7 +2164,8 @@ static ssize_t
rtems_termios_imfs_read (rtems_libio_t *iop, void *buffer, size_t count)
{
struct rtems_termios_tty *tty;
- uint32_t bytes_moved;
+ uint32_t bytes_moved;
+ rtems_status_code sc;
tty = iop->data1;
@@ -2049,9 +2192,13 @@ rtems_termios_imfs_read (rtems_libio_t *iop, void *buffer, size_t count)
return (ssize_t) args.bytes_moved;
}
- bytes_moved = rtems_termios_read_tty (tty, buffer, count);
+ sc = rtems_termios_read_tty(tty, buffer, count, &bytes_moved);
rtems_mutex_unlock (&tty->isem);
+ if (sc != RTEMS_SUCCESSFUL) {
+ return rtems_status_code_to_errno (sc);
+ }
return (ssize_t) bytes_moved;
+
}
static ssize_t
diff --git a/cpukit/libcsupport/src/termios_posix_isig_handler.c b/cpukit/libcsupport/src/termios_posix_isig_handler.c
new file mode 100644
index 0000000000..105e7f463d
--- /dev/null
+++ b/cpukit/libcsupport/src/termios_posix_isig_handler.c
@@ -0,0 +1,39 @@
+/**
+ * @file
+ * TERMIOS POSIX behavior on INTR and QUIT characters
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2012,2019.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+
+#include <signal.h>
+
+rtems_termios_isig_status_code rtems_termios_posix_isig_handler(
+ unsigned char c,
+ struct rtems_termios_tty *tty
+)
+{
+ if (c == tty->termios.c_cc[VINTR]) {
+ raise(SIGINT);
+ return RTEMS_TERMIOS_ISIG_INTERRUPT_READ;
+ }
+
+ if (c == tty->termios.c_cc[VQUIT]) {
+ raise(SIGQUIT);
+ return RTEMS_TERMIOS_ISIG_INTERRUPT_READ;
+ }
+
+ return RTEMS_TERMIOS_ISIG_WAS_NOT_PROCESSED;
+}
diff --git a/cpukit/rtems/src/statustext.c b/cpukit/rtems/src/statustext.c
index f701ebd356..23697942fd 100644
--- a/cpukit/rtems/src/statustext.c
+++ b/cpukit/rtems/src/statustext.c
@@ -53,6 +53,7 @@ static const char *const status_code_text[] = {
"RTEMS_INTERNAL_ERROR",
"RTEMS_NO_MEMORY",
"RTEMS_IO_ERROR",
+ "RTEMS_INTERRUPTED",
"RTEMS_PROXY_BLOCKING"
};
diff --git a/cpukit/rtems/src/statustoerrno.c b/cpukit/rtems/src/statustoerrno.c
index 8f34ff5921..76a9e2c056 100644
--- a/cpukit/rtems/src/statustoerrno.c
+++ b/cpukit/rtems/src/statustoerrno.c
@@ -45,6 +45,7 @@ static const int status_code_to_errno [RTEMS_STATUS_CODES_LAST + 1] = {
[RTEMS_INTERNAL_ERROR] = EIO,
[RTEMS_NO_MEMORY] = ENOMEM,
[RTEMS_IO_ERROR] = EIO,
+ [RTEMS_INTERRUPTED] = EINTR,
[RTEMS_PROXY_BLOCKING] = EIO
};
diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am
index 1b80283123..20a5a6fc5e 100644
--- a/testsuites/libtests/Makefile.am
+++ b/testsuites/libtests/Makefile.am
@@ -1489,7 +1489,27 @@ lib_screens += termios09/termios09.scn
lib_docs += termios09/termios09.doc
termios09_SOURCES = termios09/init.c
termios09_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_termios09) \
- $(support_includes)
+ $(support_includes)
+endif
+
+if TEST_termios10
+lib_tests += termios10
+lib_screens += termios10/termios10.scn
+lib_docs += termios10/termios10.doc
+termios10_SOURCES = termios10/init.c
+termios10_SOURCES += termios03/termios_testdriver_polled.c
+termios10_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_termios10) \
+ $(support_includes) -I$(top_srcdir)/termios03
+endif
+
+if TEST_termios11
+lib_tests += termios11
+lib_screens += termios11/termios11.scn
+lib_docs += termios11/termios11.doc
+termios11_SOURCES = termios10/init.c
+termios11_SOURCES += termios04/termios_testdriver_intr.c
+termios11_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_termios11) \
+ $(support_includes) -I$(top_srcdir)/termios04 -DINTERRUPT_DRIVEN
endif
if TEST_top
diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac
index c02b42a5f9..4d0707c219 100644
--- a/testsuites/libtests/configure.ac
+++ b/testsuites/libtests/configure.ac
@@ -225,6 +225,8 @@ RTEMS_TEST_CHECK([termios06])
RTEMS_TEST_CHECK([termios07])
RTEMS_TEST_CHECK([termios08])
RTEMS_TEST_CHECK([termios09])
+RTEMS_TEST_CHECK([termios10])
+RTEMS_TEST_CHECK([termios11])
RTEMS_TEST_CHECK([top])
RTEMS_TEST_CHECK([ttest01])
RTEMS_TEST_CHECK([tztest])
diff --git a/testsuites/libtests/termios10/init.c b/testsuites/libtests/termios10/init.c
new file mode 100644
index 0000000000..ca5de97f24
--- /dev/null
+++ b/testsuites/libtests/termios10/init.c
@@ -0,0 +1,191 @@
+/*
+ * COPYRIGHT (c) 1989-2012,2019.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tmacros.h>
+#include "test_support.h"
+
+#ifdef INTERRUPT_DRIVEN
+#include "termios_testdriver_intr.h"
+const char rtems_test_name[] = "TERMIOS 11 -- Interrupt driven";
+#else
+#include "termios_testdriver_polled.h"
+const char rtems_test_name[] = "TERMIOS 10 -- Polled";
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <termios.h>
+#include <rtems/dumpbuf.h>
+#include <rtems/libio.h>
+
+int Test_fd;
+
+static void open_it(void)
+{
+ Test_fd = open( TERMIOS_TEST_DRIVER_DEVICE_NAME, O_RDWR );
+ rtems_test_assert( Test_fd != -1 );
+}
+
+static void change_lflag( const char *desc, int mask, int new )
+{
+ int rc;
+ struct termios attr;
+
+ if (desc) {
+ printf( "Changing c_lflag to: %s\n", desc );
+ }
+
+ rc = tcgetattr( Test_fd, &attr );
+ rtems_test_assert( rc == 0 );
+
+ attr.c_lflag &= ~mask;
+ attr.c_lflag |= new;
+
+ rc = tcsetattr( Test_fd, TCSANOW, &attr );
+ rtems_test_assert( rc == 0 );
+}
+
+
+static void read_it(ssize_t expected, int expected_intr)
+{
+ ssize_t rc;
+ char buf[32];
+
+ rtems_test_assert( expected <= sizeof(buf) );
+
+ rc = read( Test_fd, buf, expected );
+ if (expected_intr) {
+ rtems_test_assert( rc == -1 );
+ rtems_test_assert( errno == EINTR );
+ } else {
+ if ( expected != rc )
+ printf( "ERROR - expected=%zd rc=%zd\n", expected, rc );
+ rtems_test_assert( expected == rc );
+ }
+}
+
+static void close_it(void)
+{
+ int rc;
+
+ rc = close( Test_fd );
+ rtems_test_assert( rc == 0 );
+}
+
+volatile int sigint_occurred = 0;
+volatile int sigquit_occurred = 0;
+
+static void sigint_handler(int signo)
+{
+ rtems_test_assert(signo == SIGINT);
+ sigint_occurred = 1;
+}
+
+static void sigquit_handler(int signo)
+{
+ rtems_test_assert(signo == SIGQUIT);
+ sigquit_occurred = 1;
+}
+
+static void test_read_for_signal(
+ const char *description,
+ int isig_value,
+ char c,
+ int sigint_expected,
+ int sigquit_expected
+)
+{
+ char expected[3];
+
+ printf("Test read for %s\n", description);
+
+ expected[0] = c;
+ expected[1] = '\n'; /* in canonical mode, so need \n for read to return */
+ expected[2] = '\0';
+
+ sigint_occurred = 0;
+ sigquit_occurred = 0;
+
+ open_it();
+
+ change_lflag(NULL, ISIG, isig_value);
+
+ termios_test_driver_set_rx( expected, 2 );
+
+ read_it(1, (sigint_expected || sigquit_expected));
+
+ rtems_test_assert(sigint_occurred == sigint_expected);
+ rtems_test_assert(sigquit_occurred == sigquit_expected);
+ close_it();
+}
+
+/*
+ * Use a POSIX init thread so signals are enabled.
+ */
+static void *POSIX_Init(void *argument)
+{
+ int rc;
+
+ TEST_BEGIN();
+
+ signal(SIGINT, sigint_handler);
+ signal(SIGQUIT, sigquit_handler);
+
+ puts( "Exercise default ISIG handler with ISIG enabled");
+ test_read_for_signal("VKILL - no signals", ISIG, '\003', 0, 0);
+ test_read_for_signal("VQUIT - no signals", ISIG, '\034', 0, 0);
+
+ puts( "Exercise POSIX ISIG handler with ISIG enabled");
+ rc = rtems_termios_register_isig_handler(rtems_termios_posix_isig_handler);
+ rtems_test_assert( rc == 0 );
+ test_read_for_signal("VKILL - signal caught", ISIG, '\003', 1, 0);
+ test_read_for_signal("VQUIT - signal caught", ISIG, '\034', 0, 1);
+
+ puts( "Exercise default ISIG handler with ISIG enabled");
+ rc = rtems_termios_register_isig_handler(rtems_termios_default_isig_handler);
+ rtems_test_assert( rc == 0 );
+ test_read_for_signal("VKILL - signal caught", ISIG, '\003', 0, 0);
+ test_read_for_signal("VQUIT - signal caught", ISIG, '\034', 0, 0);
+
+ puts( "Exercise POSIX ISIG handler with ISIG disabled");
+ rc = rtems_termios_register_isig_handler(rtems_termios_posix_isig_handler);
+ rtems_test_assert( rc == 0 );
+ test_read_for_signal("VKILL - signal caught", 0, '\003', 0, 0);
+ test_read_for_signal("VQUIT - signal caught", 0, '\034', 0, 0);
+
+ TEST_END();
+
+ rtems_test_exit(0);
+}
+
+/* configuration information */
+
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_EXTRA_DRIVERS \
+ TERMIOS_TEST_DRIVER_TABLE_ENTRY
+
+/* we need to be able to open the test device */
+#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4
+#define CONFIGURE_MAXIMUM_POSIX_THREADS 1
+#define CONFIGURE_MAXIMUM_TIMERS 2
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_POSIX_INIT_THREAD_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
+/* end of file */
diff --git a/testsuites/libtests/termios10/termios10.doc b/testsuites/libtests/termios10/termios10.doc
new file mode 100644
index 0000000000..c98e5ca8b1
--- /dev/null
+++ b/testsuites/libtests/termios10/termios10.doc
@@ -0,0 +1,23 @@
+# COPYRIGHT (c) 2019.
+# On-Line Applications Research Corporation (OAR).
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+test name: termios10
+
+directives:
+ rtems_termios_register_isig_handler
+
+concepts:
+
++ Verifies signals are not delivered on QUIT and INTR characters
+ as default behavior.
+
++ Verified that signals are delivered when QUIT or INTR characters
+ are entered after rtems_termios_posix_isig_handler()
+ is registered using rtems_termios_register_isig_handler().
+
++ Verifies signals are not delivered on QUIT and INTR characters
+ after the default handler rtems_termios_default_isig_handler()
+ is registered using rtems_termios_register_isig_handler().
diff --git a/testsuites/libtests/termios10/termios10.scn b/testsuites/libtests/termios10/termios10.scn
new file mode 100644
index 0000000000..198752850e
--- /dev/null
+++ b/testsuites/libtests/termios10/termios10.scn
@@ -0,0 +1,14 @@
+*** BEGIN OF TEST TERMIOS 10 -- Polled ***
+Exercise default ISIG handler with ISIG enabled
+Test read for VKILL - no signals
+Test read for VQUIT - no signals
+Exercise POSIX ISIG handler with ISIG enabled
+Test read for VKILL - signal caught
+Test read for VQUIT - signal caught
+Exercise default ISIG handler with ISIG enabled
+Test read for VKILL - signal caught
+Test read for VQUIT - signal caught
+Exercise POSIX ISIG handler with ISIG disabled
+Test read for VKILL - signal caught
+Test read for VQUIT - signal caught
+*** END OF TEST TERMIOS 10 -- Polled ***
diff --git a/testsuites/libtests/termios11/termios11.doc b/testsuites/libtests/termios11/termios11.doc
new file mode 100644
index 0000000000..c98e5ca8b1
--- /dev/null
+++ b/testsuites/libtests/termios11/termios11.doc
@@ -0,0 +1,23 @@
+# COPYRIGHT (c) 2019.
+# On-Line Applications Research Corporation (OAR).
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+test name: termios10
+
+directives:
+ rtems_termios_register_isig_handler
+
+concepts:
+
++ Verifies signals are not delivered on QUIT and INTR characters
+ as default behavior.
+
++ Verified that signals are delivered when QUIT or INTR characters
+ are entered after rtems_termios_posix_isig_handler()
+ is registered using rtems_termios_register_isig_handler().
+
++ Verifies signals are not delivered on QUIT and INTR characters
+ after the default handler rtems_termios_default_isig_handler()
+ is registered using rtems_termios_register_isig_handler().
diff --git a/testsuites/libtests/termios11/termios11.scn b/testsuites/libtests/termios11/termios11.scn
new file mode 100644
index 0000000000..d4c379832b
--- /dev/null
+++ b/testsuites/libtests/termios11/termios11.scn
@@ -0,0 +1,14 @@
+*** BEGIN OF TEST TERMIOS 11 -- Interrupt driven ***
+Exercise default ISIG handler with ISIG enabled
+Test read for VKILL - no signals
+Test read for VQUIT - no signals
+Exercise POSIX ISIG handler with ISIG enabled
+Test read for VKILL - signal caught
+Test read for VQUIT - signal caught
+Exercise default ISIG handler with ISIG enabled
+Test read for VKILL - signal caught
+Test read for VQUIT - signal caught
+Exercise POSIX ISIG handler with ISIG disabled
+Test read for VKILL - signal caught
+Test read for VQUIT - signal caught
+*** END OF TEST TERMIOS 11 -- Interrupt driven ***