summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-11-06 14:49:32 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-11-07 08:31:40 +0100
commit791469bd4fb1eba09ea8464795f100d7dd09379e (patch)
treea9f2757628501ce35f59868acdddf4b5b8c8a498
parenttests: Use normal console for user input tests (diff)
downloadrtems-791469bd4fb1eba09ea8464795f100d7dd09379e.tar.bz2
termios: Fix canonical mode
In canonical mode, input is made available line by line. We must stop the canonical buffer filling upon reception of an end-of-line character. Close #3218.
-rw-r--r--cpukit/libcsupport/src/termios.c6
-rw-r--r--testsuites/libtests/termios09/init.c97
2 files changed, 81 insertions, 22 deletions
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index 7a114a74b9..8303e9f18d 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -1570,8 +1570,10 @@ fillBufferQueue (struct rtems_termios_tty *tty)
/* continue processing new character */
if (tty->termios.c_lflag & ICANON) {
- if (siproc (c, tty))
- wait = false;
+ if (siproc (c, tty)) {
+ /* In canonical mode, input is made available line by line */
+ return;
+ }
} else {
siproc (c, tty);
if (tty->ccount >= tty->termios.c_cc[VMIN])
diff --git a/testsuites/libtests/termios09/init.c b/testsuites/libtests/termios09/init.c
index 7509101682..62138bc213 100644
--- a/testsuites/libtests/termios09/init.c
+++ b/testsuites/libtests/termios09/init.c
@@ -36,6 +36,8 @@ const char rtems_test_name[] = "TERMIOS 9";
#define OUTPUT_BUFFER_SIZE 64
+#define INPUT_BUFFER_SIZE 64
+
static const char * const paths[DEVICE_COUNT] = {
"/interrupt",
"/polled"
@@ -47,7 +49,9 @@ typedef struct {
size_t output_pending;
size_t output_count;
char output_buf[OUTPUT_BUFFER_SIZE];
- int input_char;
+ size_t input_head;
+ size_t input_tail;
+ unsigned char input_buf[INPUT_BUFFER_SIZE];
int callback_counter;
} device_context;
@@ -64,8 +68,7 @@ static test_context test_instance = {
{
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Interrupt")
}, {
- .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Polled"),
- .input_char = -1
+ .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Polled")
}
}
};
@@ -112,9 +115,14 @@ static void write_interrupt(
static int read_polled(rtems_termios_device_context *base)
{
device_context *dev = (device_context *) base;
- int c = dev->input_char;
+ int c;
- dev->input_char = -1;
+ if (dev->input_head != dev->input_tail) {
+ c = dev->input_buf[dev->input_head];
+ dev->input_head = (dev->input_head + 1) % INPUT_BUFFER_SIZE;
+ } else {
+ c = -1;
+ }
return c;
}
@@ -187,12 +195,16 @@ static void setup(test_context *ctx)
static void input(test_context *ctx, size_t i, char c)
{
+ device_context *dev = &ctx->devices[i];
+
switch (i) {
case INTERRUPT:
- rtems_termios_enqueue_raw_characters(ctx->devices[i].tty, &c, sizeof(c));
+ rtems_termios_enqueue_raw_characters(dev->tty, &c, sizeof(c));
break;
case POLLED:
- ctx->devices[i].input_char = (unsigned char) c;
+ dev->input_buf[dev->input_tail] = (unsigned char) c;
+ dev->input_tail = (dev->input_tail + 1) % INPUT_BUFFER_SIZE;
+ rtems_test_assert(dev->input_head != dev->input_tail);
break;
default:
rtems_test_assert(0);
@@ -523,11 +535,13 @@ static void test_rx_callback_icanon(test_context *ctx)
input(ctx, i, '\n');
rtems_test_assert(dev->callback_counter == 1);
- n = read(ctx->fds[i], buf, 3);
- rtems_test_assert(n == 3);
+ n = read(ctx->fds[i], buf, 2);
+ rtems_test_assert(n == 1);
rtems_test_assert(buf[0] == '\n');
- rtems_test_assert(buf[1] == 'a');
- rtems_test_assert(buf[2] == '\n');
+ n = read(ctx->fds[i], buf, 3);
+ rtems_test_assert(n == 2);
+ rtems_test_assert(buf[0] == 'a');
+ rtems_test_assert(buf[1] == '\n');
input(ctx, i, '\4');
rtems_test_assert(dev->callback_counter == 2);
@@ -538,11 +552,15 @@ static void test_rx_callback_icanon(test_context *ctx)
input(ctx, i, '\n');
rtems_test_assert(dev->callback_counter == 2);
- n = read(ctx->fds[i], buf, 2);
+ n = read(ctx->fds[i], buf, 1);
+ rtems_test_assert(n == 0);
+
+ n = read(ctx->fds[i], buf, 3);
rtems_test_assert(n == 2);
rtems_test_assert(buf[0] == 'b');
rtems_test_assert(buf[1] == '\n');
+ /* EOL */
input(ctx, i, '1');
rtems_test_assert(dev->callback_counter == 3);
@@ -552,12 +570,15 @@ static void test_rx_callback_icanon(test_context *ctx)
input(ctx, i, '\n');
rtems_test_assert(dev->callback_counter == 3);
- n = read(ctx->fds[i], buf, 3);
- rtems_test_assert(n == 3);
+ n = read(ctx->fds[i], buf, 2);
+ rtems_test_assert(n == 1);
rtems_test_assert(buf[0] == '1');
- rtems_test_assert(buf[1] == 'c');
- rtems_test_assert(buf[2] == '\n');
+ n = read(ctx->fds[i], buf, 3);
+ rtems_test_assert(n == 2);
+ rtems_test_assert(buf[0] == 'c');
+ rtems_test_assert(buf[1] == '\n');
+ /* EOL2 */
input(ctx, i, '2');
rtems_test_assert(dev->callback_counter == 4);
@@ -567,11 +588,13 @@ static void test_rx_callback_icanon(test_context *ctx)
input(ctx, i, '\n');
rtems_test_assert(dev->callback_counter == 4);
- n = read(ctx->fds[i], buf, 3);
- rtems_test_assert(n == 3);
+ n = read(ctx->fds[i], buf, 2);
+ rtems_test_assert(n == 1);
rtems_test_assert(buf[0] == '2');
- rtems_test_assert(buf[1] == 'd');
- rtems_test_assert(buf[2] == '\n');
+ n = read(ctx->fds[i], buf, 3);
+ rtems_test_assert(n == 2);
+ rtems_test_assert(buf[0] == 'd');
+ rtems_test_assert(buf[1] == '\n');
for (j = 0; j < 255; ++j) {
input(ctx, i, 'e');
@@ -591,6 +614,38 @@ static void test_rx_callback_icanon(test_context *ctx)
clear_set_lflag(ctx, i, ICANON, 0);
}
+static void test_read_icanon(test_context *ctx, size_t i)
+{
+ ssize_t n;
+ char buf[3];
+
+ clear_set_lflag(ctx, i, 0, ICANON);
+
+ input(ctx, i, 'a');
+ input(ctx, i, '\n');
+ input(ctx, i, 'b');
+ input(ctx, i, '\n');
+ input(ctx, i, 'c');
+ input(ctx, i, '\n');
+
+ n = read(ctx->fds[i], buf, 3);
+ rtems_test_assert(n == 2);
+ rtems_test_assert(buf[0] == 'a');
+ rtems_test_assert(buf[1] == '\n');
+
+ n = read(ctx->fds[i], buf, 3);
+ rtems_test_assert(n == 2);
+ rtems_test_assert(buf[0] == 'b');
+ rtems_test_assert(buf[1] == '\n');
+
+ n = read(ctx->fds[i], buf, 3);
+ rtems_test_assert(n == 2);
+ rtems_test_assert(buf[0] == 'c');
+ rtems_test_assert(buf[1] == '\n');
+
+ clear_set_lflag(ctx, i, ICANON, 0);
+}
+
static void flush_output(test_context *ctx, size_t i)
{
if (i == INTERRUPT) {
@@ -1106,6 +1161,8 @@ static void Init(rtems_task_argument arg)
test_inlcr(ctx);
test_rx_callback(ctx);
test_rx_callback_icanon(ctx);
+ test_read_icanon(ctx, INTERRUPT);
+ test_read_icanon(ctx, POLLED);
test_onlret(ctx);
test_onlcr(ctx);
test_onocr(ctx);