Improve observer that logs blocked threads.
This commit is contained in:
parent
7866e2e29c
commit
168481fee5
1 changed files with 29 additions and 7 deletions
|
@ -1,9 +1,7 @@
|
||||||
package org.signal.core.util.concurrent
|
package org.signal.core.util.concurrent
|
||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.SystemClock
|
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that polls active threads at a set interval and logs when multiple threads are BLOCKED.
|
* A class that polls active threads at a set interval and logs when multiple threads are BLOCKED.
|
||||||
|
@ -11,6 +9,7 @@ import java.util.concurrent.TimeUnit
|
||||||
class DeadlockDetector(private val handler: Handler, private val pollingInterval: Long) {
|
class DeadlockDetector(private val handler: Handler, private val pollingInterval: Long) {
|
||||||
|
|
||||||
private var running = false
|
private var running = false
|
||||||
|
private val previouslyBlocked: MutableSet<Long> = mutableSetOf()
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
Log.d(TAG, "Beginning deadlock monitoring.");
|
Log.d(TAG, "Beginning deadlock monitoring.");
|
||||||
|
@ -25,13 +24,36 @@ class DeadlockDetector(private val handler: Handler, private val pollingInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun poll() {
|
private fun poll() {
|
||||||
val threads = Thread.getAllStackTraces()
|
val threads: Map<Thread, Array<StackTraceElement>> = Thread.getAllStackTraces()
|
||||||
val blocked = threads.filterKeys { thread -> thread.state == Thread.State.BLOCKED }
|
val blocked: Map<Thread, Array<StackTraceElement>> = threads.filter { entry ->
|
||||||
|
val thread: Thread = entry.key
|
||||||
|
val stack: Array<StackTraceElement> = entry.value
|
||||||
|
|
||||||
|
thread.state == Thread.State.BLOCKED || (thread.state == Thread.State.WAITING && stack.any { it.methodName.startsWith("lock") })
|
||||||
|
}
|
||||||
|
val blockedIds: Set<Long> = blocked.keys.map(Thread::getId).toSet()
|
||||||
|
|
||||||
if (blocked.size > 1) {
|
if (blocked.size > 1) {
|
||||||
Log.w(TAG, buildLogString(blocked))
|
Log.w(TAG, buildLogString("Found multiple blocked threads! Possible deadlock.", blocked))
|
||||||
|
} else {
|
||||||
|
val stillBlocked: Set<Long> = blockedIds.intersect(previouslyBlocked)
|
||||||
|
|
||||||
|
if (stillBlocked.isNotEmpty()) {
|
||||||
|
val stillBlockedMap: Map<Thread, Array<StackTraceElement>> = stillBlocked
|
||||||
|
.map { blockedId ->
|
||||||
|
val key: Thread = blocked.keys.first { it.id == blockedId }
|
||||||
|
val value: Array<StackTraceElement> = blocked[key]!!
|
||||||
|
Pair(key, value)
|
||||||
|
}
|
||||||
|
.toMap()
|
||||||
|
|
||||||
|
Log.w(TAG, buildLogString("Found a long block! Blocked for at least $pollingInterval ms.", stillBlockedMap))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
previouslyBlocked.clear()
|
||||||
|
previouslyBlocked.addAll(blockedIds)
|
||||||
|
|
||||||
if (running) {
|
if (running) {
|
||||||
handler.postDelayed(this::poll, pollingInterval)
|
handler.postDelayed(this::poll, pollingInterval)
|
||||||
}
|
}
|
||||||
|
@ -40,9 +62,9 @@ class DeadlockDetector(private val handler: Handler, private val pollingInterval
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = Log.tag(DeadlockDetector::class.java)
|
private val TAG = Log.tag(DeadlockDetector::class.java)
|
||||||
|
|
||||||
private fun buildLogString(blocked: Map<Thread, Array<StackTraceElement>>): String {
|
private fun buildLogString(description: String, blocked: Map<Thread, Array<StackTraceElement>>): String {
|
||||||
val stringBuilder = StringBuilder()
|
val stringBuilder = StringBuilder()
|
||||||
stringBuilder.append("Found multiple blocked threads! Possible deadlock.\n")
|
stringBuilder.append(description).append("\n")
|
||||||
|
|
||||||
for (entry in blocked) {
|
for (entry in blocked) {
|
||||||
stringBuilder.append("-- [${entry.key.id}] ${entry.key.name}\n")
|
stringBuilder.append("-- [${entry.key.id}] ${entry.key.name}\n")
|
||||||
|
|
Loading…
Add table
Reference in a new issue