diff --git a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientSession.java b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientSession.java index 0df3b0f39..afac104ea 100644 --- a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientSession.java +++ b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientSession.java @@ -240,6 +240,11 @@ private boolean combineOutputs(List vecTally, HashMap= FULL_THREAD_DUMP_INTERVAL_MS && lastFullThreadDumpTime.compareAndSet(last, now); + } + /** * Checks all thread stacks to detect if any thread is stuck in native I/O operations * (peekByteArray or SPVBlockStore operations that freeze on Android). * @return true if a blockstore timeout is detected */ private boolean checkForBlockStoreTimeout() { - Thread.getAllStackTraces().forEach((thread, stackTrace) -> { - String threadName = thread.getName(); - if (threadName.contains("PeerGroup Thread") || threadName.contains("NioClientManager")) { - log.warn("Stack trace for thread '{}' (State: {}):", threadName, thread.getState()); - - boolean foundBlockingCall = false; - for (StackTraceElement element : stackTrace) { - log.warn(" at {}", element); + boolean fullDump = shouldLogFullThreadDump(); + boolean blockStoreTimeout = false; - // Check if this thread is stuck in native peekByteArray or SPVBlockStore operations - String elementStr = element.toString(); - if (elementStr.contains("peekByteArray")) { - foundBlockingCall = true; - } + for (Map.Entry entry : Thread.getAllStackTraces().entrySet()) { + Thread thread = entry.getKey(); + StackTraceElement[] stackTrace = entry.getValue(); + String threadName = thread.getName(); + boolean networkThread = threadName.contains("PeerGroup Thread") || threadName.contains("NioClientManager"); + + // Check if this thread is stuck in native peekByteArray or SPVBlockStore operations + boolean foundBlockingCall = false; + for (StackTraceElement element : stackTrace) { + if (element.toString().contains("peekByteArray")) { + foundBlockingCall = true; + break; } + } - if (foundBlockingCall) { - log.error("CRITICAL: Thread '{}' is stuck in native I/O operation (peekByteArray/SPVBlockStore)", threadName); - } - } else { + // always dump a stuck thread's stack; other threads only on the rate-limited full dump + if (networkThread || foundBlockingCall || fullDump) { log.warn("Stack trace for thread '{}' (State: {}):", threadName, thread.getState()); for (StackTraceElement element : stackTrace) { log.warn(" at {}", element); } } - }); - - // Check all threads for blocking SPVBlockStore calls - for (Thread thread : Thread.getAllStackTraces().keySet()) { - for (StackTraceElement element : thread.getStackTrace()) { - String elementStr = element.toString(); - if (elementStr.contains("peekByteArray")) { - log.error("CRITICAL: Detected SPVBlockStore timeout - native I/O freeze detected in thread: {}", thread.getName()); - return true; + + if (foundBlockingCall) { + blockStoreTimeout = true; + if (networkThread) { + log.error("CRITICAL: Thread '{}' is stuck in native I/O operation (peekByteArray/SPVBlockStore)", threadName); + } else { + log.error("CRITICAL: Detected SPVBlockStore timeout - native I/O freeze detected in thread: {}", threadName); } } } - return false; + return blockStoreTimeout; } /**