@@ -9,6 +9,7 @@ import kotlinx.coroutines.internal.AVAILABLE_PROCESSORS
9
9
import org.junit.Test
10
10
import java.util.*
11
11
import java.util.concurrent.ConcurrentHashMap
12
+ import java.util.concurrent.CountDownLatch
12
13
import java.util.concurrent.CyclicBarrier
13
14
import java.util.concurrent.atomic.AtomicInteger
14
15
import kotlin.random.*
@@ -18,63 +19,76 @@ import kotlin.time.*
18
19
19
20
class CoroutineSchedulerInternalApiStressTest : TestBase () {
20
21
21
- @Test
22
- fun testHelpDefaultIoIsIsolated () {
23
- repeat(10 ) {
24
- runTest {
25
- val jobToComplete = Job ()
26
- val tasksToCompleteJob = AtomicInteger (200 )
22
+ @Test(timeout = 120_000L )
23
+ fun testHelpDefaultIoIsIsolated () = repeat(100 * stressTestMultiplierSqrt) {
24
+ val ioTaskMarker = ThreadLocal .withInitial { false }
25
+ var threadThatShould = Thread .currentThread()
26
+ runTest {
27
+ val jobToComplete = Job ()
28
+ val expectedIterations = 100
29
+ val completionLatch = CountDownLatch (1 )
30
+ val tasksToCompleteJob = AtomicInteger (expectedIterations)
31
+ val observedIoThreads = Collections .newSetFromMap(ConcurrentHashMap <Thread , Boolean >())
32
+ val observedDefaultThreads = Collections .newSetFromMap(ConcurrentHashMap <Thread , Boolean >())
27
33
28
- val observedIoThreads = Collections .newSetFromMap(ConcurrentHashMap <Thread , Boolean >())
29
- val observedDefaultThreads = Collections .newSetFromMap(ConcurrentHashMap <Thread , Boolean >())
30
-
31
- val barrier = CyclicBarrier (AVAILABLE_PROCESSORS )
32
- repeat(AVAILABLE_PROCESSORS - 1 ) {
33
- // Launch CORES - 1 spawners
34
- launch(Dispatchers .Default ) {
35
- barrier.await()
36
- while (! jobToComplete.isCompleted) {
37
- launch {
38
- observedDefaultThreads.add(Thread .currentThread())
39
- val tasksLeft = tasksToCompleteJob.decrementAndGet()
40
- if (tasksLeft == 0 ) {
41
- // Verify threads first
42
- try {
43
- assertFalse(observedIoThreads.containsAll(observedDefaultThreads))
44
- } finally {
45
- jobToComplete.complete()
46
- }
34
+ val barrier = CyclicBarrier (AVAILABLE_PROCESSORS )
35
+ val spawners = ArrayList <Job >()
36
+ repeat(AVAILABLE_PROCESSORS - 1 ) {
37
+ // Launch CORES - 1 spawners
38
+ spawners + = launch(Dispatchers .Default ) {
39
+ barrier.await()
40
+ repeat(expectedIterations) {
41
+ launch {
42
+ val tasksLeft = tasksToCompleteJob.decrementAndGet()
43
+ if (tasksLeft < 0 ) return @launch // Leftovers are being executed all over the place
44
+ if (threadThatShould != = Thread .currentThread()) {
45
+ val a = 2
46
+ }
47
+ observedDefaultThreads.add(Thread .currentThread())
48
+ if (tasksLeft == 0 ) {
49
+ // Verify threads first
50
+ try {
51
+ assertFalse(observedIoThreads.containsAll(observedDefaultThreads))
52
+ } finally {
53
+ jobToComplete.complete()
47
54
}
48
55
}
56
+ }
49
57
50
- // Sometimes launch an IO task
51
- if (Random .nextInt(0 .. 9 ) == 0 ) {
52
- launch(Dispatchers .IO ) {
53
- observedIoThreads.add( Thread .currentThread() )
54
- assertTrue (Thread .currentThread().isIoDispatcherThread ())
55
- }
58
+ // Sometimes launch an IO task to mess with a scheduler
59
+ if (Random .nextInt(0 .. 9 ) == 0 ) {
60
+ launch(Dispatchers .IO ) {
61
+ ioTaskMarker.set( true )
62
+ observedIoThreads.add (Thread .currentThread())
63
+ assertTrue( Thread .currentThread().isIoDispatcherThread())
56
64
}
57
65
}
58
66
}
67
+ completionLatch.await()
59
68
}
69
+ }
60
70
61
- withContext(Dispatchers .Default ) {
62
- barrier.await()
63
-
64
- while (! jobToComplete.isCompleted) {
65
- val result = runSingleTaskFromCurrentSystemDispatcher()
66
- if (result == 0L ) {
67
- continue
68
- } else if (result >= 0L ) {
69
- delay(result.toDuration(DurationUnit .NANOSECONDS ))
70
- } else {
71
- delay(10 )
72
- }
71
+ withContext(Dispatchers .Default ) {
72
+ threadThatShould = Thread .currentThread()
73
+ barrier.await()
74
+ var timesHelped = 0
75
+ while (! jobToComplete.isCompleted) {
76
+ val result = runSingleTaskFromCurrentSystemDispatcher()
77
+ assertFalse(ioTaskMarker.get())
78
+ if (result == 0L ) {
79
+ ++ timesHelped
80
+ continue
81
+ } else if (result >= 0L ) {
82
+ Thread .sleep(result.toDuration(DurationUnit .NANOSECONDS ).toDelayMillis())
83
+ } else {
84
+ Thread .sleep(10 )
73
85
}
74
- assertTrue(Thread .currentThread() in observedDefaultThreads)
75
86
}
76
- coroutineContext.job.children.toList().joinAll()
87
+ completionLatch.countDown()
88
+ // assertEquals(100, timesHelped)
89
+ // assertTrue(Thread.currentThread() in observedDefaultThreads, observedDefaultThreads.toString())
77
90
}
78
91
}
79
92
}
80
93
}
94
+
0 commit comments