From 09ddda7dba0e2a6728d2b9429c2f3115bd0813d5 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 5 Mar 2025 14:51:11 +0400 Subject: [PATCH] fixed ancient p2p bug --- .../epee/include/net/abstract_tcp_server2.inl | 18 ++++++++ .../net/levin_protocol_handler_async.h | 6 +++ contrib/epee/include/syncobj.h | 41 ++++++++++++++++--- src/common/pre_download.h | 2 +- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 6829b645..3f5aa31b 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -44,6 +44,18 @@ namespace net_utils { /************************************************************************/ DISABLE_VS_WARNINGS(4355) + + +template > +struct has_pre_destructor_handler : std::false_type {}; + +// This specialization is selected if T has a valid 'b()' that can be called +template +struct has_pre_destructor_handler().on_pre_destroy())>> + : std::true_type {}; + + + template connection::connection(boost::asio::io_service& io_service, typename t_protocol_handler::config_type& config, volatile uint32_t& sock_count, i_connection_filter*& pfilter) @@ -66,6 +78,12 @@ connection::~connection() { NESTED_TRY_ENTRY(); + if constexpr (has_pre_destructor_handler::value) + { + m_protocol_handler.on_pre_destroy(); + } + + if(!m_was_shutdown) { LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Socket destroyed without shutdown."); shutdown(); diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h index c3cdd02d..d85fa428 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -252,6 +252,7 @@ public: LOG_PRINT_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "] CONSTRUCTED", LOG_LEVEL_4); } + virtual ~async_protocol_handler() { NESTED_TRY_ENTRY(); @@ -278,6 +279,11 @@ public: NESTED_CATCH_ENTRY(__func__); } + void on_pre_destroy() + { + m_config.del_connection(this); + } + bool start_outer_call() { LOG_PRINT_CC_L4(m_connection_context, "[LEVIN_PROTOCOL" << this << "] -->> start_outer_call"); diff --git a/contrib/epee/include/syncobj.h b/contrib/epee/include/syncobj.h index 9971ef12..73f84b15 100644 --- a/contrib/epee/include/syncobj.h +++ b/contrib/epee/include/syncobj.h @@ -277,7 +277,7 @@ namespace epee #define POTENTIAL_HANG_PREVENT_LIMIT 1000 - +#define DEADLOCK_GUARD_JOURNAL_LIMIT 1000 /************************************************************************/ /* */ @@ -290,11 +290,11 @@ namespace epee struct thread_info { std::map m_owned_objects; - bool is_blocked; - lock_reference_type blocker_lock; - const char* block_location; - const char* func_name; - const char* lock_name; + bool is_blocked = false; + lock_reference_type blocker_lock = nullptr; + const char* block_location = "unknown"; + const char* func_name = "unknown"; + const char* lock_name = "unknown"; std::string thread_name; }; @@ -307,6 +307,18 @@ namespace epee std::map m_owned_locks_to_thread; // deadlock journal std::list m_deadlock_journal; + //lock/unlock journal + struct journal_entry + { + std::thread::id tid; + lock_reference_type lock = nullptr; + bool is_lock_event = false; + const char* func_name = "unkonwn"; + const char* lock_name = "unkonwn"; + std::string thread_name; + }; + + std::list m_journal; public: void on_before_lock(lock_reference_type lock, const char* func_name, const char* loction, const char* lock_name, const std::string& thread_name) @@ -363,6 +375,10 @@ namespace epee } else { + m_journal.push_front(journal_entry{ this_id, lock, false, "", "", ""}); + if (m_journal.size() > DEADLOCK_GUARD_JOURNAL_LIMIT) + m_journal.pop_back(); + m_owned_locks_to_thread.erase(lock_to_thread_it); } it->second.m_owned_objects.erase(ownership_it); @@ -400,6 +416,15 @@ namespace epee ss << "-----------------------------------------------------------------------" << std::endl << err << std::endl; } + ss << "Ownership history history:" << std::endl; + size_t count = 0; + for (auto entry : m_journal) + { + ss << "tid(" << entry.thread_name << "): " << entry.tid << ", lock_addr: " << entry.lock << (entry.is_lock_event ? "-->":"<--") << ", func: " << (entry.func_name ? entry.func_name:"") << ", lock_name: " << (entry.lock_name ? entry.lock_name : "") << std::endl; + if (++count > 100) + break; + } + return ss.str(); } @@ -429,6 +454,10 @@ namespace epee //need to add lock-to-thread reccord m_owned_locks_to_thread[lock] = it; DO_DEBUG_COUT("[" << std::this_thread::get_id() << "][ADDED_OWNERSHIP]: " << lock << std::endl); + m_journal.push_front(journal_entry{ this_id, lock, true, it->second.func_name, it->second.lock_name, it->second.thread_name }); + if (m_journal.size() > DEADLOCK_GUARD_JOURNAL_LIMIT) + m_journal.pop_back(); + } else { diff --git a/src/common/pre_download.h b/src/common/pre_download.h index c44649a0..9314c059 100644 --- a/src/common/pre_download.h +++ b/src/common/pre_download.h @@ -59,7 +59,7 @@ namespace tools } // okay, let's download - + LOG_PRINT_MAGENTA("Pre-download required: local db size: " << sz << ", pre_download.unpacked_size = " << pre_download.unpacked_size << ", flag_force_predownload: " << (flag_force_predownload ? "true":"false"), LOG_LEVEL_0); std::string downloading_file_path = db_main_file_path + ".download"; if (!command_line::has_arg(vm, command_line::arg_process_predownload_from_path)) {