From c088d38a57f6be5c8399a8c2243b2862d9f67cbe Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 21 Aug 2017 12:55:06 +0100 Subject: [PATCH 1/2] Simplify readline support And don't use std::mutex --- contrib/epee/include/console_handler.h | 28 ++-- contrib/epee/include/readline_buffer.h | 6 +- contrib/epee/src/readline_buffer.cpp | 197 +++++++++---------------- 3 files changed, 88 insertions(+), 143 deletions(-) diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h index a3b2d30eb..b8336b270 100644 --- a/contrib/epee/include/console_handler.h +++ b/contrib/epee/include/console_handler.h @@ -52,11 +52,10 @@ namespace epee , m_has_read_request(false) , m_read_status(state_init) { - m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this)); #ifdef HAVE_READLINE m_readline_buffer.start(); - m_readline_thread = boost::thread(std::bind(&async_stdin_reader::readline_thread_func, this)); #endif + m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this)); } ~async_stdin_reader() @@ -115,7 +114,6 @@ namespace epee m_reader_thread.join(); #ifdef HAVE_READLINE m_readline_buffer.stop(); - m_readline_thread.join(); #endif } } @@ -193,16 +191,6 @@ namespace epee return true; } -#ifdef HAVE_READLINE - void readline_thread_func() - { - while (m_run.load(std::memory_order_relaxed)) - { - m_readline_buffer.process(); - } - } -#endif - void reader_thread_func() { while (true) @@ -212,12 +200,20 @@ namespace epee std::string line; bool read_ok = true; +#ifdef HAVE_READLINE +reread: +#endif if (wait_stdin_data()) { if (m_run.load(std::memory_order_relaxed)) { #ifdef HAVE_READLINE - m_readline_buffer.get_line(line); + switch (m_readline_buffer.get_line(line)) + { + case rdln::empty: goto eof; + case rdln::partial: goto reread; + case rdln::full: break; + } #else std::getline(std::cin, line); #endif @@ -229,6 +225,9 @@ namespace epee read_ok = false; } if (std::cin.eof()) { +#ifdef HAVE_READLINE +eof: +#endif m_read_status = state_eos; m_response_cv.notify_one(); break; @@ -263,7 +262,6 @@ namespace epee boost::thread m_reader_thread; std::atomic m_run; #ifdef HAVE_READLINE - boost::thread m_readline_thread; rdln::readline_buffer m_readline_buffer; #endif diff --git a/contrib/epee/include/readline_buffer.h b/contrib/epee/include/readline_buffer.h index 28a153414..cda7e34f9 100644 --- a/contrib/epee/include/readline_buffer.h +++ b/contrib/epee/include/readline_buffer.h @@ -8,25 +8,25 @@ namespace rdln { + typedef enum { empty, partial, full } linestatus; class readline_buffer : public std::stringbuf { public: readline_buffer(); void start(); void stop(); - int process(); bool is_running() const { return m_cout_buf != NULL; } - void get_line(std::string& line) const; + linestatus get_line(std::string& line) const; void set_prompt(const std::string& prompt); static void add_completion(const std::string& command); static const std::vector& get_completions(); protected: virtual int sync(); - + private: std::streambuf* m_cout_buf; static std::vector& completion_commands(); diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp index 42b474052..291bba94c 100644 --- a/contrib/epee/src/readline_buffer.cpp +++ b/contrib/epee/src/readline_buffer.cpp @@ -3,19 +3,15 @@ #include #include #include -#include -#include #include #include -static int process_input(); static void install_line_handler(); static void remove_line_handler(); -static std::string last_line; -static std::string last_prompt; -static std::mutex line_mutex, sync_mutex, process_mutex; -static std::condition_variable have_line; +static boost::mutex sync_mutex; +static rdln::linestatus line_stat; +static char *the_line; namespace { @@ -55,7 +51,6 @@ rdln::readline_buffer::readline_buffer() void rdln::readline_buffer::start() { - std::unique_lock lock(process_mutex); if(m_cout_buf != NULL) return; m_cout_buf = std::cout.rdbuf(); @@ -65,9 +60,6 @@ void rdln::readline_buffer::start() void rdln::readline_buffer::stop() { - std::unique_lock lock_process(process_mutex); - std::unique_lock lock_sync(sync_mutex); - have_line.notify_all(); if(m_cout_buf == NULL) return; std::cout.rdbuf(m_cout_buf); @@ -75,20 +67,26 @@ void rdln::readline_buffer::stop() remove_line_handler(); } -void rdln::readline_buffer::get_line(std::string& line) const +rdln::linestatus rdln::readline_buffer::get_line(std::string& line) const { - std::unique_lock lock(line_mutex); - have_line.wait(lock); - line = last_line; + boost::lock_guard lock(sync_mutex); + line_stat = rdln::partial; + rl_callback_read_char(); + if (line_stat == rdln::full) + { + line = the_line; + free(the_line); + the_line = NULL; + } + return line_stat; } void rdln::readline_buffer::set_prompt(const std::string& prompt) { - last_prompt = prompt; if(m_cout_buf == NULL) return; - std::lock_guard lock(sync_mutex); - rl_set_prompt(last_prompt.c_str()); + boost::lock_guard lock(sync_mutex); + rl_set_prompt(prompt.c_str()); rl_redisplay(); } @@ -104,128 +102,80 @@ const std::vector& rdln::readline_buffer::get_completions() return completion_commands(); } -int rdln::readline_buffer::process() -{ - process_mutex.lock(); - if(m_cout_buf == NULL) - { - process_mutex.unlock(); - boost::this_thread::sleep_for(boost::chrono::milliseconds( 1 )); - return 0; - } - int count = process_input(); - process_mutex.unlock(); - boost::this_thread::sleep_for(boost::chrono::milliseconds( 1 )); - return count; -} - int rdln::readline_buffer::sync() { - std::lock_guard lock(sync_mutex); - char* saved_line; - int saved_point; - - saved_point = rl_point; - saved_line = rl_copy_text(0, rl_end); - - rl_set_prompt(""); - rl_replace_line("", 0); - rl_redisplay(); - + boost::lock_guard lock(sync_mutex); +#if RL_READLINE_VERSION < 0x0700 + char lbuf[2] = {0,0}; + char *line = NULL; + int end = 0, point = 0; +#endif + + if (rl_end || *rl_prompt) + { +#if RL_READLINE_VERSION >= 0x0700 + rl_clear_visible_line(); +#else + line = rl_line_buffer; + end = rl_end; + point = rl_point; + rl_line_buffer = lbuf; + rl_end = 0; + rl_point = 0; + rl_save_prompt(); + rl_redisplay(); +#endif + } + do { m_cout_buf->sputc( this->sgetc() ); } while ( this->snextc() != EOF ); - - rl_set_prompt(last_prompt.c_str()); - rl_replace_line(saved_line, 0); - rl_point = saved_point; - rl_redisplay(); - free(saved_line); - - return 0; -} -static int process_input() -{ - int count; - struct timeval t; - fd_set fds; - - t.tv_sec = 0; - t.tv_usec = 1000; - - FD_ZERO(&fds); - FD_SET(STDIN_FILENO, &fds); - count = select(STDIN_FILENO + 1, &fds, NULL, NULL, &t); - if (count < 1) +#if RL_READLINE_VERSION < 0x0700 + if (end || *rl_prompt) { - return count; + rl_restore_prompt(); + rl_line_buffer = line; + rl_end = end; + rl_point = point; } - rl_callback_read_char(); - return count; +#endif + rl_on_new_line(); + rl_redisplay(); + + return 0; } static void handle_line(char* line) { - free(line); + bool exit = false; + if (line) + { + line_stat = rdln::full; + the_line = line; + std::string test_line = line; + boost::trim_right(test_line); + if(!test_line.empty()) + { + add_history(test_line.c_str()); + history_set_pos(history_length); + if (test_line == "exit" || test_line == "q") + exit = true; + } + } else + /* EOF */ + { + line_stat = rdln::empty; + exit = true; + } rl_done = 1; + if (exit) + rl_set_prompt(""); return; } -static int handle_enter(int x, int y) -{ - std::lock_guard lock(sync_mutex); - char* line = NULL; - - line = rl_copy_text(0, rl_end); - std::string test_line = line; - free(line); - boost::trim_right(test_line); - - rl_crlf(); - rl_on_new_line(); - - if(test_line.empty()) - { - last_line = ""; - rl_set_prompt(last_prompt.c_str()); - rl_replace_line("", 1); - rl_redisplay(); - have_line.notify_one(); - return 0; - } - - rl_set_prompt(""); - rl_replace_line("", 1); - rl_redisplay(); - - if (!test_line.empty()) - { - last_line = test_line; - add_history(test_line.c_str()); - history_set_pos(history_length); - } - - if(last_line != "exit" && last_line != "q") - { - rl_set_prompt(last_prompt.c_str()); - rl_replace_line("", 1); - rl_redisplay(); - } - - have_line.notify_one(); - return 0; -} - -static int startup_hook() -{ - rl_bind_key(RETURN, handle_enter); - rl_bind_key(NEWLINE, handle_enter); - return 0; -} - static char* completion_matches(const char* text, int state) { static size_t list_index; @@ -258,7 +208,6 @@ static char** attempted_completion(const char* text, int start, int end) static void install_line_handler() { - rl_startup_hook = startup_hook; rl_attempted_completion_function = attempted_completion; rl_callback_handler_install("", handle_line); stifle_history(500); @@ -269,8 +218,6 @@ static void remove_line_handler() rl_replace_line("", 0); rl_set_prompt(""); rl_redisplay(); - rl_unbind_key(RETURN); - rl_unbind_key(NEWLINE); rl_callback_handler_remove(); } From c656dd0ede64c3c71a9a357c9354b5e3cdb94ce4 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 21 Aug 2017 16:34:45 +0100 Subject: [PATCH 2/2] Fix refresh counter display Suspend readline when refreshing --- src/simplewallet/simplewallet.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 1811eeb3c..2ccb6c7e9 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -63,6 +63,10 @@ #include "wallet/wallet_args.h" #include +#ifdef HAVE_READLINE +#include "readline_buffer.h" +#endif + using namespace std; using namespace epee; using namespace cryptonote; @@ -1835,6 +1839,10 @@ bool simple_wallet::refresh_main(uint64_t start_height, bool reset) if (reset) m_wallet->rescan_blockchain(false); +#ifdef HAVE_READLINE + rdln::suspend_readline pause_readline; +#endif + message_writer() << tr("Starting refresh..."); uint64_t fetched_blocks = 0;