diff --git a/src/console_commands.cpp b/src/console_commands.cpp index 48922f7..a0a011e 100644 --- a/src/console_commands.cpp +++ b/src/console_commands.cpp @@ -209,7 +209,7 @@ static void do_status(p2pool *m_pool, const char * /* args */) m_pool->print_merge_mining_status(); - bkg_jobs_tracker.print_status(); + bkg_jobs_tracker->print_status(); if (p2p) { p2p->check_for_updates(true); @@ -313,7 +313,7 @@ static void do_stop_mining(p2pool* m_pool, const char* /*args*/) static void do_exit(p2pool *m_pool, const char * /* args */) { - bkg_jobs_tracker.wait(); + bkg_jobs_tracker->wait(); m_pool->stop(); } diff --git a/src/crypto.cpp b/src/crypto.cpp index 2c1079a..cbd7d08 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -37,9 +37,7 @@ class RandomBytes public: RandomBytes() : rng(RandomDeviceSeed::instance), dist(0, 255) { - if (uv_mutex_init(&m) != 0) { - abort(); - } + uv_mutex_init_checked(&m); // Diffuse the initial state in case it has low quality rng.discard(10000); @@ -66,7 +64,7 @@ private: std::uniform_int_distribution<> dist; }; -static RandomBytes randomBytes; +static RandomBytes* randomBytes = nullptr; } @@ -86,7 +84,7 @@ static FORCEINLINE bool less32(const uint8_t* k0, const uint8_t* k1) void generate_keys(hash& pub, hash& sec) { do { - do { randomBytes(sec.h); } while (!less32(sec.h, limit)); + do { (*randomBytes)(sec.h); } while (!less32(sec.h, limit)); sc_reduce32(sec.h); } while (!sc_isnonzero(sec.h)); @@ -472,6 +470,10 @@ void derive_view_tag(const hash& derivation, size_t output_index, uint8_t& view_ void init_crypto_cache() { + if (!randomBytes) { + randomBytes = new RandomBytes(); + } + if (!cache) { cache = new Cache(); } @@ -479,9 +481,15 @@ void init_crypto_cache() void destroy_crypto_cache() { - if (cache) { - delete cache; + { + auto p = randomBytes; + randomBytes = nullptr; + delete p; + } + { + auto p = cache; cache = nullptr; + delete p; } } diff --git a/src/keccak.cpp b/src/keccak.cpp index f8a2338..f204057 100644 --- a/src/keccak.cpp +++ b/src/keccak.cpp @@ -116,17 +116,14 @@ NOINLINE void keccakf_plain(std::array& st) } } -void (*keccakf)(std::array&) = keccakf_plain; - +keccakf_func keccakf = []() { #if defined(__x86_64__) || defined(_M_AMD64) -static struct KeccakBMI_Check { - KeccakBMI_Check() { - if (randomx::Cpu().hasBmi()) { - keccakf = keccakf_bmi; - } + if (randomx::Cpu().hasBmi()) { + return keccakf_bmi; } -} keccak_bmi_check; #endif + return keccakf_plain; +}(); NOINLINE void keccak_step(const uint8_t* &in, int &inlen, std::array& st) { diff --git a/src/keccak.h b/src/keccak.h index b735ed9..aee0ef7 100644 --- a/src/keccak.h +++ b/src/keccak.h @@ -25,7 +25,9 @@ enum KeccakParams { }; extern const uint64_t keccakf_rndc[24]; -extern void (*keccakf)(std::array& st); + +typedef void (*keccakf_func)(std::array&); +extern keccakf_func keccakf; void keccakf_plain(std::array& st); void keccakf_bmi(std::array& st); diff --git a/src/log.cpp b/src/log.cpp index 8d2223e..9c76e96 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -117,12 +117,10 @@ public: FORCEINLINE Worker() : m_writePos(0) , m_readPos(0) - , m_started{ false } , m_stopped(false) { #if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) SetUnhandledExceptionFilter(UnhandledExceptionFilter); - SymInitialize(GetCurrentProcess(), NULL, TRUE); #endif set_main_thread(); @@ -133,22 +131,9 @@ public: m_buf.resize(BUF_SIZE); - // Create default loop here - uv_default_loop(); - uv_cond_init(&m_cond); uv_mutex_init(&m_mutex); - const int err = uv_thread_create(&m_worker, run_wrapper, this); - if (err) { - fprintf(stderr, "failed to start logger thread (%s), aborting\n", uv_err_name(err)); - abort(); - } - - while (m_started.load() == false) { - std::this_thread::yield(); - } - #ifdef _WIN32 SetConsoleMode(hStdIn, ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_EXTENDED_FLAGS); @@ -163,13 +148,17 @@ public: CONSOLE_COLORS = false; } - LOGINFO(0, "started"); - if (!m_logFile.is_open()) { - LOGERR(0, "failed to open " << log_file_name); + fprintf(stderr, "failed to open %s\n", log_file_name); } init_uv_threadpool(); + + const int err = uv_thread_create(&m_worker, run_wrapper, this); + if (err) { + fprintf(stderr, "failed to start logger thread (%s), aborting\n", uv_err_name(err)); + abort(); + } } ~Worker() @@ -196,17 +185,8 @@ public: uv_thread_join(&m_worker); uv_cond_destroy(&m_cond); uv_mutex_destroy(&m_mutex); - uv_loop_close(uv_default_loop()); - -#if ((UV_VERSION_MAJOR > 1) || ((UV_VERSION_MAJOR == 1) && (UV_VERSION_MINOR >= 38))) - uv_library_shutdown(); -#endif m_logFile.close(); - -#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) - SymCleanup(GetCurrentProcess()); -#endif } FORCEINLINE void write(const char* buf, uint32_t size) @@ -252,13 +232,13 @@ private: int err = putenv(buf); if (err != 0) { err = errno; - LOGWARN(0, "Couldn't set UV thread pool size to " << N << " threads, putenv returned error " << err); + fprintf(stderr, "Couldn't set UV thread pool size to %u threads, putenv returned error %d\n", N, err); } static uv_work_t dummy; err = uv_queue_work(uv_default_loop_checked(), &dummy, [](uv_work_t*) {}, nullptr); if (err) { - LOGERR(0, "init_uv_threadpool: uv_queue_work failed, error " << uv_err_name(err)); + fprintf(stderr, "init_uv_threadpool: uv_queue_work failed, error %s\n", uv_err_name(err)); } } @@ -267,8 +247,6 @@ private: NOINLINE void run() { - m_started.exchange(true); - do { uv_mutex_lock(&m_mutex); if (m_readPos == m_writePos.load()) { @@ -392,13 +370,12 @@ private: uv_mutex_t m_mutex; uv_thread_t m_worker; - std::atomic m_started; bool m_stopped; std::ofstream m_logFile; }; -static Worker worker; +static Worker* worker = nullptr; #endif // P2POOL_LOG_DISABLE @@ -445,7 +422,16 @@ NOINLINE Writer::~Writer() m_buf[2] = static_cast(size >> 8); m_buf[m_pos] = '\n'; #ifndef P2POOL_LOG_DISABLE - worker.write(m_buf, size); + worker->write(m_buf, size); +#endif +} + +void start() +{ +#ifndef P2POOL_LOG_DISABLE + worker = new Worker(); + + LOGINFO(0, "started"); #endif } @@ -458,7 +444,8 @@ void reopen() void stop() { #ifndef P2POOL_LOG_DISABLE - worker.stop(); + delete worker; + worker = nullptr; #endif } diff --git a/src/log.h b/src/log.h index c1bcc70..a18a630 100644 --- a/src/log.h +++ b/src/log.h @@ -547,6 +547,7 @@ struct DummyStream #endif +void start(); void reopen(); void stop(); diff --git a/src/main.cpp b/src/main.cpp index 4bf3485..30f0a24 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,14 @@ #include "randomx.h" #endif +#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) + +#include + +#pragma comment(lib, "Dbghelp.lib") + +#endif + void p2pool_usage() { printf("P2Pool %s\n" @@ -188,8 +196,17 @@ int main(int argc, char* argv[]) } } +#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) + SymInitialize(GetCurrentProcess(), NULL, TRUE); +#endif + memory_tracking_start(); + // Create default loop here + uv_default_loop(); + + p2pool::log::start(); + p2pool::init_crypto_cache(); int result = static_cast(curl_global_init_mem(CURL_GLOBAL_ALL, p2pool::malloc_hook, p2pool::free_hook, p2pool::realloc_hook, p2pool::strdup_hook, p2pool::calloc_hook)); @@ -209,9 +226,21 @@ int main(int argc, char* argv[]) p2pool::destroy_crypto_cache(); + p2pool::log::stop(); + + uv_loop_close(uv_default_loop()); + +#if ((UV_VERSION_MAJOR > 1) || ((UV_VERSION_MAJOR == 1) && (UV_VERSION_MINOR >= 38))) + uv_library_shutdown(); +#endif + if (!memory_tracking_stop()) { result = 1; } +#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) + SymCleanup(GetCurrentProcess()); +#endif + return result; } diff --git a/src/memory_leak_debug.cpp b/src/memory_leak_debug.cpp index 9609584..c96cecf 100644 --- a/src/memory_leak_debug.cpp +++ b/src/memory_leak_debug.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include @@ -79,7 +81,7 @@ struct TrackedAllocation static_assert(sizeof(TrackedAllocation) == 256, ""); -uv_mutex_t allocation_lock; +std::mutex allocation_lock; std::hash hasher; uint32_t first[N]; uint32_t next[N]; @@ -98,7 +100,7 @@ void show_top_10_allocations() const HANDLE h = GetCurrentProcess(); { - p2pool::MutexLock lock(allocation_lock); + std::lock_guard lock(allocation_lock); TrackedAllocation* end = buf; for (size_t i = 0; i < N; ++i) { @@ -173,7 +175,7 @@ FORCEINLINE static void add_alocation(void* p, size_t size) const size_t index = hasher(p) & (N - 1); - p2pool::MutexLock lock(allocation_lock); + std::lock_guard lock(allocation_lock); ++num_allocations; if (num_allocations >= N / 2) { @@ -204,7 +206,7 @@ FORCEINLINE static void remove_allocation(void* p) return; } - p2pool::MutexLock lock(allocation_lock); + std::lock_guard lock(allocation_lock); --num_allocations; @@ -292,10 +294,14 @@ void memory_tracking_start() // Trigger std::ostream initialization to avoid reporting it as leaks std::cout << "Memory leak detection = " << 1 << std::endl; + // Trigger std::ofstream initialization to avoid reporting it as leaks + { + std::ofstream tmp("memory_tracking.tmp"); + } + using namespace p2pool; uv_replace_allocator(malloc_hook, realloc_hook, calloc_hook, free_hook); - uv_mutex_init_checked(&allocation_lock); track_memory = true; } @@ -304,7 +310,6 @@ bool memory_tracking_stop() using namespace p2pool; track_memory = false; - uv_mutex_destroy(&allocation_lock); const HANDLE h = GetCurrentProcess(); diff --git a/src/p2pool.cpp b/src/p2pool.cpp index 5fff44f..d355c6c 100644 --- a/src/p2pool.cpp +++ b/src/p2pool.cpp @@ -73,6 +73,8 @@ p2pool::p2pool(int argc, char* argv[]) m_params = p; + bkg_jobs_tracker = new BackgroundJobTracker(); + #ifdef WITH_UPNP if (p->m_upnp) { init_upnp(); @@ -184,6 +186,8 @@ p2pool::p2pool(int argc, char* argv[]) m_hasher = new RandomX_Hasher_RPC(this); #endif + PoolBlock::s_precalculatedSharesLock = new ReadWriteLock(); + m_blockTemplate = new BlockTemplate(m_sideChain, m_hasher); m_mempool = new Mempool(); @@ -232,6 +236,17 @@ p2pool::~p2pool() delete m_blockTemplate; delete m_mempool; delete m_params; + + { + auto p = bkg_jobs_tracker; + bkg_jobs_tracker = nullptr; + delete p; + } + { + auto p = PoolBlock::s_precalculatedSharesLock; + PoolBlock::s_precalculatedSharesLock = nullptr; + delete p; + } } void p2pool::update_host_ping(const std::string& display_name, double ping) @@ -1955,7 +1970,7 @@ int p2pool::run() m_stopped = true; - bkg_jobs_tracker.wait(); + bkg_jobs_tracker->wait(); #ifdef WITH_RANDOMX delete m_miner; diff --git a/src/pool_block.cpp b/src/pool_block.cpp index 2063be2..94bf7bb 100644 --- a/src/pool_block.cpp +++ b/src/pool_block.cpp @@ -29,7 +29,7 @@ LOG_CATEGORY(PoolBlock) namespace p2pool { -ReadWriteLock PoolBlock::s_precalculatedSharesLock; +ReadWriteLock* PoolBlock::s_precalculatedSharesLock = nullptr; PoolBlock::PoolBlock() : m_majorVersion(0) @@ -118,7 +118,7 @@ PoolBlock& PoolBlock::operator=(const PoolBlock& b) m_wantBroadcast = b.m_wantBroadcast; m_precalculated = b.m_precalculated; { - WriteLock lock(s_precalculatedSharesLock); + WriteLock lock(*s_precalculatedSharesLock); m_precalculatedShares = b.m_precalculatedShares; } @@ -309,7 +309,7 @@ void PoolBlock::reset_offchain_data() m_precalculated = false; { - WriteLock lock(s_precalculatedSharesLock); + WriteLock lock(*s_precalculatedSharesLock); m_precalculatedShares.clear(); m_precalculatedShares.shrink_to_fit(); } diff --git a/src/pool_block.h b/src/pool_block.h index 866382d..53ace67 100644 --- a/src/pool_block.h +++ b/src/pool_block.h @@ -162,7 +162,7 @@ struct PoolBlock bool m_precalculated; - static ReadWriteLock s_precalculatedSharesLock; + static ReadWriteLock* s_precalculatedSharesLock; std::vector m_precalculatedShares; uint64_t m_localTimestamp; diff --git a/src/side_chain.cpp b/src/side_chain.cpp index 2c61564..57b6c7b 100644 --- a/src/side_chain.cpp +++ b/src/side_chain.cpp @@ -1683,7 +1683,7 @@ void SideChain::verify(PoolBlock* block) std::vector shares; if (block->m_precalculated) { - WriteLock lock(PoolBlock::s_precalculatedSharesLock); + WriteLock lock(*PoolBlock::s_precalculatedSharesLock); shares = std::move(block->m_precalculatedShares); } @@ -2356,7 +2356,7 @@ void SideChain::launch_precalc(const PoolBlock* block) if (get_shares(b, shares, nullptr, true)) { b->m_precalculated = true; { - WriteLock lock(PoolBlock::s_precalculatedSharesLock); + WriteLock lock(*PoolBlock::s_precalculatedSharesLock); b->m_precalculatedShares = std::move(shares); } { @@ -2401,7 +2401,7 @@ void SideChain::precalc_worker() wallets.clear(); - ReadLock lock2(PoolBlock::s_precalculatedSharesLock); + ReadLock lock2(*PoolBlock::s_precalculatedSharesLock); const size_t n = job->m_precalculatedShares.size(); diff --git a/src/util.cpp b/src/util.cpp index 137dafc..b4f3271 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -452,7 +452,7 @@ void BackgroundJobTracker::print_status() m_impl->print_status(); } -BackgroundJobTracker bkg_jobs_tracker; +BackgroundJobTracker* bkg_jobs_tracker = nullptr; static thread_local bool main_thread = false; void set_main_thread() { main_thread = true; } diff --git a/src/util.h b/src/util.h index 27d150d..f531e22 100644 --- a/src/util.h +++ b/src/util.h @@ -233,10 +233,10 @@ private: Impl* m_impl; }; -extern BackgroundJobTracker bkg_jobs_tracker; +extern BackgroundJobTracker* bkg_jobs_tracker; -#define BACKGROUND_JOB_START(x) do { bkg_jobs_tracker.start(#x); } while (0) -#define BACKGROUND_JOB_STOP(x) do { bkg_jobs_tracker.stop(#x); } while (0) +#define BACKGROUND_JOB_START(x) do { bkg_jobs_tracker->start(#x); } while (0) +#define BACKGROUND_JOB_STOP(x) do { bkg_jobs_tracker->stop(#x); } while (0) void set_main_thread(); bool is_main_thread(); diff --git a/tests/src/main.cpp b/tests/src/main.cpp index 020ca33..8a240e3 100644 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -15,14 +15,26 @@ * along with this program. If not, see . */ +#include "common.h" +#include "util.h" +#include "pool_block.h" + #include "gtest/gtest.h" void p2pool_usage() {} -namespace p2pool { void set_main_thread(); } + +using namespace p2pool; int main(int argc, char** argv) { - p2pool::set_main_thread(); + set_main_thread(); + + PoolBlock::s_precalculatedSharesLock = new ReadWriteLock(); + testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + const int result = RUN_ALL_TESTS(); + + delete PoolBlock::s_precalculatedSharesLock; + + return result; }