From 18f2b023bc2c1ea84e7690b604c196580ac8f110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bri=C3=A8re?= Date: Sat, 29 Jun 2019 08:31:08 -0400 Subject: Make Readline non-blocking: Use a self-pipe to break the Readline loop Now that we are no longer blocking on Readline calls, we can set up a self-pipe that will let us break out of the Readline loop upon receiving a "quit" command on our local socket, thus (finally) fixing issue #143. (Thanks to https://stackoverflow.com/a/27662212 for the tip!) Fixes #143 --- src/userintf.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src/userintf.cpp') diff --git a/src/userintf.cpp b/src/userintf.cpp index 21888ac..5268a7c 100644 --- a/src/userintf.cpp +++ b/src/userintf.cpp @@ -18,12 +18,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "address_book.h" #include "events.h" #include "line.h" @@ -1483,6 +1485,10 @@ bool t_userintf::exec_quit(const list command_list) { void t_userintf::do_quit(void) { end_interface = true; + // Signal the main thread that it should interrupt Readline + if (break_readline_loop_pipe[1] != -1) { + write(break_readline_loop_pipe[1], "X", 1); + } } bool t_userintf::exec_help(const list command_list) { @@ -2220,6 +2226,27 @@ void t_userintf::run(void) { // Initialize phone functions phone->init(); + // Set up the self-pipe used to interrupt Readline + if (pipe(break_readline_loop_pipe) == 0) { + // Mark both file descriptors as close-on-exec for good measure + for (int i = 0; i < 2; i++) { + int flags = fcntl(break_readline_loop_pipe[i], F_GETFD); + if (flags != -1) { + flags |= FD_CLOEXEC; + fcntl(break_readline_loop_pipe[i], F_SETFD, flags); + } + } + } else { + // Not fatal -- we just won't be able to interrupt Readline + string msg("pipe() failed: "); + msg += get_error_str(errno); + ui->cb_show_msg(msg, MSG_WARNING); + + // Mark both file descriptors as invalid + break_readline_loop_pipe[0] = -1; + break_readline_loop_pipe[1] = -1; + } + //Initialize GNU readline functions rl_attempted_completion_function = tw_completion; using_history(); @@ -2232,9 +2259,13 @@ void t_userintf::run(void) { rl_callback_handler_install(CLI_PROMPT, tw_readline_cb); while (!end_interface) { + // File descriptors we are watching (stdin + self-pipe) fd_set fds; FD_ZERO(&fds); FD_SET(fileno(rl_instream), &fds); + if (break_readline_loop_pipe[0] != -1) { + FD_SET(break_readline_loop_pipe[0], &fds); + } int ret = select(FD_SETSIZE, &fds, NULL, NULL, NULL); if ((ret == -1) && (errno != EINTR)) { -- cgit v1.2.3