blob: 9f3229afcaa442bd47a7514759a781ff8ee2410a [file] [log] [blame]
Roman Elizarov174c6962017-02-28 17:36:51 +03001/*
Roman Elizarov1f74a2d2018-06-29 19:19:45 +03002 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Roman Elizarov174c6962017-02-28 17:36:51 +03003 */
4
5package kotlinx.coroutines.experimental.selects
6
7import kotlinx.coroutines.experimental.*
Roman Elizarov9fe5f462018-02-21 19:05:52 +03008import kotlinx.coroutines.experimental.sync.*
9import org.junit.*
10import org.junit.Assert.*
11import kotlin.coroutines.experimental.*
Roman Elizarov174c6962017-02-28 17:36:51 +030012
Roman Elizarovebe18b42017-02-28 17:50:55 +030013class SelectPhilosophersStressTest : TestBase() {
14 val TEST_DURATION = 3000L * stressTestMultiplier
Roman Elizarov174c6962017-02-28 17:36:51 +030015
16 val n = 10 // number of philosophers
17 val forks = Array<Mutex>(n) { Mutex() }
18
19 suspend fun eat(id: Int, desc: String) {
20 val left = forks[id]
21 val right = forks[(id + 1) % n]
22 while (true) {
23 val pair = selectUnbiased<Pair<Mutex, Mutex>> {
24 left.onLock(desc) { left to right }
25 right.onLock(desc) { right to left }
26 }
27 if (pair.second.tryLock(desc)) break
28 pair.first.unlock(desc)
29 pair.second.lock(desc)
30 if (pair.first.tryLock(desc)) break
31 pair.second.unlock(desc)
32 }
33 assertTrue(left.isLocked && right.isLocked)
34 // om, nom, nom --> eating!!!
35 right.unlock(desc)
36 left.unlock(desc)
37 }
38
39 @Test
40 fun testPhilosophers() = runBlocking<Unit> {
Roman Elizarovd3d335b2017-10-21 17:43:53 +030041 println("--- SelectPhilosophersStressTest")
Roman Elizarov174c6962017-02-28 17:36:51 +030042 val timeLimit = System.currentTimeMillis() + TEST_DURATION
43 val philosophers = List<Deferred<Int>>(n) { id ->
44 async(CommonPool) {
45 val desc = "Philosopher $id"
46 var eatsCount = 0
47 while (System.currentTimeMillis() < timeLimit) {
48 eat(id, desc)
49 eatsCount++
50 yield()
51 }
52 println("Philosopher $id done, eats $eatsCount times")
53 eatsCount
54 }
55 }
Roman Elizarov43e3af72017-07-21 16:01:31 +030056 val debugJob = launch(coroutineContext) {
Roman Elizarov174c6962017-02-28 17:36:51 +030057 delay(3 * TEST_DURATION)
58 println("Test is failing. Lock states are:")
59 forks.withIndex().forEach { (id, mutex) -> println("$id: $mutex") }
60 }
61 val eats = withTimeout(5 * TEST_DURATION) { philosophers.map { it.await() } }
62 debugJob.cancel()
63 eats.withIndex().forEach { (id, eats) ->
64 assertTrue("$id shall not starve", eats > 0)
65 }
66 }
67}