@@ -75,7 +75,7 @@ public final class DebuggerController implements ContextsListener {
75
75
private final Map <Object , SimpleLock > suspendLocks = Collections .synchronizedMap (new HashMap <>());
76
76
private final Map <Object , SuspendedInfo > suspendedInfos = Collections .synchronizedMap (new HashMap <>());
77
77
private final Map <Object , SteppingInfo > commandRequestIds = new HashMap <>();
78
- private final Map <Object , ThreadJob <?>> threadJobs = new HashMap <>();
78
+ private final Map <Object , InvokeJob <?>> invokeJobs = new HashMap <>();
79
79
private final Map <Object , FieldBreakpointEvent > fieldBreakpointExpected = new HashMap <>();
80
80
private final Map <Object , MethodBreakpointEvent > methodBreakpointExpected = new HashMap <>();
81
81
private final Map <Breakpoint , BreakpointInfo > breakpointInfos = new HashMap <>();
@@ -176,6 +176,10 @@ public JDWPContext getContext() {
176
176
return context ;
177
177
}
178
178
179
+ public Ids <Object > getIds () {
180
+ return ids ;
181
+ }
182
+
179
183
public SuspendedInfo getSuspendedInfo (Object thread ) {
180
184
return suspendedInfos .get (thread );
181
185
}
@@ -386,6 +390,7 @@ public Object[] getVisibleGuestThreads() {
386
390
}
387
391
388
392
void forceResumeAll () {
393
+ ids .unpinAll ();
389
394
for (Object thread : getVisibleGuestThreads ()) {
390
395
boolean resumed = false ;
391
396
SimpleLock suspendLock = getSuspendLock (thread );
@@ -398,6 +403,7 @@ void forceResumeAll() {
398
403
}
399
404
400
405
public void resumeAll () {
406
+ ids .unpinAll ();
401
407
for (Object thread : getVisibleGuestThreads ()) {
402
408
SimpleLock suspendLock = getSuspendLock (thread );
403
409
synchronized (suspendLock ) {
@@ -453,6 +459,9 @@ public void immediateSuspend(Object eventThread, byte suspendPolicy, Callable<Vo
453
459
suspend (thread );
454
460
}
455
461
}
462
+ // pin all objects when VM in suspended state
463
+ ids .pinAll ();
464
+
456
465
// immediately suspend the event thread
457
466
suspend (eventThread , SuspendStrategy .EVENT_THREAD , Collections .singletonList (callBack ), true );
458
467
break ;
@@ -469,6 +478,8 @@ public void suspendAll() {
469
478
for (Object thread : getVisibleGuestThreads ()) {
470
479
suspend (thread );
471
480
}
481
+ // pin all objects
482
+ ids .pinAll ();
472
483
}
473
484
474
485
private synchronized SimpleLock getSuspendLock (Object thread ) {
@@ -480,7 +491,7 @@ private synchronized SimpleLock getSuspendLock(Object thread) {
480
491
return lock ;
481
492
}
482
493
483
- private String getThreadName (Object thread ) {
494
+ String getThreadName (Object thread ) {
484
495
return getContext ().getThreadName (thread );
485
496
}
486
497
@@ -631,19 +642,18 @@ public void suspend(Object thread, byte suspendPolicy, List<Callable<Void>> jobs
631
642
case SuspendStrategy .ALL :
632
643
fine (() -> "Suspend ALL" );
633
644
634
- Thread suspendThread = new Thread (new Runnable () {
635
- @ Override
636
- public void run () {
637
- // suspend other threads
638
- for (Object activeThread : getVisibleGuestThreads ()) {
639
- if (activeThread != thread ) {
640
- fine (() -> "Request thread suspend for other thread: " + getThreadName (activeThread ));
641
- DebuggerController .this .suspend (activeThread );
642
- }
645
+ Thread suspendThread = new Thread (() -> {
646
+ // suspend other threads
647
+ for (Object activeThread : getVisibleGuestThreads ()) {
648
+ if (activeThread != thread ) {
649
+ fine (() -> "Request thread suspend for other thread: " + getThreadName (activeThread ));
650
+ DebuggerController .this .suspend (activeThread );
643
651
}
644
652
}
645
653
});
646
654
suspendThread .start ();
655
+ // pin all objects
656
+ ids .pinAll ();
647
657
suspendEventThread (thread , forceSuspend , jobs );
648
658
break ;
649
659
}
@@ -661,83 +671,60 @@ private static void runJobs(List<Callable<Void>> jobs) {
661
671
662
672
private void suspendEventThread (Object thread , boolean forceSuspend , List <Callable <Void >> jobs ) {
663
673
fine (() -> "Suspending event thread: " + getThreadName (thread ) + " with new suspension count: " + threadSuspension .getSuspensionCount (thread ));
664
- lockThread (thread , forceSuspend , true , jobs );
674
+ lockThread (thread , forceSuspend , jobs );
665
675
}
666
676
667
- private void lockThread (Object thread , boolean forceSuspend , boolean isFirstCall , List <Callable <Void >> jobs ) {
677
+ private void lockThread (Object thread , boolean forceSuspend , List <Callable <Void >> jobs ) {
668
678
SimpleLock lock = getSuspendLock (thread );
669
- // in case a thread job is already posted on this thread
670
- checkThreadJobsAndRun (thread , forceSuspend );
671
679
synchronized (lock ) {
672
680
if (!forceSuspend && !threadSuspension .isHardSuspended (thread )) {
673
681
// thread was resumed from other command, so don't suspend now
674
682
return ;
675
683
}
684
+
685
+ if (lock .isLocked ()) {
686
+ threadSuspension .suspendThread (thread );
687
+ runJobs (jobs );
688
+ }
689
+ }
690
+ while (!Thread .currentThread ().isInterrupted ()) {
676
691
try {
677
- if (lock .isLocked () && isFirstCall ) {
678
- threadSuspension .suspendThread (thread );
679
- runJobs (jobs );
680
- }
681
- while (lock .isLocked ()) {
682
- fine (() -> "lock.wait() for thread: " + getThreadName (thread ));
692
+ synchronized (lock ) {
693
+ if (!lock .isLocked ()) {
694
+ // released from other thread, so break loop
695
+ break ;
696
+ }
683
697
// no reason to hold a hard suspension status, since now
684
698
// we have the actual suspension status and suspended information
685
699
threadSuspension .removeHardSuspendedThread (thread );
686
- lock .wait ();
700
+ fine (() -> "lock.wait() for thread: " + getThreadName (thread ));
701
+ // Having the thread lock, we can check if an invoke job was posted outside of
702
+ // locking, and if so, we postpone blocking the thread until next time around.
703
+ if (!invokeJobs .containsKey (thread )) {
704
+ lock .wait ();
705
+ }
687
706
}
688
707
} catch (InterruptedException e ) {
689
708
// the thread was interrupted, so let it run dry
690
709
// make sure the interrupted flag is set though
691
710
Thread .currentThread ().interrupt ();
692
711
}
712
+ checkInvokeJobsAndRun (thread );
693
713
}
694
-
695
- checkThreadJobsAndRun (thread , forceSuspend );
696
- getGCPrevention ().releaseActiveWhileSuspended (thread );
697
714
fine (() -> "lock wakeup for thread: " + getThreadName (thread ));
698
715
}
699
716
700
- private void checkThreadJobsAndRun (Object thread , boolean forceSuspend ) {
701
- if (threadJobs .containsKey (thread )) {
702
- // re-acquire the thread lock after completing
703
- // the job, to avoid the thread resuming.
704
- SimpleLock suspendLock = getSuspendLock (thread );
705
- synchronized (suspendLock ) {
706
- suspendLock .acquire ();
707
- }
708
- // a thread job was posted on this thread
709
- // only wake up to perform the job a go back to sleep
710
- ThreadJob <?> job = threadJobs .remove (thread );
711
- byte suspensionStrategy = job .getSuspensionStrategy ();
712
-
713
- if (suspensionStrategy == SuspendStrategy .ALL ) {
714
- Object [] allThreads = getVisibleGuestThreads ();
715
- // resume all threads during invocation of method to avoid potential deadlocks
716
- for (Object activeThread : allThreads ) {
717
- if (activeThread != thread ) {
718
- resume (activeThread );
719
- }
720
- }
721
- // perform the job on this thread
722
- job .runJob ();
723
- // suspend all other threads after the invocation
724
- for (Object activeThread : allThreads ) {
725
- if (activeThread != thread ) {
726
- suspend (activeThread );
727
- }
728
- }
729
- } else {
730
- job .runJob ();
731
- }
732
- lockThread (thread , forceSuspend , false , Collections .emptyList ());
717
+ private void checkInvokeJobsAndRun (Object thread ) {
718
+ if (invokeJobs .containsKey (thread )) {
719
+ InvokeJob <?> job = invokeJobs .remove (thread );
720
+ job .runJob (this );
733
721
}
734
722
}
735
723
736
- public void postJobForThread ( ThreadJob <?> job ) {
724
+ public void postInvokeJobForThread ( InvokeJob <?> job ) {
737
725
SimpleLock lock = getSuspendLock (job .getThread ());
738
726
synchronized (lock ) {
739
- threadJobs .put (job .getThread (), job );
740
- lock .release ();
727
+ invokeJobs .put (job .getThread (), job );
741
728
lock .notifyAll ();
742
729
}
743
730
}
0 commit comments