@@ -225,7 +225,6 @@ internal fun constructTraceGraph(
225
225
prefixProvider = prefixFactory.actorNodePrefix(iThread),
226
226
iThread = iThread,
227
227
last = lastNode,
228
- callDepth = 0 ,
229
228
actorRepresentation = actorRepresentations[iThread][nextActor],
230
229
resultRepresentation = actorNodeResultRepresentation(
231
230
result = resultProvider[iThread, nextActor],
@@ -246,9 +245,9 @@ internal fun constructTraceGraph(
246
245
prefixProvider = prefixFactory.actorNodePrefix(iCustomThread),
247
246
iThread = iThread,
248
247
last = lastNode,
249
- callDepth = 0 ,
250
248
actorRepresentation = " run()" ,
251
249
resultRepresentation = null ,
250
+ isCustomThreadActor = true ,
252
251
)
253
252
}
254
253
}
@@ -308,7 +307,6 @@ internal fun constructTraceGraph(
308
307
prefixProvider = prefixFactory.actorNodePrefix(iThread),
309
308
iThread = iThread,
310
309
last = lastNode,
311
- callDepth = 0 ,
312
310
actorRepresentation = actorRepresentations[iThread][actorId],
313
311
resultRepresentation = actorNodeResultRepresentation(
314
312
result = actorResult,
@@ -340,39 +338,6 @@ internal fun constructTraceGraph(
340
338
}
341
339
}
342
340
343
- // custom threads are handled separately
344
- for (iCustomThread in customThreadActors.indices) {
345
- val iThread = scenario.nThreads + iCustomThread
346
- var actorNode = customThreadActors[iCustomThread]
347
- if (actorNode == null )
348
- continue
349
- val lastEvent = actorNode.lastInternalEvent
350
- val lastEventNext = lastEvent.next
351
- // TODO: a hacky-way to detect if the thread was aborted due to a detected live-lock;
352
- // in the future we need a better way to pass the results of the custom threads,
353
- // but currently it is not possible and would require large refactoring of the related code
354
- val isHung = (
355
- lastEvent is TraceLeafEvent &&
356
- lastEvent.event is SwitchEventTracePoint &&
357
- lastEvent.event.reason is SwitchReason .ActiveLock
358
- )
359
- val result = if (isHung) null else VoidResult
360
- if (result == = null )
361
- continue
362
- val resultRepresentation = resultRepresentation(result, exceptionStackTraces)
363
- val callDepth = actorNode.callDepth + 1
364
- val resultNode = ActorResultNode (
365
- prefixProvider = prefixFactory.actorResultPrefix(iThread, callDepth),
366
- iThread = iThread,
367
- last = lastEvent,
368
- callDepth = callDepth,
369
- resultRepresentation = resultRepresentation,
370
- exceptionNumberIfExceptionResult = null
371
- )
372
- actorNode.addInternalEvent(resultNode)
373
- resultNode.next = lastEventNext
374
- }
375
-
376
341
// add last section
377
342
if (traceGraphNodes.isNotEmpty()) {
378
343
traceGraphNodesSections + = traceGraphNodes
@@ -444,12 +409,12 @@ private fun compressCallStackTrace(
444
409
val currentElement = oldStacktrace.removeFirst()
445
410
446
411
// if element was removed (or seen) by previous iteration continue
447
- if (removed.contains(currentElement.methodInvocationId )) continue
448
- if (seen.contains(currentElement.methodInvocationId )) {
412
+ if (removed.contains(currentElement.id )) continue
413
+ if (seen.contains(currentElement.id )) {
449
414
compressedStackTrace.add(currentElement)
450
415
continue
451
416
}
452
- seen.add(currentElement.methodInvocationId )
417
+ seen.add(currentElement.id )
453
418
454
419
// if next element is null, we reached end of list
455
420
val nextElement = oldStacktrace.firstOrNull()
@@ -460,6 +425,14 @@ private fun compressCallStackTrace(
460
425
break
461
426
}
462
427
428
+ // Check if current and next are custom thread start
429
+ if (isUserThreadStart(currentElement, nextElement)) {
430
+ // we do not mark currentElement as removed, since that is a unique call from Thread.kt
431
+ // marking it prevents starts of other threads from being detected.
432
+ removed.add(nextElement.id)
433
+ continue
434
+ }
435
+
463
436
// Check if current and next are compressible
464
437
if (isCompressiblePair(currentElement.tracePoint.methodName, nextElement.tracePoint.methodName)) {
465
438
// Combine fields of next and current, and store in current
@@ -472,7 +445,7 @@ private fun compressCallStackTrace(
472
445
check(currentElement.tracePoint.thrownException == nextElement.tracePoint.thrownException)
473
446
474
447
// Mark next as removed
475
- removed.add(nextElement.methodInvocationId )
448
+ removed.add(nextElement.id )
476
449
compressedStackTrace.add(currentElement)
477
450
continue
478
451
}
@@ -497,6 +470,16 @@ private fun actorNodeResultRepresentation(result: Result?, failure: LincheckFail
497
470
}
498
471
}
499
472
473
+ /* *
474
+ * Used by [compressCallStackTrace] to remove the two `invoke()` lines at the beginning of
475
+ * a user-defined thread trace.
476
+ */
477
+ private fun isUserThreadStart (currentElement : CallStackTraceElement , nextElement : CallStackTraceElement ): Boolean =
478
+ currentElement.tracePoint.stackTraceElement.methodName == " run"
479
+ && currentElement.tracePoint.stackTraceElement.fileName == " Thread.kt"
480
+ && currentElement.tracePoint.methodName == " invoke"
481
+ && nextElement.tracePoint.methodName == " invoke"
482
+
500
483
private fun isCompressiblePair (currentName : String , nextName : String ): Boolean =
501
484
isDefaultPair(currentName, nextName) || isAccessPair(currentName, nextName)
502
485
@@ -714,6 +697,7 @@ internal abstract class TraceInnerNode(prefixProvider: PrefixProvider, iThread:
714
697
715
698
private val _internalEvents = mutableListOf<TraceNode >()
716
699
internal val internalEvents: List <TraceNode > get() = _internalEvents
700
+ internal val directChildren: List <TraceNode > get() = internalEvents.filter { it.callDepth == callDepth + 1 }
717
701
718
702
override fun shouldBeExpanded (verboseTrace : Boolean ) =
719
703
_internalEvents .any {
@@ -723,6 +707,7 @@ internal abstract class TraceInnerNode(prefixProvider: PrefixProvider, iThread:
723
707
fun addInternalEvent (node : TraceNode ) {
724
708
_internalEvents .add(node)
725
709
}
710
+
726
711
}
727
712
728
713
internal class CallNode (
@@ -755,22 +740,25 @@ internal class ActorNode(
755
740
prefixProvider : PrefixProvider ,
756
741
iThread : Int ,
757
742
last : TraceNode ? ,
758
- callDepth : Int ,
743
+ callDepth : Int = 0 ,
759
744
internal val actorRepresentation : String ,
760
- private val resultRepresentation : String?
745
+ private val resultRepresentation : String? ,
746
+ private val isCustomThreadActor : Boolean = false
761
747
) : TraceInnerNode(prefixProvider, iThread, last, callDepth) {
762
748
override fun addRepresentationTo (
763
749
traceRepresentation : MutableList <TraceEventRepresentation >,
764
750
verboseTrace : Boolean
765
751
): TraceNode ? {
766
- val actorRepresentation = prefix + actorRepresentation + if (resultRepresentation != null ) " : $resultRepresentation " else " "
752
+ val actorRepresentation =
753
+ prefix + actorRepresentation + if (resultRepresentation != null ) " : $resultRepresentation " else " "
767
754
traceRepresentation.add(TraceEventRepresentation (iThread, actorRepresentation))
768
- return if (! shouldBeExpanded(verboseTrace)) {
755
+
756
+ if (! shouldBeExpanded(verboseTrace)) {
757
+ if (isCustomThreadActor) directChildren.forEach { it.addRepresentationTo(traceRepresentation, true ) }
769
758
lastState?.let { traceRepresentation.add(stateEventRepresentation(iThread, it)) }
770
- lastInternalEvent.next
771
- } else {
772
- next
773
- }
759
+ return lastInternalEvent.next
760
+ }
761
+ return next
774
762
}
775
763
}
776
764
0 commit comments