fun visitCodeLocation()

in src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/LoopDetector.kt [250:323]


    fun visitCodeLocation(iThread: Int, codeLocation: Int): Decision {
        check(currentThreadId == iThread) {
            "The current thread id $currentThreadId is not equal to the one provided $iThread."
        }
        // Increase the total number of happened operations for live-lock detection
        totalExecutionsCount++
        // Ignore unknown code locations.
        if (codeLocation == UNKNOWN_CODE_LOCATION_ID) {
            return Decision.Idle
        }
        // Update code location visit counter
        updateCodeLocationVisitCounter(codeLocation)
        val count = currentThreadCodeLocationVisitCountMap.getOrDefault(codeLocation, 0)
        // If we are in replay mode, check if the replay has lead to a deadlock
        replayModeLoopDetectorHelper?.let {
            return it.detectLivelock()
        }
        // In trace debugger mode, check whether the count exceeds
        // the maximum number of repetitions for spin-loop detection.
        // Check whether the count exceeds the maximum number of repetitions for loop/hang detection.
        if (isInTraceDebuggerMode) {
            return when {
                // spin-loop detected - switch
                count > currentHangingDetectionThreshold ->
                    Decision.LivelockThreadSwitch(currentHangingDetectionThreshold)
                // live-lock detected - fail
                totalExecutionsCount > ManagedCTestConfiguration.DEFAULT_LIVELOCK_EVENTS_THRESHOLD ->
                    Decision.EventsThresholdReached
                // else - continue
                else -> Decision.Idle
            }
        }
        val detectedFirstTime = count > currentHangingDetectionThreshold
        val detectedEarly = loopTrackingCursor.isInCycle
        // detectedFirstTime and detectedEarly can both sometimes be true
        // when we can't find a cycle period and can't switch to another thread.
        if (detectedFirstTime && !detectedEarly) {
            if (mode == Mode.DEFAULT) {
                // Turn on parameters and read/write values and receivers tracking and request one more replay.
                mode = Mode.CYCLE_PERIOD_CALCULATION
                return Decision.LivelockReplayToDetectCycleRequired
            }
            registerCycle()
            // Turn off parameters tracking and request one more replay to avoid side effects.
            mode = Mode.DEFAULT
            // Enormous operations count considered as total spin lock
            if (totalExecutionsCount > ManagedCTestConfiguration.DEFAULT_LIVELOCK_EVENTS_THRESHOLD) {
                return Decision.EventsThresholdReached
            }
            // Replay current interleaving to avoid side effects caused by multiple cycle executions
            return Decision.LivelockReplayRequired
        }
        if (!detectedFirstTime && detectedEarly) {
            totalExecutionsCount += currentHangingDetectionThreshold
            val lastNode = currentInterleavingHistory.last()
            // spinCyclePeriod may be not 0 only we tried to switch
            // from the current thread but no available threads were available to switch
            if (lastNode.spinCyclePeriod == 0) {
                // transform current node to the state corresponding to early found cycle
                val cyclePeriod = loopTrackingCursor.cyclePeriod
                lastNode.executions -= cyclePeriod
                lastNode.spinCyclePeriod = cyclePeriod
                lastNode.executionHash = loopTrackingCursor.cycleLocationsHash
            }
            // Enormous operations count considered as total spin lock
            if (totalExecutionsCount > ManagedCTestConfiguration.DEFAULT_LIVELOCK_EVENTS_THRESHOLD) {
                return Decision.EventsThresholdReached
            }
        }
        if (detectedFirstTime || detectedEarly) {
            return Decision.LivelockThreadSwitch(replayModeCurrentCyclePeriod)
        }
        return Decision.Idle
    }