Fix crash from race condition in miner::stop()

miner::stop() destroys threads without joining them, which can call
`std::terminate()` and abort the program if any of the threads are still
active (which happens to me consistently under --regtest).

This fixes the code to properly join threads rather than using a custom
racey hack with a sleep loop.
This commit is contained in:
Jason Rhinelander 2020-08-02 13:11:12 -03:00
parent d0e2fdb87e
commit 742d005fc1
2 changed files with 12 additions and 15 deletions

View file

@ -72,7 +72,6 @@ namespace cryptonote
m_phandler(phandler),
m_gbh(gbh),
m_height(0),
m_threads_active(0),
m_pausers_count(0),
m_threads_total(0),
m_starter_nonce(0),
@ -221,13 +220,12 @@ namespace cryptonote
}
// restart all threads
{
std::unique_lock lock{m_threads_lock};
m_stop = true;
while (m_threads_active > 0)
epee::misc_utils::sleep_no_w(100);
m_threads.clear();
}
std::unique_lock lock{m_threads_lock};
m_stop = true;
for (auto& th : m_threads)
if (th.joinable())
th.join();
m_threads.clear();
m_stop = false;
m_thread_index = 0;
for(size_t i = 0; i != m_threads_total; i++)
@ -376,9 +374,9 @@ namespace cryptonote
}
m_stop = true;
while (m_threads_active > 0)
epee::misc_utils::sleep_no_w(100);
for (auto& th : m_threads)
if (th.joinable())
th.join();
MINFO("Mining has been stopped, " << m_threads.size() << " finished" );
m_threads.clear();
m_threads_autodetect.clear();
@ -445,7 +443,6 @@ namespace cryptonote
uint32_t local_template_ver = 0;
block b;
rx_slow_hash_allocate_state();
++m_threads_active;
bool call_stop = false;
#if defined(LOKI_ENABLE_INTEGRATION_TEST_HOOKS)
call_stop = true;
@ -520,9 +517,10 @@ namespace cryptonote
}
rx_slow_hash_free_state();
MGINFO("Miner thread stopped ["<< th_local_index << "]");
--m_threads_active;
if (call_stop)
stop();
// Call in a detached thread because the thread calling stop() needs to be able to join this
// worker thread.
std::thread{[this] { stop(); }}.detach();
return true;
}
}

View file

@ -121,7 +121,6 @@ namespace cryptonote
uint64_t m_height;
std::atomic<uint32_t> m_thread_index;
std::atomic<uint32_t> m_threads_total;
std::atomic<uint32_t> m_threads_active;
std::atomic<int32_t> m_pausers_count;
std::mutex m_miners_count_lock;