Add threaded input handling

To make tio more responsive to quit and I/O flush key command when main I/O
thread is blocked on output.
This commit is contained in:
Martin Lund 2022-11-24 22:52:28 +01:00
parent 12f20c84e3
commit 93e6efc001
5 changed files with 123 additions and 9 deletions

View file

@ -291,6 +291,8 @@ Show configuration (baudrate, databits, etc.)
Toggle local echo mode
.IP "\fBctrl-t f"
Toggle log to file
.IP "\fBctrl-t F"
Flush data I/O channels (discard data written but not transmitted and data received but not read)
.IP "\fBctrl-t g"
Toggle serial port line
.IP "\fBctrl-t h"

View file

@ -120,6 +120,12 @@ int main(int argc, char *argv[])
socket_configure();
}
/* Spawn input handling into separate thread */
tty_input_thread_create();
/* Wait for input to be ready */
tty_input_thread_wait_ready();
/* Connect to tty device */
if (option.no_autoconnect)
{

View file

@ -20,9 +20,12 @@ tio_sources = [
'alert.c'
]
tio_dep = dependency('inih', required: true,
tio_dep = [
dependency('threads', required: true),
dependency('inih', required: true,
fallback : ['libinih', 'inih_dep'],
default_options: ['default_library=static', 'distro_install=false'])
]
tio_c_args = ['-Wno-unused-result']

117
src/tty.c
View file

@ -40,6 +40,7 @@
#include <errno.h>
#include <time.h>
#include <dirent.h>
#include <pthread.h>
#include "config.h"
#include "configfile.h"
#include "tty.h"
@ -81,6 +82,7 @@
#define KEY_C 0x63
#define KEY_E 0x65
#define KEY_F 0x66
#define KEY_SHIFT_F 0x46
#define KEY_G 0x67
#define KEY_H 0x68
#define KEY_L 0x6C
@ -134,6 +136,9 @@ static unsigned char hex_char_index = 0;
static char tty_buffer[BUFSIZ*2];
static size_t tty_buffer_count = 0;
static char *tty_buffer_write_ptr = tty_buffer;
static pthread_t thread;
static int pipefd[2];
static pthread_mutex_t mutex_input_ready = PTHREAD_MUTEX_INITIALIZER;
static void optional_local_echo(char c)
{
@ -256,6 +261,99 @@ ssize_t tty_write(int fd, const void *buffer, size_t count)
return bytes_written;
}
void *tty_stdin_input_thread(void *arg)
{
UNUSED(arg);
char input_buffer[BUFSIZ];
ssize_t byte_count;
ssize_t bytes_written;
// Create FIFO pipe
if (pipe(pipefd) == -1)
{
tio_error_printf("Failed to create pipe");
exit(EXIT_FAILURE);
}
// Signal that input pipe is ready
pthread_mutex_unlock(&mutex_input_ready);
// Input loop for stdin
while (1)
{
/* Input from stdin ready */
byte_count = read(STDIN_FILENO, input_buffer, BUFSIZ);
if (byte_count < 0)
{
tio_warning_printf("Could not read from stdin (%s)", strerror(errno));
}
else if (byte_count == 0)
{
// Close write end to signal EOF in read end
close(pipefd[1]);
pthread_exit(0);
}
if (interactive_mode)
{
static char previous_char = 0;
char input_char;
// Process quit and flush key command
for (int i = 0; i<byte_count; i++)
{
input_char = input_buffer[i];
if (previous_char == option.prefix_code)
{
switch (input_char)
{
case KEY_Q:
exit(EXIT_FAILURE);
break;
case KEY_SHIFT_F:
tio_printf("Flushed data I/O channels")
tcflush(fd, TCIOFLUSH);
break;
default:
break;
}
}
previous_char = input_char;
}
}
// Write all bytes read to pipe
while (byte_count)
{
bytes_written = write(pipefd[1], input_buffer, byte_count);
if (bytes_written < 0)
{
tio_warning_printf("Could not write to pipe (%s)", strerror(errno));
break;
}
byte_count -= bytes_written;
}
}
pthread_exit(0);
}
void tty_input_thread_create(void)
{
pthread_mutex_lock(&mutex_input_ready);
if (pthread_create(&thread, NULL, tty_stdin_input_thread, NULL) != 0) {
tio_error_printf("pthread_create() error");
exit(1);
}
}
void tty_input_thread_wait_ready(void)
{
pthread_mutex_lock(&mutex_input_ready);
}
static void output_hex(char c)
{
hex_chars[hex_char_index++] = c;
@ -472,6 +570,9 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
tio_printf("Switched log to file %s", option.log ? "on" : "off");
break;
case KEY_SHIFT_F:
break;
case KEY_G:
tio_printf("Please enter which serial line number to toggle:");
tio_printf(" DTR (0)");
@ -947,19 +1048,19 @@ void tty_wait_for_device(void)
}
FD_ZERO(&rdfs);
FD_SET(STDIN_FILENO, &rdfs);
maxfd = MAX(STDIN_FILENO, socket_add_fds(&rdfs, false));
FD_SET(pipefd[0], &rdfs);
maxfd = MAX(pipefd[0], socket_add_fds(&rdfs, false));
/* Block until input becomes available or timeout */
status = select(maxfd + 1, &rdfs, NULL, NULL, &tv);
if (status > 0)
{
if (FD_ISSET(STDIN_FILENO, &rdfs))
if (FD_ISSET(pipefd[0], &rdfs))
{
/* Input from stdin ready */
/* Read one character */
status = read(STDIN_FILENO, &input_char, 1);
status = read(pipefd[0], &input_char, 1);
if (status <= 0)
{
tio_error_printf("Could not read from stdin");
@ -1200,9 +1301,9 @@ int tty_connect(void)
FD_SET(fd, &rdfs);
if (!ignore_stdin)
{
FD_SET(STDIN_FILENO, &rdfs);
FD_SET(pipefd[0], &rdfs);
}
maxfd = MAX(fd, STDIN_FILENO);
maxfd = MAX(fd, pipefd[0]);
maxfd = MAX(maxfd, socket_add_fds(&rdfs, true));
/* Manage timeout */
@ -1309,10 +1410,10 @@ int tty_connect(void)
}
}
}
else if (FD_ISSET(STDIN_FILENO, &rdfs))
else if (FD_ISSET(pipefd[0], &rdfs))
{
/* Input from stdin ready */
ssize_t bytes_read = read(STDIN_FILENO, input_buffer, BUFSIZ);
ssize_t bytes_read = read(pipefd[0], input_buffer, BUFSIZ);
if (bytes_read < 0)
{
tio_error_printf_silent("Could not read from stdin (%s)", strerror(errno));

View file

@ -31,3 +31,5 @@ void tty_configure(void);
int tty_connect(void);
void tty_wait_for_device(void);
void list_serial_devices(void);
void tty_input_thread_create(void);
void tty_input_thread_wait_ready(void);