Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Halting problem when using I/O #409

Open
I-Gleb opened this issue Oct 1, 2024 · 1 comment
Open

Halting problem when using I/O #409

I-Gleb opened this issue Oct 1, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@I-Gleb
Copy link

I-Gleb commented Oct 1, 2024

Lincheck version 2.34

After adding debug output to the data structure testing is not finishing.

DS under test:

package day1

import kotlinx.atomicfu.*

interface MyQueue<E> {
    fun enqueue(element: E)
    fun dequeue(): E?
    fun validate() {}
}

class MSQueue<E> : MyQueue<E> {
    private val head: AtomicRef<Node<E>>
    private val tail: AtomicRef<Node<E>>

    init {
        val dummy = Node<E>(null)
        head = atomic(dummy)
        tail = atomic(dummy)
    }

    override fun enqueue(element: E) {
        val newTail = Node(element)
        while (true) {
            val currentTail  = tail.value
            if (currentTail.next.compareAndSet(null, newTail)){
                tail.compareAndSet(currentTail, newTail)
                println("Enqueue $element" + toString())
                return
            } else {
                tail.compareAndSet(currentTail, currentTail.next.value!!)
            }
        }
    }

    override fun dequeue(): E? {
        while (true) {
            val currentHead = head.value
            val currentNext = currentHead.next.value ?: return null

            if (head.compareAndSet(currentHead, currentNext)){
                val result = currentNext.element
                println("Dequeued $result" + toString())
                return result
            }
        }
    }

    private class Node<E>(
        var element: E?
    ) {
        val next = atomic<Node<E>?>(null)
    }

    override fun toString(): String {
        val builder = StringBuilder(" | ")
        var current = head.value
        while (current != tail.value) {
            builder.append(current.element)
            builder.append(" ")
            current = current.next.value!!
        }
        builder.append(" | ${hashCode()}")
        return builder.toString()
    }
}

Test class:

package day1

import org.jetbrains.kotlinx.lincheck.annotations.*
import org.jetbrains.kotlinx.lincheck.paramgen.*
import org.jetbrains.kotlinx.lincheck.*
import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
import org.junit.*
import org.junit.runners.*
import kotlin.reflect.*

@Param(name = "element", gen = IntGen::class, conf = "0:3")
abstract class AbstractQueueTest(
    private val queue: MyQueue<Int>,
    checkObstructionFreedom: Boolean = true,
    threads: Int = 3,
    actorsBefore: Int = 1
) : TestBase(
    sequentialSpecification = IntQueueSequential::class,
    checkObstructionFreedom = checkObstructionFreedom,
    threads = threads,
    actorsBefore = actorsBefore
) {
    @Operation
    fun enqueue(@Param(name = "element") element: Int) = queue.enqueue(element)

    @Operation
    fun dequeue() = queue.dequeue()

    @Validate
    fun validate() = queue.validate()
}

class IntQueueSequential {
    private val q = ArrayList<Int>()

    fun enqueue(element: Int) {
        q.add(element)
    }

    fun dequeue() = q.removeFirstOrNull()
    fun remove(element: Int) = q.remove(element)
}

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
abstract class TestBase(
    val sequentialSpecification: KClass<*>,
    val checkObstructionFreedom: Boolean = true,
    val scenarios: Int = 150,
    val threads: Int = 3,
    val actorsBefore: Int = 1
) {
    @Test
    fun modelCheckingTest() = try {
        ModelCheckingOptions()
            .iterations(scenarios)
            .invocationsPerIteration(10_000)
            .actorsBefore(actorsBefore)
            .threads(threads)
            .actorsPerThread(2)
            .actorsAfter(0)
            .checkObstructionFreedom(checkObstructionFreedom)
            .sequentialSpecification(sequentialSpecification.java)
            .apply { customConfiguration() }
            .check(this::class.java)
    } catch (t: Throwable) {
        throw t
    }

    protected open fun Options<*, *>.customConfiguration() {}
}

class MSQueueTest : AbstractQueueTest(MSQueue())
@ndkoval ndkoval added the bug Something isn't working label Oct 2, 2024
@ndkoval
Copy link
Collaborator

ndkoval commented Oct 2, 2024

Thanks for the issue! I suppose we need to ignore println calls in Lincheck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants