override fun tryCollectTrace()

in src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt [330:387]


    override fun tryCollectTrace(result: InvocationResult): Pair<Trace?, InvocationResult> {
        val detectedByStrategy = (suddenInvocationResult != null)
        val canCollectTrace = when {
            result is CompletedInvocationResult -> true
            result is ValidationFailureInvocationResult -> true
            // Timeout poisons the runner, making it impossible to
            // re-run invocation and collect the trace.
            result is RunnerTimeoutInvocationResult -> false
            detectedByStrategy -> true
            else -> false
        }
        if (!canCollectTrace) {
            // Interleaving events can be collected almost always,
            // except for the strange cases such as runner's timeout or exceptions in Lincheck.
            return null to result
        }

        collectTrace = true
        loopDetector.enableReplayMode(
            failDueToDeadlockInTheEnd =
                result is ManagedDeadlockInvocationResult ||
                result is ObstructionFreedomViolationInvocationResult
        )
        resetTraceDebuggerTrackerIds()

        val loggedResults = runInvocation()
        // In case the runner detects a deadlock, some threads can still be in an active state,
        // simultaneously adding events to the TraceCollector, which leads to an inconsistent trace.
        // Therefore, if the runner detects deadlock, we don't even try to collect trace.
        if (loggedResults is RunnerTimeoutInvocationResult) return null to result

        val threadNames = MutableList(threadScheduler.nThreads) { "" }
        getRegisteredThreads().forEach { (threadId, thread) ->
            when (val threadNumber = objectTracker.getObjectDisplayNumber(thread)) {
                0    -> threadNames[threadId] = "Main Thread"
                else -> threadNames[threadId] = "Thread $threadNumber"
            }
        }
        val trace = Trace(traceCollector!!.trace, threadNames)

        val sameResultTypes = loggedResults.javaClass == result.javaClass
        val sameResults = (
            loggedResults !is CompletedInvocationResult ||
            result !is CompletedInvocationResult ||
            loggedResults.results == result.results
        )
        check(sameResultTypes && sameResults) {
            StringBuilder().apply {
                appendLine("Non-determinism found. Probably caused by non-deterministic code (WeakHashMap, Object.hashCode, etc).")
                appendLine("== Reporting the first execution without execution trace ==")
                appendLine(result.toLincheckFailure(scenario ?: emptyScenario(), null, analysisProfile))
                appendLine("== Reporting the second execution ==")
                appendLine(loggedResults.toLincheckFailure(scenario ?: emptyScenario(), trace, analysisProfile).toString())
            }.toString()
        }

        return trace to loggedResults
    }