Skip to content

java.lang.ClassCircularityError exception thrown by Lincheck #755

@eupp

Description

@eupp

To reproduce, run AtomicArrayWithCAS2SingleWriterTest in test/day3/AtomicArrayTests.kt:
https://github.com/ndkoval/concurrent-programming-intensive

with the following implementation of AtomicArrayWithCAS2SingleWriter:

@file:Suppress("DuplicatedCode", "UNCHECKED_CAST")

package day3

import day3.AtomicArrayWithCAS2SingleWriter.Status.*
import java.util.concurrent.atomic.*

// This implementation never stores `null` values.
class AtomicArrayWithCAS2SingleWriter<E : Any>(size: Int, initialValue: E) {
    private val array = AtomicReferenceArray<Any?>(size)

    init {
        // Fill array with the initial value.
        for (i in 0 until size) {
            array[i] = initialValue
        }
    }

    fun get(index: Int): E {
        val curValue = array.get(index)
        if (curValue is AtomicArrayWithCAS2SingleWriter<*>.CAS2Descriptor) {
            val curStatus = curValue.status.get()
            if (curStatus == SUCCESS)
                return (if (curValue.index1 == index) curValue.update1 else curValue.update2) as E
            else
                return (if (curValue.index1 == index) curValue.expected1 else curValue.expected2) as E
        }
        return curValue as E
    }

    fun cas2(
        index1: Int, expected1: E, update1: E,
        index2: Int, expected2: E, update2: E
    ): Boolean {
        require(index1 != index2) { "The indices should be different" }
        val descriptor = CAS2Descriptor(
            index1 = index1, expected1 = expected1, update1 = update1,
            index2 = index2, expected2 = expected2, update2 = update2
        )
        descriptor.apply()
        return descriptor.status.get() === SUCCESS
    }

    inner class CAS2Descriptor(
        val index1: Int, val expected1: E, val update1: E,
        val index2: Int, val expected2: E, val update2: E
    ) {
        val status = AtomicReference(UNDECIDED)

        fun installDescriptor(): Boolean {
//            while(true) {
//                val curValue = array[index1]
//                if (curValue is AtomicArrayWithCAS2SingleWriter<*>.CAS2Descriptor) {
//                    curValue.apply()
//                    continue
//                }

                val desc1 = array.compareAndSet(index1, expected1, this)
                val desc2 = array.compareAndSet(index2, expected2, this)
                if (desc2 && desc1) {
                    return true
                } else {
                    if (desc2)
                        array.compareAndSet(index2, this, expected2)
                    if (desc1)
                        array.compareAndSet(index1, this, expected1)
                    return false;
                }
//            }
        }

        fun apply() {
            if (installDescriptor()) {
                status.compareAndSet(UNDECIDED, SUCCESS)
                array.compareAndSet(index1, this, update1)
                array.compareAndSet(index2, this, update2)
            }

            // TODO: Install the descriptor, update the status, and update the cells;
            // TODO: create functions for each of these three phases.
            // TODO: In this task, only one thread can call cas2(..),
            // TODO: so cas2(..) calls cannot be executed concurrently.
        }
    }

    enum class Status {
        UNDECIDED, SUCCESS, FAILED
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions