diff options
author | Frédéric Brière <fbriere@fbriere.net> | 2019-06-29 08:31:08 -0400 |
---|---|---|
committer | Frédéric Brière <fbriere@fbriere.net> | 2019-06-29 19:48:27 -0400 |
commit | 18f2b023bc2c1ea84e7690b604c196580ac8f110 (patch) | |
tree | 3578fe3a26deead00a67688f7731d617a8e1ce2d /src | |
parent | d26fa24087265dd4e9dccf0db261da0e6f093c8e (diff) | |
download | twinkle-18f2b023bc2c1ea84e7690b604c196580ac8f110.tar twinkle-18f2b023bc2c1ea84e7690b604c196580ac8f110.tar.gz twinkle-18f2b023bc2c1ea84e7690b604c196580ac8f110.tar.lz twinkle-18f2b023bc2c1ea84e7690b604c196580ac8f110.tar.xz twinkle-18f2b023bc2c1ea84e7690b604c196580ac8f110.zip |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/userintf.cpp | 31 | ||||
-rw-r--r-- | src/userintf.h | 1 |
2 files changed, 32 insertions, 0 deletions
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 <iostream> #include <cstdlib> #include <errno.h> +#include <fcntl.h> #include <readline/readline.h> #include <readline/history.h> #include <signal.h> #include <stdio.h> #include <string> #include <sys/select.h> +#include <unistd.h> #include "address_book.h" #include "events.h" #include "line.h" @@ -1483,6 +1485,10 @@ bool t_userintf::exec_quit(const list<string> 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<string> 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)) { diff --git a/src/userintf.h b/src/userintf.h index 48a4c50..2c6d96d 100644 --- a/src/userintf.h +++ b/src/userintf.h @@ -62,6 +62,7 @@ protected: private: bool end_interface; // indicates if interface loop should quit + int break_readline_loop_pipe[2]; // pipe used to interrupt Readline list<string> all_commands; // list of all commands t_tone_gen *tone_gen; // tone generator for ringing |