Skip to content

Commit dda97d1

Browse files
committed
create_share_fn: unique_lock(try_to_lock) — fix race + freeze risk
Two bugs in the same call site, fixed together: 1. tracker_shared_lock() was a BLOCKING acquire. Same freeze class as the SHAREREQ paths fixed in 2f9d3e1 — when the compute thread held the exclusive write lock for a long think+clean cycle, this would block the io_context until the watchdog fired. 2. create_local_share() called below mutates the tracker via tracker.add() (sharechain.hpp:267 — writes m_shares, m_reverse, heads/tails). ShareChain::add is NOT internally synchronised. Holding only a shared_lock here was a real data race against the compute thread's writes (drop-tails, prune, attempt_verify). Fix: unique_lock with try_to_lock. On busy, log+return (drop the share creation request). The miner will submit again; dropping one request is strictly better than 30 s freeze + SIGABRT + losing all state. The blocking helper tracker_shared_lock() is now caller-less. Left in place with its existing anti-pattern warning so the next session can decide whether to remove it outright.
1 parent 2f9d3e1 commit dda97d1

1 file changed

Lines changed: 27 additions & 1 deletion

File tree

src/c2pool/c2pool_refactored.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4598,7 +4598,33 @@ int main(int argc, char* argv[]) {
45984598
}
45994599

46004600
try {
4601-
auto tracker_lock = p2p_node->tracker_shared_lock();
4601+
// Two bugs being fixed simultaneously:
4602+
// 1. tracker_shared_lock() was BLOCKING — when the
4603+
// compute thread held the exclusive lock for a long
4604+
// think+clean cycle, this would freeze the io_context
4605+
// and trip the watchdog (same class as 2026-04-25).
4606+
// 2. create_local_share() below calls tracker.add() which
4607+
// mutates m_shares + m_reverse + heads/tails — a WRITE
4608+
// under what was a SHARED lock. Real data race
4609+
// against the compute thread which also writes during
4610+
// think (drop-tails, prune, attempt_verify).
4611+
// Both fixed by taking unique_lock(try_to_lock). On busy
4612+
// we drop the share creation request — the miner will
4613+
// submit again, and dropping one request is strictly
4614+
// better than 30 s freeze + SIGABRT + losing all state.
4615+
std::unique_lock<std::shared_mutex> tracker_lock(
4616+
p2p_node->tracker_mutex(), std::try_to_lock);
4617+
if (!tracker_lock.owns_lock()) {
4618+
++s_guard_blocked;
4619+
static std::atomic<int64_t> s_last_drop{0};
4620+
auto now_ns = std::chrono::steady_clock::now().time_since_epoch().count();
4621+
if (now_ns - s_last_drop.load() > 10'000'000'000LL) {
4622+
s_last_drop.store(now_ns);
4623+
LOG_WARNING << "[Pool] create_share dropped: tracker busy"
4624+
<< " (compute thread holds exclusive lock — miner will retry)";
4625+
}
4626+
return;
4627+
}
46024628
if (p.prev_share_hash.IsNull()) {
46034629
auto chain_sz = p2p_node->tracker().chain.size();
46044630
// WAIT mode: block genesis (empty chain) until peers deliver shares

0 commit comments

Comments
 (0)