summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrédéric Brière <fbriere@fbriere.net>2019-06-29 08:31:08 -0400
committerFrédéric Brière <fbriere@fbriere.net>2019-06-29 19:48:27 -0400
commit18f2b023bc2c1ea84e7690b604c196580ac8f110 (patch)
tree3578fe3a26deead00a67688f7731d617a8e1ce2d
parentd26fa24087265dd4e9dccf0db261da0e6f093c8e (diff)
downloadtwinkle-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
-rw-r--r--src/userintf.cpp31
-rw-r--r--src/userintf.h1
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