Skip to content

btc(v36): complete livelock mirror — hold tracker lock across IO-thread share mutations - #117

Merged
frstrtr merged 1 commit into
masterfrom
btc/v36-livelock-mirror-complete
Jun 16, 2026
Merged

btc(v36): complete livelock mirror — hold tracker lock across IO-thread share mutations#117
frstrtr merged 1 commit into
masterfrom
btc/v36-livelock-mirror-complete

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Completes the BTC twin of the contabo run_think() livelock / kr1z1s SIGSEGV fix.

Gate

LTC fix has landed on master:

  • f445db8e ltc/node: hold tracker lock across chain access in IO-thread share paths
  • 2f9d3e1a Fix event-loop freeze: try_to_lock in IO-thread tracker accesses

PR #97 (ee906e8a) landed only the watchdog half of the BTC mirror; the lock-yield half was inert (test-then-release). This PR mirrors f445db8e 1:1 onto src/impl/btc/node.cpp.

Changes (BTC-only)

  1. processing_shares_phase2() — previously held the try_to_lock only to TEST availability, released it, then ran m_tracker.add() lock-free on the "think() isnt running" assumption. The compute-thread clean_tracker() prune could grab the lock the instant phase2 released it and free chain nodes mid-mutation → SIGSEGV. The unique_lock is now held across the whole mutation body and released (lock.unlock()) immediately before the async run_think() trigger. BTC-only backpressure cap (MAX_PENDING_ADDS) preserved inside the !owns_lock() branch.
  2. notify_local_share() — bare m_tracker.chain.contains() in the early-return ran outside the lock. Moved under the existing try_to_lock guard (owns_lock() && contains()); on contention the inline verify is skipped and run_think() scores the share next cycle.

Verification

  • Builds clean: cmake --build build --target c2pool-btc -j16 → BUILD_EXIT=0 (warnings only).
  • Diff: 1 file, +42/-29, no cross-coin surface (BTC-only, no 4-coin smoke gate).
  • Commit e8abf28d GPG-signed.

Merge operator-gated.

…ad share mutations

Mirrors LTC f445db8 onto the BTC twin. PR #97 landed only the watchdog
half; the lock-yield half was inert (test-then-release). Two IO-thread
sites read/mutated m_tracker.chain racing the compute-thread clean_tracker()
exclusive prune (drop_tails), freeing chain nodes mid-access -> SIGSEGV
(kr1z1s LTC/DGB shape):

  - processing_shares_phase2(): held the try_to_lock only to TEST availability,
    released it, then ran m_tracker.add() lock-free. The unique_lock is now held
    across the whole mutation body and released just before the async run_think()
    trigger. BTC-only backpressure cap (MAX_PENDING_ADDS) preserved.
  - notify_local_share(): bare m_tracker.chain.contains() in the early-return ran
    outside the lock. Moved under the existing try_to_lock guard
    (owns_lock() && contains()); on contention the inline verify is skipped and
    run_think() scores the share next cycle.

BTC-only (src/impl/btc/node.cpp). Same non-blocking IO-thread contract
(busy -> defer/queue, never block).
@frstrtr
frstrtr merged commit fd18df8 into master Jun 16, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant