some fixes

This commit is contained in:
Antonio Juarez 2014-03-20 11:46:11 +00:00
parent 296ae46ed8
commit 8efa1313f3
67 changed files with 1523 additions and 757 deletions

View file

@ -1,6 +1,6 @@
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
@ -11,7 +11,7 @@
// * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@ -22,16 +22,187 @@
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
#pragma once
#include <atomic>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
namespace epee
{
class async_stdin_reader
{
public:
async_stdin_reader()
: m_run(true)
, m_has_read_request(false)
, m_read_status(state_init)
{
m_reader_thread = std::thread(std::bind(&async_stdin_reader::reader_thread_func, this));
}
~async_stdin_reader()
{
stop();
}
// Not thread safe. Only one thread can call this method at once.
bool get_line(std::string& line)
{
if (!start_read())
return false;
std::unique_lock<std::mutex> lock(m_response_mutex);
while (state_init == m_read_status)
{
m_response_cv.wait(lock);
}
bool res = false;
if (state_success == m_read_status)
{
line = m_line;
res = true;
}
m_read_status = state_init;
return res;
}
void stop()
{
if (m_run)
{
m_run.store(false, std::memory_order_relaxed);
#if defined(WIN32)
::CloseHandle(::GetStdHandle(STD_INPUT_HANDLE));
#endif
m_request_cv.notify_one();
m_reader_thread.join();
}
}
private:
bool start_read()
{
std::unique_lock<std::mutex> lock(m_request_mutex);
if (!m_run.load(std::memory_order_relaxed) || m_has_read_request)
return false;
m_has_read_request = true;
m_request_cv.notify_one();
return true;
}
bool wait_read()
{
std::unique_lock<std::mutex> lock(m_request_mutex);
while (m_run.load(std::memory_order_relaxed) && !m_has_read_request)
{
m_request_cv.wait(lock);
}
if (m_has_read_request)
{
m_has_read_request = false;
return true;
}
return false;
}
bool wait_stdin_data()
{
#if !defined(WIN32)
int stdin_fileno = ::fileno(stdin);
while (m_run.load(std::memory_order_relaxed))
{
fd_set read_set;
FD_ZERO(&read_set);
FD_SET(stdin_fileno, &read_set);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
int retval = ::select(stdin_fileno + 1, &read_set, NULL, NULL, &tv);
if (retval < 0)
return false;
else if (0 < retval)
return true;
}
#endif
return true;
}
void reader_thread_func()
{
while (true)
{
if (!wait_read())
break;
std::string line;
bool read_ok = true;
if (wait_stdin_data())
{
if (m_run.load(std::memory_order_relaxed))
{
std::getline(std::cin, line);
read_ok = !std::cin.eof() && !std::cin.fail();
}
}
else
{
read_ok = false;
}
{
std::unique_lock<std::mutex> lock(m_response_mutex);
if (m_run.load(std::memory_order_relaxed))
{
m_line = std::move(line);
m_read_status = read_ok ? state_success : state_error;
}
else
{
m_read_status = state_cancelled;
}
m_response_cv.notify_one();
}
}
}
enum t_state
{
state_init,
state_success,
state_error,
state_cancelled
};
private:
std::thread m_reader_thread;
std::atomic<bool> m_run;
std::string m_line;
bool m_has_read_request;
t_state m_read_status;
std::mutex m_request_mutex;
std::mutex m_response_mutex;
std::condition_variable m_request_cv;
std::condition_variable m_response_cv;
};
template<class t_server>
@ -39,124 +210,113 @@ namespace epee
{
return true;
}
template<class t_server, class chain_handler>
bool default_console_handler(t_server* psrv, chain_handler ch_handler, const std::string usage = "")
class async_console_handler
{
TRY_ENTRY();
bool continue_handle = true;
while(continue_handle)
public:
async_console_handler()
{
char command_buff[400] = {0};
std::string command;
std::cin.getline(command_buff, 399);
if(std::cin.eof() || std::cin.fail())
{
LOG_PRINT("std::cin.eof() or std::cin.fail(), stopping...", LOG_LEVEL_0);
continue_handle = false;
break;
}
command = command_buff;
if(!command.compare("exit") || !command.compare("q") )
{
psrv->send_stop_signal();
continue_handle = false;
}else if ( !command.compare(0, 7, "set_log"))
{
//parse set_log command
if(command.size() != 9)
{
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
continue;
}
int n = 0;
if(!string_tools::get_xtype_from_string(n, command.substr(8, 1)))
{
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
continue;
}
log_space::get_set_log_detalisation_level(true, n);
LOG_PRINT_L0("New log level set " << n);
}
else if(ch_handler(psrv, command))
continue;
else
{
std::cout << "unknown command: " << command << std::endl;
std::cout << usage;
}
}
return true;
CATCH_ENTRY_L0("console_handler", false);
}
template<class chain_handler>
bool default_console_handler2(chain_handler ch_handler, const std::string usage)
{
TRY_ENTRY();
bool continue_handle = true;
while(continue_handle)
template<class t_server, class chain_handler>
bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
{
char command_buff[400] = {0};
std::string command;
std::cin.getline(command_buff, 399);
if(std::cin.eof() || std::cin.fail())
{
LOG_PRINT("std::cin.eof() or std::cin.fail(), stopping...", LOG_LEVEL_0);
continue_handle = false;
break;
}
command = command_buff;
if(!command.compare("exit") || !command.compare("q") )
{
continue_handle = false;
}else if ( !command.compare(0, 7, "set_log"))
{
//parse set_log command
if(command.size() != 9)
{
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
continue;
}
int n = 0;
if(!string_tools::get_xtype_from_string(n, command.substr(8, 1)))
{
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
continue;
}
log_space::get_set_log_detalisation_level(true, n);
LOG_PRINT_L0("New log level set " << n);
}
else if(ch_handler(command))
continue;
else
{
std::cout << "unknown command: " << command << std::endl;
std::cout << usage;
}
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); });
}
return true;
CATCH_ENTRY_L0("console_handler", false);
}
template<class chain_handler>
bool run(chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
{
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(cmd); }, [] { });
}
void stop()
{
m_stdin_reader.stop();
}
private:
template<typename t_cmd_handler, typename t_exit_handler>
bool run(const std::string& prompt, const std::string& usage, const t_cmd_handler& cmd_handler, const t_exit_handler& exit_handler)
{
TRY_ENTRY();
bool continue_handle = true;
while(continue_handle)
{
if (!prompt.empty())
{
epee::log_space::set_console_color(epee::log_space::console_color_yellow, true);
std::cout << prompt;
if (' ' != prompt.back())
std::cout << ' ';
epee::log_space::reset_console_color();
std::cout.flush();
}
std::string command;
if(!m_stdin_reader.get_line(command))
{
LOG_PRINT("Failed to read line. Stopping...", LOG_LEVEL_0);
continue_handle = false;
break;
}
LOG_PRINT_L2("Read command: " << command);
if(0 == command.compare("exit") || 0 == command.compare("q"))
{
continue_handle = false;
}else if (!command.compare(0, 7, "set_log"))
{
//parse set_log command
if(command.size() != 9)
{
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
continue;
}
uint16_t n = 0;
if(!string_tools::get_xtype_from_string(n, command.substr(8, 1)))
{
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
continue;
}
log_space::get_set_log_detalisation_level(true, n);
LOG_PRINT_L0("New log level set " << n);
}else if (command.empty())
{
continue;
}
else if(cmd_handler(command))
{
continue;
} else
{
std::cout << "unknown command: " << command << std::endl;
std::cout << usage;
}
}
exit_handler();
return true;
CATCH_ENTRY_L0("console_handler", false);
}
private:
async_stdin_reader m_stdin_reader;
};
template<class t_server, class t_handler>
bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
{
boost::thread( boost::bind(default_console_handler<t_server, t_handler>, ptsrv, handlr, usage) );
std::shared_ptr<async_console_handler> console_handler = std::make_shared<async_console_handler>();
boost::thread(boost::bind(&async_console_handler::run<t_server, t_handler>, console_handler, ptsrv, handlr, prompt, usage)).detach();
return true;
}
template<class t_server>
bool start_default_console(t_server* ptsrv, const std::string& usage = "")
bool start_default_console(t_server* ptsrv, const std::string& prompt, const std::string& usage = "")
{
return start_default_console(ptsrv, empty_commands_handler<t_server>, usage);
return start_default_console(ptsrv, empty_commands_handler<t_server>, prompt, usage);
}
template<class t_server, class t_handler>
@ -166,15 +326,16 @@ namespace epee
}
template<class t_server, class t_handler>
bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
{
return default_console_handler(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), usage);
async_console_handler console_handler;
return console_handler.run(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), prompt, usage);
}
template<class t_server, class t_handler>
bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
{
boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, usage) );
boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, prompt, usage) );
return true;
}
@ -209,7 +370,8 @@ namespace epee
typedef std::map<std::string, std::pair<console_command_handler, std::string> > command_handlers_map;
std::unique_ptr<boost::thread> m_console_thread;
command_handlers_map m_command_handlers;
public:
async_console_handler m_console_handler;
public:
std::string get_usage()
{
std::stringstream ss;
@ -217,7 +379,7 @@ namespace epee
for(auto& x:m_command_handlers)
if(x.first.size() > max_command_len)
max_command_len = x.first.size();
for(auto& x:m_command_handlers)
{
ss.width(max_command_len + 3);
@ -255,24 +417,22 @@ namespace epee
start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1));
return true;
}*/
bool start_handling(const std::string& usage_string = "")
bool start_handling(const std::string& prompt, const std::string& usage_string = "")
{
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, usage_string) ));
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string)));
m_console_thread->detach();
return true;
}
bool stop_handling()
void stop_handling()
{
if(m_console_thread.get())
m_console_thread->interrupt();
return true;
m_console_handler.stop();
}
bool run_handling(const std::string usage_string)
bool run_handling(const std::string& prompt, const std::string& usage_string)
{
return default_console_handler2(boost::bind(&console_handlers_binder::process_command_str, this, _1), usage_string);
return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string);
}
/*template<class t_srv>
@ -280,7 +440,6 @@ namespace epee
{
return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string);
}*/
};
/* work around because of broken boost bind */
@ -292,19 +451,23 @@ namespace epee
return console_handlers_binder::process_command_str(cmd);
}
public:
bool start_handling(t_server* psrv, const std::string& usage_string = "")
bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "")
{
boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, usage_string) );
boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
return true;
}
bool run_handling(t_server* psrv, const std::string usage_string)
bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string)
{
return default_console_handler(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), usage_string);
return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), prompt, usage_string);
}
void stop_handling()
{
m_console_handler.stop();
}
private:
async_console_handler m_console_handler;
};
}