diff --git a/src/common/threads_pool.h b/src/common/threads_pool.h new file mode 100644 index 00000000..4e4e3905 --- /dev/null +++ b/src/common/threads_pool.h @@ -0,0 +1,153 @@ +// Copyright (c) 2014-2019 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include + +namespace utils +{ + + struct call_executor_base + { + virtual void execute() = 0; + }; + + template + struct call_executor_t : public call_executor_base + { + call_executor_t(t_executor_func f) :m_func(f) + {} + t_executor_func m_func; + virtual void execute() + { + m_func(); + } + }; + + template + std::shared_ptr build_call_executor(t_executor_func func) + { + std::shared_ptr res(static_cast(new call_executor_t(func))); + return res; + } + + class threads_pool + { + public: + typedef std::list> jobs_container; + + template + static void add_job_to_container(jobs_container& cntr, t_executor_func func) + { + cntr.push_back(std::shared_ptr(static_cast(new call_executor_t(func)))); + } + + void init() + { + int num_threads = std::thread::hardware_concurrency(); + this->init(num_threads); + } + void init(unsigned int num_threads) + { + m_is_stop = false; + + for (int i = 0; i < num_threads; i++) + { + m_threads.push_back(std::thread([this]() {this->worker_func(); })); + } + } + + threads_pool() : m_is_stop(false), m_threads_counter(0) + {} + + template + bool add_job(t_executor_func func) + { + { + std::unique_lock lock(m_queue_mutex); + m_jobs_que.push_back(build_call_executor(func)); + } + m_condition.notify_one(); + return true; + } + + void add_batch_and_wait(const jobs_container& cntr) + { + std::condition_variable batch_condition; + std::mutex batch_mutex; + + + std::atomic cnt = 0; + for (const auto& jb : cntr) + { + call_executor_base* pjob = jb.get(); + add_job([&, pjob]() { + pjob->execute(); + { + std::lock_guard lock(batch_mutex); + cnt++; + } + batch_condition.notify_one(); + }); + } + + std::unique_lock lock(batch_mutex); + batch_condition.wait(lock, [&]() + { + return cnt == cntr.size(); + }); + LOG_PRINT_L0("All jobs finiahed"); + } + + ~threads_pool() + { + m_is_stop = true; + m_condition.notify_all(); + for (auto& th : m_threads) + { + th.join(); + } + } + + private: + void worker_func() + { + LOG_PRINT_L0("Worker thread is started"); + while (true) + { + std::shared_ptr job; + { + std::unique_lock lock(m_queue_mutex); + + m_condition.wait(lock, [this]() + { + return !m_jobs_que.empty() || m_is_stop; + }); + if (m_is_stop) + { + LOG_PRINT_L0("Worker thread is finished"); + return; + } + + job = m_jobs_que.front(); + m_jobs_que.pop_front(); + } + + job->execute(); + } + } + + + + jobs_container m_jobs_que; + std::condition_variable m_condition; + std::mutex m_queue_mutex; + std::vector m_threads; + std::atomic m_is_stop; + std::atomic m_threads_counter; + }; +} \ No newline at end of file diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 0c0ce687..df242aff 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -744,11 +744,25 @@ void qt_log_message_handler(QtMsgType type, const QMessageLogContext &context, c } } +bool MainWindow::remove_ipc() +{ + try { + boost::interprocess::message_queue::remove(GUI_IPC_MESSAGE_CHANNEL_NAME); + } + catch (...) + { + } + return true; +} bool MainWindow::init_ipc_server() { + //in case previous instance wasn't close graceful, ipc channel will remain open and new creation will fail, so we + //trying to close it anyway before open, to make sure there are no dead channels. If there are another running instance, it wom't + //let channel to close, so it will fail later on creating channel + remove_ipc(); #define GUI_IPC_BUFFER_SIZE 10000 try { //Create a message queue. @@ -772,21 +786,23 @@ bool MainWindow::init_ipc_server() bool data_received = pmq->timed_receive((void*)buff.data(), GUI_IPC_BUFFER_SIZE, recvd_size, priority, boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) + boost::posix_time::milliseconds(1000)); if (data_received && recvd_size != 0) { + buff.resize(recvd_size, '*'); handle_ipc_event(buff);//todo process token } } - boost::interprocess::message_queue::remove(GUI_IPC_MESSAGE_CHANNEL_NAME); + remove_ipc(); LOG_PRINT_L0("IPC Handling thread finished"); } catch (const std::exception& ex) { + remove_ipc(); boost::interprocess::message_queue::remove(GUI_IPC_MESSAGE_CHANNEL_NAME); LOG_ERROR("Failed to receive IPC que: " << ex.what()); } catch (...) { - boost::interprocess::message_queue::remove(GUI_IPC_MESSAGE_CHANNEL_NAME); + remove_ipc(); LOG_ERROR("Failed to receive IPC que: unknown exception"); } }); @@ -810,8 +826,8 @@ bool MainWindow::init_ipc_server() bool MainWindow::handle_ipc_event(const std::string& arguments) { - std::string zzz = "Received IPC: " + arguments; - message_box(zzz.c_str()); + std::string zzz = std::string("Received IPC: ") + arguments.c_str(); + std::cout << zzz;//message_box(zzz.c_str()); handle_deeplink_click(arguments.c_str()); diff --git a/src/gui/qt-daemon/application/mainwindow.h b/src/gui/qt-daemon/application/mainwindow.h index 974b0bea..4f7af71d 100644 --- a/src/gui/qt-daemon/application/mainwindow.h +++ b/src/gui/qt-daemon/application/mainwindow.h @@ -240,6 +240,7 @@ private: bool load_app_config(); bool init_window(); bool init_ipc_server(); + bool remove_ipc(); std::string get_wallet_log_prefix(size_t wallet_id) const { return m_backend.get_wallet_log_prefix(wallet_id); } diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 02e277cb..22bed634 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 02e277cbda5c9b40f8bb445fb2f6b87a3a780431 +Subproject commit 22bed634e5f3c1da0b4d4b1262d57a2445dba08b diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index c3f0a77a..e8d7a2ed 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -23,6 +23,8 @@ #include "print_struct_to_json.h" #include "free_space_check.h" #include "htlc_hash_tests.h" +#include "threads_pool_tests.h" + int main(int argc, char** argv) { @@ -33,21 +35,23 @@ int main(int argc, char** argv) epee::log_space::log_singletone::get_default_log_file().c_str(), epee::log_space::log_singletone::get_default_log_folder().c_str()); - - std::string buf1 = tools::get_varint_data(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX); - std::string buf2 = tools::get_varint_data(CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX); - std::string buf3 = tools::get_varint_data(CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX); - std::string buf4 = tools::get_varint_data(CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX); - std::string buf5 = tools::get_varint_data(CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX); - std::cout << "Buf1: " << epee::string_tools::buff_to_hex_nodelimer(buf1) << ENDL; - std::cout << "Buf2: " << epee::string_tools::buff_to_hex_nodelimer(buf2) << ENDL; - std::cout << "Buf3: " << epee::string_tools::buff_to_hex_nodelimer(buf3) << ENDL; - std::cout << "Buf4: " << epee::string_tools::buff_to_hex_nodelimer(buf4) << ENDL; - std::cout << "Buf5: " << epee::string_tools::buff_to_hex_nodelimer(buf5) << ENDL; + thread_pool_tests(); - - do_htlc_hash_tests(); +// std::string buf1 = tools::get_varint_data(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX); +// std::string buf2 = tools::get_varint_data(CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX); +// std::string buf3 = tools::get_varint_data(CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX); +// std::string buf4 = tools::get_varint_data(CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX); +// std::string buf5 = tools::get_varint_data(CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX); +// +// std::cout << "Buf1: " << epee::string_tools::buff_to_hex_nodelimer(buf1) << ENDL; +// std::cout << "Buf2: " << epee::string_tools::buff_to_hex_nodelimer(buf2) << ENDL; +// std::cout << "Buf3: " << epee::string_tools::buff_to_hex_nodelimer(buf3) << ENDL; +// std::cout << "Buf4: " << epee::string_tools::buff_to_hex_nodelimer(buf4) << ENDL; +// std::cout << "Buf5: " << epee::string_tools::buff_to_hex_nodelimer(buf5) << ENDL; +// +// + //do_htlc_hash_tests(); //run_serialization_performance_test(); //return 1; //run_core_market_performance_tests(100000); diff --git a/tests/performance_tests/threads_pool_tests.h b/tests/performance_tests/threads_pool_tests.h new file mode 100644 index 00000000..6999ac30 --- /dev/null +++ b/tests/performance_tests/threads_pool_tests.h @@ -0,0 +1,57 @@ +// Copyright (c) 2019 The Zano developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include "include_base_utils.h" +#include "common/threads_pool.h" + + +inline +void thread_pool_tests_simple() +{ + { + utils::threads_pool pool; + pool.init(); + std::atomic count_jobs_finished = 0; + size_t i = 0; + for (; i != 10; i++) + { + pool.add_job([&, i]() {LOG_PRINT_L0("Job " << i << " started"); epee::misc_utils::sleep_no_w(10000); ++count_jobs_finished; LOG_PRINT_L0("Job " << i << " finished"); }); + } + while (count_jobs_finished != i) + { + epee::misc_utils::sleep_no_w(500); + } + LOG_PRINT_L0("All jobs finished"); + } + LOG_PRINT_L0("Scope left"); +} + +inline +void thread_pool_tests() +{ + { + utils::threads_pool pool; + pool.init(); + std::atomic count_jobs_finished = 0; + + utils::threads_pool::jobs_container jobs; + size_t i = 0; + for (; i != 10; i++) + { + utils::threads_pool::add_job_to_container(jobs, [&, i]() {LOG_PRINT_L0("Job " << i << " started"); epee::misc_utils::sleep_no_w(10000); ++count_jobs_finished; LOG_PRINT_L0("Job " << i << " finished"); }); + } + + pool.add_batch_and_wait(jobs); + if (count_jobs_finished != i) + { + LOG_ERROR("Test failed"); + return; + } + LOG_PRINT_L0("All jobs finished"); + } + LOG_PRINT_L0("Scope left"); +} \ No newline at end of file diff --git a/utils/Zano.sh b/utils/Zano.sh index e0eac8cc..6e4d22d8 100755 --- a/utils/Zano.sh +++ b/utils/Zano.sh @@ -29,7 +29,7 @@ create_desktop_icon() echo GenericName=Zano | tee -a $target_file_name > /dev/null echo Comment=Privacy blockchain | tee -a $target_file_name > /dev/null echo Icon=$script_dir/html/files/desktop_linux_icon.png | tee -a $target_file_name > /dev/null - echo Exec=$script_dir/Zano.sh %u | tee -a $target_file_name > /dev/null + echo Exec=$script_dir/Zano.sh --deeplink-params=%u | tee -a $target_file_name > /dev/null echo Terminal=true | tee -a $target_file_name > /dev/null echo Type=Application | tee -a $target_file_name > /dev/null echo "Categories=Qt;Utility;" | tee -a $target_file_name > /dev/null diff --git a/utils/setup_64.iss b/utils/setup_64.iss index adee27a8..364a9767 100644 --- a/utils/setup_64.iss +++ b/utils/setup_64.iss @@ -53,7 +53,7 @@ Root: HKCR; Subkey: "ZanoWalletDataFile\DefaultIcon"; ValueType: string; ValueNa Root: HKCR; Subkey: "ZanoWalletDataKyesFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\Zano.exe,0" Root: HKCR; Subkey: "Zano"; ValueType: string; ValueName: "URL Protocol"; ValueData: "" -Root: HKCR; Subkey: "Zano\shell\open\command"; ValueType: string; ValueName: ""; ValueData: "{app}\Zano.exe %1" +Root: HKCR; Subkey: "Zano\shell\open\command"; ValueType: string; ValueName: ""; ValueData: "{app}\Zano.exe --deeplink-params=%1" [Files]