• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.coroutines
6 
7 private const val WAIT_LOST_THREADS = 10_000L // 10s
8 private val ignoreLostThreads = mutableSetOf<String>()
9 
10 fun ignoreLostThreads(vararg s: String) { ignoreLostThreads += s }
11 
currentThreadsnull12 fun currentThreads(): Set<Thread> {
13     var estimate = 0
14     while (true) {
15         estimate = estimate.coerceAtLeast(Thread.activeCount() + 1)
16         val arrayOfThreads = Array<Thread?>(estimate) { null }
17         val n = Thread.enumerate(arrayOfThreads)
18         if (n >= estimate) {
19             estimate = n + 1
20             continue // retry with a better size estimate
21         }
22         val threads = hashSetOf<Thread>()
23         for (i in 0 until n)
24             threads.add(arrayOfThreads[i]!!)
25         return threads
26     }
27 }
28 
dumpThreadsnull29 fun List<Thread>.dumpThreads(header: String) {
30     println("=== $header")
31     forEach { thread ->
32         println("Thread \"${thread.name}\" ${thread.state}")
33         val trace = thread.stackTrace
34         for (t in trace) println("\tat ${t.className}.${t.methodName}(${t.fileName}:${t.lineNumber})")
35         println()
36     }
37     println("===")
38 }
39 
dumpThreadsnull40 fun ExecutorCoroutineDispatcher.dumpThreads(header: String) =
41     currentThreads().filter { it is PoolThread && it.dispatcher == this@dumpThreads }.dumpThreads(header)
42 
checkTestThreadsnull43 fun checkTestThreads(threadsBefore: Set<Thread>) {
44     // give threads some time to shutdown
45     val waitTill = System.currentTimeMillis() + WAIT_LOST_THREADS
46     var diff: List<Thread>
47     do {
48         val threadsAfter = currentThreads()
49         diff = (threadsAfter - threadsBefore).filter { thread ->
50             ignoreLostThreads.none { prefix -> thread.name.startsWith(prefix) }
51         }
52         if (diff.isEmpty()) break
53     } while (System.currentTimeMillis() <= waitTill)
54     ignoreLostThreads.clear()
55     if (diff.isEmpty()) return
56     val message = "Lost threads ${diff.map { it.name }}"
57     println("!!! $message")
58     diff.dumpThreads("Dumping lost thread stack traces")
59     error(message)
60 }
61