diff options
-rw-r--r-- | cpukit/Makefile.am | 1 | ||||
-rw-r--r-- | cpukit/include/rtems/libio.h | 116 | ||||
-rw-r--r-- | cpukit/include/rtems/rtems/status.h | 9 | ||||
-rw-r--r-- | cpukit/libcsupport/src/termios.c | 225 | ||||
-rw-r--r-- | cpukit/libcsupport/src/termios_posix_isig_handler.c | 39 | ||||
-rw-r--r-- | cpukit/rtems/src/statustext.c | 1 | ||||
-rw-r--r-- | cpukit/rtems/src/statustoerrno.c | 1 | ||||
-rw-r--r-- | testsuites/libtests/Makefile.am | 22 | ||||
-rw-r--r-- | testsuites/libtests/configure.ac | 2 | ||||
-rw-r--r-- | testsuites/libtests/termios10/init.c | 191 | ||||
-rw-r--r-- | testsuites/libtests/termios10/termios10.doc | 23 | ||||
-rw-r--r-- | testsuites/libtests/termios10/termios10.scn | 14 | ||||
-rw-r--r-- | testsuites/libtests/termios11/termios11.doc | 23 | ||||
-rw-r--r-- | testsuites/libtests/termios11/termios11.scn | 14 |
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 *** |