Merged in aslemmer-fix-clockutils-race (pull request #328)

fix clockutils race
This commit is contained in:
Andras Slemmer 2016-09-06 11:48:08 +01:00
commit 220b3f9043
2 changed files with 29 additions and 7 deletions

View File

@ -37,7 +37,7 @@ abstract class MutableClock : Clock() {
private val _version = AtomicLong(0L)
/**
* This tracks how many direct mutations of "now" have occured for this [Clock], but not the passage of time.
* This tracks how many direct mutations of "now" have occurred for this [Clock], but not the passage of time.
*
* It starts at zero, and increments by one per mutation.
*/
@ -79,22 +79,22 @@ abstract class MutableClock : Clock() {
*
* @throws InterruptedException if interrupted by something other than a [MutableClock].
*/
@Suppress("UNUSED_VALUE") // This is here due to the compiler thinking version is not used
@Suspendable
private fun Clock.doInterruptibly(runnable: SuspendableRunnable) {
var version = 0L
var subscription: Subscription? = null
var interruptedByMutation = false
try {
if (this is MutableClock) {
version = this.mutationCount
val strand = Strand.currentStrand()
subscription = this.mutations.subscribe { strand.interrupt() }
subscription = this.mutations.subscribe {
interruptedByMutation = true
strand.interrupt()
}
}
runnable.run()
} catch(e: InterruptedException) {
// If clock has not mutated, then re-throw
val newVersion = if (this is MutableClock) this.mutationCount else version
if (newVersion == version) {
if (!interruptedByMutation) {
throw e
}
} finally {

View File

@ -16,6 +16,7 @@ import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.test.fail
class ClockUtilsTest {
@ -112,6 +113,27 @@ class ClockUtilsTest {
assertFalse(testClock.awaitWithDeadline(advancedClock.instant(), future), "Should have reached deadline")
}
@Test
fun `test external interrupt of a clock future`() {
val mainStrand = Strand.currentStrand()
executor.execute @Suspendable {
// Wait until main thread is waiting
while (mainStrand.state != Strand.State.TIMED_WAITING) {
Strand.sleep(1)
}
mainStrand.interrupt()
}
val testClock = TestClock(stoppedClock)
val advancedClock = Clock.offset(stoppedClock, Duration.ofHours(10))
try {
testClock.awaitWithDeadline(advancedClock.instant(), SettableFuture.create<Boolean>())
fail("Expected InterruptedException")
} catch (exception: InterruptedException) {
}
}
/**
* If this test seems to hang and throw an NPE, then likely that quasar suspendables scanner has not been
* run on core module (in IntelliJ, open gradle side tab and run: