author | erikj |
Tue, 12 Sep 2017 19:03:39 +0200 | |
changeset 47216 | 71c04702a3d5 |
parent 45714 | jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java@1820d351198d |
permissions | -rw-r--r-- |
2 | 1 |
/* |
45714 | 2 |
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
package com.sun.tools.jdi; |
|
27 |
||
45714 | 28 |
import java.lang.ref.WeakReference; |
29 |
import java.util.ArrayList; |
|
30 |
import java.util.Arrays; |
|
31 |
import java.util.Collections; |
|
32 |
import java.util.Iterator; |
|
33 |
import java.util.List; |
|
34 |
||
35 |
import com.sun.jdi.ClassNotLoadedException; |
|
36 |
import com.sun.jdi.IncompatibleThreadStateException; |
|
37 |
import com.sun.jdi.InternalException; |
|
38 |
import com.sun.jdi.InvalidStackFrameException; |
|
39 |
import com.sun.jdi.InvalidTypeException; |
|
40 |
import com.sun.jdi.Location; |
|
41 |
import com.sun.jdi.MonitorInfo; |
|
42 |
import com.sun.jdi.NativeMethodException; |
|
43 |
import com.sun.jdi.ObjectReference; |
|
44 |
import com.sun.jdi.ReferenceType; |
|
45 |
import com.sun.jdi.StackFrame; |
|
46 |
import com.sun.jdi.ThreadGroupReference; |
|
47 |
import com.sun.jdi.ThreadReference; |
|
48 |
import com.sun.jdi.Value; |
|
49 |
import com.sun.jdi.VirtualMachine; |
|
2 | 50 |
import com.sun.jdi.request.BreakpointRequest; |
51 |
||
52 |
public class ThreadReferenceImpl extends ObjectReferenceImpl |
|
45714 | 53 |
implements ThreadReference { |
2 | 54 |
static final int SUSPEND_STATUS_SUSPENDED = 0x1; |
55 |
static final int SUSPEND_STATUS_BREAK = 0x2; |
|
56 |
||
57 |
private int suspendedZombieCount = 0; |
|
58 |
||
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
59 |
/* |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
60 |
* Some objects can only be created while a thread is suspended and are valid |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
61 |
* only while the thread remains suspended. Examples are StackFrameImpl |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
62 |
* and MonitorInfoImpl. When the thread resumes, these objects have to be |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
63 |
* marked as invalid so that their methods can throw |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
64 |
* InvalidStackFrameException if they are called. To do this, such objects |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
65 |
* register themselves as listeners of the associated thread. When the |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
66 |
* thread is resumed, its listeners are notified and mark themselves |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
67 |
* invalid. |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
68 |
* Also, note that ThreadReferenceImpl itself caches some info that |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
69 |
* is valid only as long as the thread is suspended. When the thread |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
70 |
* is resumed, that cache must be purged. |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
71 |
* Lastly, note that ThreadReferenceImpl and its super, ObjectReferenceImpl |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
72 |
* cache some info that is only valid as long as the entire VM is suspended. |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
73 |
* If _any_ thread is resumed, this cache must be purged. To handle this, |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
74 |
* both ThreadReferenceImpl and ObjectReferenceImpl register themselves as |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
75 |
* VMListeners so that they get notified when all threads are suspended and |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
76 |
* when any thread is resumed. |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
77 |
*/ |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
78 |
|
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
79 |
// This is cached for the life of the thread |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
80 |
private ThreadGroupReference threadGroup; |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
81 |
|
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
82 |
// This is cached only while this one thread is suspended. Each time |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
83 |
// the thread is resumed, we abandon the current cache object and |
21278 | 84 |
// create a new initialized one. |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
85 |
private static class LocalCache { |
2 | 86 |
JDWP.ThreadReference.Status status = null; |
87 |
List<StackFrame> frames = null; |
|
88 |
int framesStart = -1; |
|
89 |
int framesLength = 0; |
|
90 |
int frameCount = -1; |
|
91 |
List<ObjectReference> ownedMonitors = null; |
|
92 |
List<MonitorInfo> ownedMonitorsInfo = null; |
|
93 |
ObjectReference contendedMonitor = null; |
|
94 |
boolean triedCurrentContended = false; |
|
95 |
} |
|
96 |
||
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
97 |
/* |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
98 |
* The localCache instance var is set by resetLocalCache to an initialized |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
99 |
* object as shown above. This occurs when the ThreadReference |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
100 |
* object is created, and when the mirrored thread is resumed. |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
101 |
* The fields are then filled in by the relevant methods as they |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
102 |
* are called. A problem can occur if resetLocalCache is called |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
103 |
* (ie, a resume() is executed) at certain points in the execution |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
104 |
* of some of these methods - see 6751643. To avoid this, each |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
105 |
* method that wants to use this cache must make a local copy of |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
106 |
* this variable and use that. This means that each invocation of |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
107 |
* these methods will use a copy of the cache object that was in |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
108 |
* effect at the point that the copy was made; if a racy resume |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
109 |
* occurs, it won't affect the method's local copy. This means that |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
110 |
* the values returned by these calls may not match the state of |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
111 |
* the debuggee at the time the caller gets the values. EG, |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
112 |
* frameCount() is called and comes up with 5 frames. But before |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
113 |
* it returns this, a resume of the debuggee thread is executed in a |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
114 |
* different debugger thread. The thread is resumed and running at |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
115 |
* the time that the value 5 is returned. Or even worse, the thread |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
116 |
* could be suspended again and have a different number of frames, eg, 24, |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
117 |
* but this call will still return 5. |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
118 |
*/ |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
119 |
private LocalCache localCache; |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
120 |
|
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
121 |
private void resetLocalCache() { |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
122 |
localCache = new LocalCache(); |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
123 |
} |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
124 |
|
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
125 |
// This is cached only while all threads in the VM are suspended |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
126 |
// Yes, someone could change the name of a thread while it is suspended. |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
127 |
private static class Cache extends ObjectReferenceImpl.Cache { |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
128 |
String name = null; |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
129 |
} |
2 | 130 |
protected ObjectReferenceImpl.Cache newCache() { |
131 |
return new Cache(); |
|
132 |
} |
|
133 |
||
134 |
// Listeners - synchronized on vm.state() |
|
45714 | 135 |
private List<WeakReference<ThreadListener>> listeners = new ArrayList<>(); |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
136 |
|
2 | 137 |
ThreadReferenceImpl(VirtualMachine aVm, long aRef) { |
45714 | 138 |
super(aVm, aRef); |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
139 |
resetLocalCache(); |
2 | 140 |
vm.state().addListener(this); |
141 |
} |
|
142 |
||
143 |
protected String description() { |
|
144 |
return "ThreadReference " + uniqueID(); |
|
145 |
} |
|
146 |
||
147 |
/* |
|
148 |
* VMListener implementation |
|
149 |
*/ |
|
150 |
public boolean vmNotSuspended(VMAction action) { |
|
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
151 |
if (action.resumingThread() == null) { |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
152 |
// all threads are being resumed |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
153 |
synchronized (vm.state()) { |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
154 |
processThreadAction(new ThreadAction(this, |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
155 |
ThreadAction.THREAD_RESUMABLE)); |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
156 |
} |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
157 |
|
2 | 158 |
} |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
159 |
|
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
160 |
/* |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
161 |
* Othewise, only one thread is being resumed: |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
162 |
* if it is us, |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
163 |
* we have already done our processThreadAction to notify our |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
164 |
* listeners when we processed the resume. |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
165 |
* if it is not us, |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
166 |
* we don't want to notify our listeners |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
167 |
* because we are not being resumed. |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
168 |
*/ |
2 | 169 |
return super.vmNotSuspended(action); |
170 |
} |
|
171 |
||
172 |
/** |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
173 |
* Note that we only cache the name string while the entire VM is suspended |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
174 |
* because the name can change via Thread.setName arbitrarily while this |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
175 |
* thread is running. |
2 | 176 |
*/ |
177 |
public String name() { |
|
178 |
String name = null; |
|
179 |
try { |
|
180 |
Cache local = (Cache)getCache(); |
|
181 |
||
182 |
if (local != null) { |
|
183 |
name = local.name; |
|
184 |
} |
|
185 |
if (name == null) { |
|
45714 | 186 |
name = JDWP.ThreadReference.Name.process(vm, this).threadName; |
2 | 187 |
if (local != null) { |
188 |
local.name = name; |
|
189 |
} |
|
190 |
} |
|
191 |
} catch (JDWPException exc) { |
|
192 |
throw exc.toJDIException(); |
|
193 |
} |
|
194 |
return name; |
|
195 |
} |
|
196 |
||
197 |
/* |
|
198 |
* Sends a command to the back end which is defined to do an |
|
199 |
* implicit vm-wide resume. |
|
200 |
*/ |
|
201 |
PacketStream sendResumingCommand(CommandSender sender) { |
|
202 |
synchronized (vm.state()) { |
|
203 |
processThreadAction(new ThreadAction(this, |
|
204 |
ThreadAction.THREAD_RESUMABLE)); |
|
205 |
return sender.send(); |
|
206 |
} |
|
207 |
} |
|
208 |
||
209 |
public void suspend() { |
|
210 |
try { |
|
211 |
JDWP.ThreadReference.Suspend.process(vm, this); |
|
212 |
} catch (JDWPException exc) { |
|
213 |
throw exc.toJDIException(); |
|
214 |
} |
|
215 |
// Don't consider the thread suspended yet. On reply, notifySuspend() |
|
216 |
// will be called. |
|
217 |
} |
|
218 |
||
219 |
public void resume() { |
|
220 |
/* |
|
221 |
* If it's a zombie, we can just update internal state without |
|
222 |
* going to back end. |
|
223 |
*/ |
|
224 |
if (suspendedZombieCount > 0) { |
|
225 |
suspendedZombieCount--; |
|
226 |
return; |
|
227 |
} |
|
228 |
||
229 |
PacketStream stream; |
|
230 |
synchronized (vm.state()) { |
|
231 |
processThreadAction(new ThreadAction(this, |
|
232 |
ThreadAction.THREAD_RESUMABLE)); |
|
233 |
stream = JDWP.ThreadReference.Resume.enqueueCommand(vm, this); |
|
234 |
} |
|
235 |
try { |
|
236 |
JDWP.ThreadReference.Resume.waitForReply(vm, stream); |
|
237 |
} catch (JDWPException exc) { |
|
238 |
throw exc.toJDIException(); |
|
239 |
} |
|
240 |
} |
|
241 |
||
242 |
public int suspendCount() { |
|
243 |
/* |
|
244 |
* If it's a zombie, we maintain the count in the front end. |
|
245 |
*/ |
|
246 |
if (suspendedZombieCount > 0) { |
|
247 |
return suspendedZombieCount; |
|
248 |
} |
|
249 |
||
250 |
try { |
|
251 |
return JDWP.ThreadReference.SuspendCount.process(vm, this).suspendCount; |
|
252 |
} catch (JDWPException exc) { |
|
253 |
throw exc.toJDIException(); |
|
254 |
} |
|
255 |
} |
|
256 |
||
257 |
public void stop(ObjectReference throwable) throws InvalidTypeException { |
|
28097
fa1a96810647
6618335: ThreadReference.stop(null) throws NPE instead of InvalidTypeException
egahlin
parents:
25859
diff
changeset
|
258 |
validateMirrorOrNull(throwable); |
2 | 259 |
// Verify that the given object is a Throwable instance |
11277 | 260 |
List<ReferenceType> list = vm.classesByName("java.lang.Throwable"); |
2 | 261 |
ClassTypeImpl throwableClass = (ClassTypeImpl)list.get(0); |
262 |
if ((throwable == null) || |
|
263 |
!throwableClass.isAssignableFrom(throwable)) { |
|
264 |
throw new InvalidTypeException("Not an instance of Throwable"); |
|
265 |
} |
|
266 |
||
267 |
try { |
|
268 |
JDWP.ThreadReference.Stop.process(vm, this, |
|
269 |
(ObjectReferenceImpl)throwable); |
|
270 |
} catch (JDWPException exc) { |
|
271 |
throw exc.toJDIException(); |
|
272 |
} |
|
273 |
} |
|
274 |
||
275 |
public void interrupt() { |
|
276 |
try { |
|
277 |
JDWP.ThreadReference.Interrupt.process(vm, this); |
|
278 |
} catch (JDWPException exc) { |
|
279 |
throw exc.toJDIException(); |
|
280 |
} |
|
281 |
} |
|
282 |
||
283 |
private JDWP.ThreadReference.Status jdwpStatus() { |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
284 |
LocalCache snapshot = localCache; |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
285 |
JDWP.ThreadReference.Status myStatus = snapshot.status; |
2 | 286 |
try { |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
287 |
if (myStatus == null) { |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
288 |
myStatus = JDWP.ThreadReference.Status.process(vm, this); |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
289 |
if ((myStatus.suspendStatus & SUSPEND_STATUS_SUSPENDED) != 0) { |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
290 |
// thread is suspended, we can cache the status. |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
291 |
snapshot.status = myStatus; |
2 | 292 |
} |
293 |
} |
|
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
294 |
} catch (JDWPException exc) { |
2 | 295 |
throw exc.toJDIException(); |
296 |
} |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
297 |
return myStatus; |
2 | 298 |
} |
299 |
||
300 |
public int status() { |
|
301 |
return jdwpStatus().threadStatus; |
|
302 |
} |
|
303 |
||
304 |
public boolean isSuspended() { |
|
305 |
return ((suspendedZombieCount > 0) || |
|
306 |
((jdwpStatus().suspendStatus & SUSPEND_STATUS_SUSPENDED) != 0)); |
|
307 |
} |
|
308 |
||
309 |
public boolean isAtBreakpoint() { |
|
310 |
/* |
|
311 |
* TO DO: This fails to take filters into account. |
|
312 |
*/ |
|
313 |
try { |
|
314 |
StackFrame frame = frame(0); |
|
315 |
Location location = frame.location(); |
|
11277 | 316 |
List<BreakpointRequest> requests = vm.eventRequestManager().breakpointRequests(); |
317 |
Iterator<BreakpointRequest> iter = requests.iterator(); |
|
2 | 318 |
while (iter.hasNext()) { |
11277 | 319 |
BreakpointRequest request = iter.next(); |
2 | 320 |
if (location.equals(request.location())) { |
321 |
return true; |
|
322 |
} |
|
323 |
} |
|
324 |
return false; |
|
325 |
} catch (IndexOutOfBoundsException iobe) { |
|
326 |
return false; // no frames on stack => not at breakpoint |
|
327 |
} catch (IncompatibleThreadStateException itse) { |
|
328 |
// Per the javadoc, not suspended => return false |
|
329 |
return false; |
|
330 |
} |
|
331 |
} |
|
332 |
||
333 |
public ThreadGroupReference threadGroup() { |
|
334 |
/* |
|
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
335 |
* Thread group can't change, so it's cached once and for all. |
2 | 336 |
*/ |
337 |
if (threadGroup == null) { |
|
338 |
try { |
|
339 |
threadGroup = JDWP.ThreadReference.ThreadGroup. |
|
340 |
process(vm, this).group; |
|
341 |
} catch (JDWPException exc) { |
|
342 |
throw exc.toJDIException(); |
|
343 |
} |
|
344 |
} |
|
345 |
return threadGroup; |
|
346 |
} |
|
347 |
||
348 |
public int frameCount() throws IncompatibleThreadStateException { |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
349 |
LocalCache snapshot = localCache; |
2 | 350 |
try { |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
351 |
if (snapshot.frameCount == -1) { |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
352 |
snapshot.frameCount = JDWP.ThreadReference.FrameCount |
2 | 353 |
.process(vm, this).frameCount; |
354 |
} |
|
355 |
} catch (JDWPException exc) { |
|
356 |
switch (exc.errorCode()) { |
|
357 |
case JDWP.Error.THREAD_NOT_SUSPENDED: |
|
358 |
case JDWP.Error.INVALID_THREAD: /* zombie */ |
|
359 |
throw new IncompatibleThreadStateException(); |
|
360 |
default: |
|
361 |
throw exc.toJDIException(); |
|
362 |
} |
|
363 |
} |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
364 |
return snapshot.frameCount; |
2 | 365 |
} |
366 |
||
367 |
public List<StackFrame> frames() throws IncompatibleThreadStateException { |
|
368 |
return privateFrames(0, -1); |
|
369 |
} |
|
370 |
||
371 |
public StackFrame frame(int index) throws IncompatibleThreadStateException { |
|
11277 | 372 |
List<StackFrame> list = privateFrames(index, 1); |
373 |
return list.get(0); |
|
2 | 374 |
} |
375 |
||
376 |
/** |
|
377 |
* Is the requested subrange within what has been retrieved? |
|
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
378 |
* local is known to be non-null. Should only be called from |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
379 |
* a sync method. |
2 | 380 |
*/ |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
381 |
private boolean isSubrange(LocalCache snapshot, |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
382 |
int start, int length) { |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
383 |
if (start < snapshot.framesStart) { |
2 | 384 |
return false; |
385 |
} |
|
386 |
if (length == -1) { |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
387 |
return (snapshot.framesLength == -1); |
2 | 388 |
} |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
389 |
if (snapshot.framesLength == -1) { |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
390 |
if ((start + length) > (snapshot.framesStart + |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
391 |
snapshot.frames.size())) { |
2 | 392 |
throw new IndexOutOfBoundsException(); |
393 |
} |
|
394 |
return true; |
|
395 |
} |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
396 |
return ((start + length) <= (snapshot.framesStart + snapshot.framesLength)); |
2 | 397 |
} |
398 |
||
399 |
public List<StackFrame> frames(int start, int length) |
|
400 |
throws IncompatibleThreadStateException { |
|
401 |
if (length < 0) { |
|
402 |
throw new IndexOutOfBoundsException( |
|
403 |
"length must be greater than or equal to zero"); |
|
404 |
} |
|
405 |
return privateFrames(start, length); |
|
406 |
} |
|
407 |
||
408 |
/** |
|
409 |
* Private version of frames() allows "-1" to specify all |
|
410 |
* remaining frames. |
|
411 |
*/ |
|
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
412 |
synchronized private List<StackFrame> privateFrames(int start, int length) |
2 | 413 |
throws IncompatibleThreadStateException { |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
414 |
|
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
415 |
// Lock must be held while creating stack frames so if that two threads |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
416 |
// do this at the same time, one won't clobber the subset created by the other. |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
417 |
LocalCache snapshot = localCache; |
2 | 418 |
try { |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
419 |
if (snapshot.frames == null || !isSubrange(snapshot, start, length)) { |
2 | 420 |
JDWP.ThreadReference.Frames.Frame[] jdwpFrames |
421 |
= JDWP.ThreadReference.Frames. |
|
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
422 |
process(vm, this, start, length).frames; |
2 | 423 |
int count = jdwpFrames.length; |
45714 | 424 |
snapshot.frames = new ArrayList<>(count); |
2 | 425 |
|
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
426 |
for (int i = 0; i<count; i++) { |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
427 |
if (jdwpFrames[i].location == null) { |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
428 |
throw new InternalException("Invalid frame location"); |
2 | 429 |
} |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
430 |
StackFrame frame = new StackFrameImpl(vm, this, |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
431 |
jdwpFrames[i].frameID, |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
432 |
jdwpFrames[i].location); |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
433 |
// Add to the frame list |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
434 |
snapshot.frames.add(frame); |
2 | 435 |
} |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
436 |
snapshot.framesStart = start; |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
437 |
snapshot.framesLength = length; |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
438 |
return Collections.unmodifiableList(snapshot.frames); |
2 | 439 |
} else { |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
440 |
int fromIndex = start - snapshot.framesStart; |
2 | 441 |
int toIndex; |
442 |
if (length == -1) { |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
443 |
toIndex = snapshot.frames.size() - fromIndex; |
2 | 444 |
} else { |
445 |
toIndex = fromIndex + length; |
|
446 |
} |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
447 |
return Collections.unmodifiableList(snapshot.frames.subList(fromIndex, toIndex)); |
2 | 448 |
} |
449 |
} catch (JDWPException exc) { |
|
450 |
switch (exc.errorCode()) { |
|
451 |
case JDWP.Error.THREAD_NOT_SUSPENDED: |
|
452 |
case JDWP.Error.INVALID_THREAD: /* zombie */ |
|
453 |
throw new IncompatibleThreadStateException(); |
|
454 |
default: |
|
455 |
throw exc.toJDIException(); |
|
456 |
} |
|
457 |
} |
|
458 |
} |
|
459 |
||
460 |
public List<ObjectReference> ownedMonitors() throws IncompatibleThreadStateException { |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
461 |
LocalCache snapshot = localCache; |
2 | 462 |
try { |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
463 |
if (snapshot.ownedMonitors == null) { |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
464 |
snapshot.ownedMonitors = Arrays.asList( |
2 | 465 |
(ObjectReference[])JDWP.ThreadReference.OwnedMonitors. |
466 |
process(vm, this).owned); |
|
11277 | 467 |
if ((vm.traceFlags & VirtualMachine.TRACE_OBJREFS) != 0) { |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
468 |
vm.printTrace(description() + |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
469 |
" temporarily caching owned monitors"+ |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
470 |
" (count = " + snapshot.ownedMonitors.size() + ")"); |
2 | 471 |
} |
472 |
} |
|
473 |
} catch (JDWPException exc) { |
|
474 |
switch (exc.errorCode()) { |
|
475 |
case JDWP.Error.THREAD_NOT_SUSPENDED: |
|
476 |
case JDWP.Error.INVALID_THREAD: /* zombie */ |
|
477 |
throw new IncompatibleThreadStateException(); |
|
478 |
default: |
|
479 |
throw exc.toJDIException(); |
|
480 |
} |
|
481 |
} |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
482 |
return snapshot.ownedMonitors; |
2 | 483 |
} |
484 |
||
485 |
public ObjectReference currentContendedMonitor() |
|
486 |
throws IncompatibleThreadStateException { |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
487 |
LocalCache snapshot = localCache; |
2 | 488 |
try { |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
489 |
if (snapshot.contendedMonitor == null && |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
490 |
!snapshot.triedCurrentContended) { |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
491 |
snapshot.contendedMonitor = JDWP.ThreadReference.CurrentContendedMonitor. |
2 | 492 |
process(vm, this).monitor; |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
493 |
snapshot.triedCurrentContended = true; |
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
494 |
if ((snapshot.contendedMonitor != null) && |
11277 | 495 |
((vm.traceFlags & VirtualMachine.TRACE_OBJREFS) != 0)) { |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
496 |
vm.printTrace(description() + |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
497 |
" temporarily caching contended monitor"+ |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
498 |
" (id = " + snapshot.contendedMonitor.uniqueID() + ")"); |
2 | 499 |
} |
500 |
} |
|
501 |
} catch (JDWPException exc) { |
|
502 |
switch (exc.errorCode()) { |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
503 |
case JDWP.Error.THREAD_NOT_SUSPENDED: |
2 | 504 |
case JDWP.Error.INVALID_THREAD: /* zombie */ |
505 |
throw new IncompatibleThreadStateException(); |
|
506 |
default: |
|
507 |
throw exc.toJDIException(); |
|
508 |
} |
|
509 |
} |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
510 |
return snapshot.contendedMonitor; |
2 | 511 |
} |
512 |
||
513 |
public List<MonitorInfo> ownedMonitorsAndFrames() throws IncompatibleThreadStateException { |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
514 |
LocalCache snapshot = localCache; |
2 | 515 |
try { |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
516 |
if (snapshot.ownedMonitorsInfo == null) { |
2 | 517 |
JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.monitor[] minfo; |
518 |
minfo = JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.process(vm, this).owned; |
|
519 |
||
45714 | 520 |
snapshot.ownedMonitorsInfo = new ArrayList<>(minfo.length); |
2 | 521 |
|
522 |
for (int i=0; i < minfo.length; i++) { |
|
523 |
MonitorInfo mon = new MonitorInfoImpl(vm, minfo[i].monitor, this, minfo[i].stack_depth); |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
524 |
snapshot.ownedMonitorsInfo.add(mon); |
2 | 525 |
} |
526 |
||
11277 | 527 |
if ((vm.traceFlags & VirtualMachine.TRACE_OBJREFS) != 0) { |
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
528 |
vm.printTrace(description() + |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
529 |
" temporarily caching owned monitors"+ |
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
530 |
" (count = " + snapshot.ownedMonitorsInfo.size() + ")"); |
2 | 531 |
} |
532 |
} |
|
533 |
||
534 |
} catch (JDWPException exc) { |
|
535 |
switch (exc.errorCode()) { |
|
536 |
case JDWP.Error.THREAD_NOT_SUSPENDED: |
|
537 |
case JDWP.Error.INVALID_THREAD: /* zombie */ |
|
538 |
throw new IncompatibleThreadStateException(); |
|
539 |
default: |
|
540 |
throw exc.toJDIException(); |
|
541 |
} |
|
542 |
} |
|
1326
0c330a451ed9
6751643: ThreadReference.ownedMonitors() can return null
jjh
parents:
836
diff
changeset
|
543 |
return snapshot.ownedMonitorsInfo; |
2 | 544 |
} |
545 |
||
546 |
public void popFrames(StackFrame frame) throws IncompatibleThreadStateException { |
|
547 |
// Note that interface-wise this functionality belongs |
|
548 |
// here in ThreadReference, but implementation-wise it |
|
549 |
// belongs in StackFrame, so we just forward it. |
|
550 |
if (!frame.thread().equals(this)) { |
|
551 |
throw new IllegalArgumentException("frame does not belong to this thread"); |
|
552 |
} |
|
553 |
if (!vm.canPopFrames()) { |
|
554 |
throw new UnsupportedOperationException( |
|
555 |
"target does not support popping frames"); |
|
556 |
} |
|
557 |
((StackFrameImpl)frame).pop(); |
|
558 |
} |
|
559 |
||
45714 | 560 |
public void forceEarlyReturn(Value returnValue) throws InvalidTypeException, |
561 |
ClassNotLoadedException, |
|
2 | 562 |
IncompatibleThreadStateException { |
563 |
if (!vm.canForceEarlyReturn()) { |
|
564 |
throw new UnsupportedOperationException( |
|
565 |
"target does not support the forcing of a method to return early"); |
|
566 |
} |
|
567 |
||
568 |
validateMirrorOrNull(returnValue); |
|
569 |
||
570 |
StackFrameImpl sf; |
|
571 |
try { |
|
572 |
sf = (StackFrameImpl)frame(0); |
|
573 |
} catch (IndexOutOfBoundsException exc) { |
|
574 |
throw new InvalidStackFrameException("No more frames on the stack"); |
|
575 |
} |
|
576 |
sf.validateStackFrame(); |
|
577 |
MethodImpl meth = (MethodImpl)sf.location().method(); |
|
578 |
ValueImpl convertedValue = ValueImpl.prepareForAssignment(returnValue, |
|
579 |
meth.getReturnValueContainer()); |
|
580 |
||
581 |
try { |
|
582 |
JDWP.ThreadReference.ForceEarlyReturn.process(vm, this, convertedValue); |
|
583 |
} catch (JDWPException exc) { |
|
584 |
switch (exc.errorCode()) { |
|
585 |
case JDWP.Error.OPAQUE_FRAME: |
|
586 |
throw new NativeMethodException(); |
|
587 |
case JDWP.Error.THREAD_NOT_SUSPENDED: |
|
588 |
throw new IncompatibleThreadStateException( |
|
589 |
"Thread not suspended"); |
|
590 |
case JDWP.Error.THREAD_NOT_ALIVE: |
|
591 |
throw new IncompatibleThreadStateException( |
|
592 |
"Thread has not started or has finished"); |
|
593 |
case JDWP.Error.NO_MORE_FRAMES: |
|
594 |
throw new InvalidStackFrameException( |
|
595 |
"No more frames on the stack"); |
|
596 |
default: |
|
597 |
throw exc.toJDIException(); |
|
598 |
} |
|
599 |
} |
|
600 |
} |
|
601 |
||
602 |
public String toString() { |
|
603 |
return "instance of " + referenceType().name() + |
|
604 |
"(name='" + name() + "', " + "id=" + uniqueID() + ")"; |
|
605 |
} |
|
606 |
||
607 |
byte typeValueKey() { |
|
608 |
return JDWP.Tag.THREAD; |
|
609 |
} |
|
610 |
||
611 |
void addListener(ThreadListener listener) { |
|
612 |
synchronized (vm.state()) { |
|
45714 | 613 |
listeners.add(new WeakReference<>(listener)); |
2 | 614 |
} |
615 |
} |
|
616 |
||
617 |
void removeListener(ThreadListener listener) { |
|
618 |
synchronized (vm.state()) { |
|
11277 | 619 |
Iterator<WeakReference<ThreadListener>> iter = listeners.iterator(); |
2 | 620 |
while (iter.hasNext()) { |
11277 | 621 |
WeakReference<ThreadListener> ref = iter.next(); |
2 | 622 |
if (listener.equals(ref.get())) { |
623 |
iter.remove(); |
|
624 |
break; |
|
625 |
} |
|
626 |
} |
|
627 |
} |
|
628 |
} |
|
629 |
||
630 |
/** |
|
28059
e576535359cc
8067377: My hobby: caning, then then canning, the the can-can
martin
parents:
25859
diff
changeset
|
631 |
* Propagate the thread state change information |
2 | 632 |
* to registered listeners. |
633 |
* Must be entered while synchronized on vm.state() |
|
634 |
*/ |
|
635 |
private void processThreadAction(ThreadAction action) { |
|
636 |
synchronized (vm.state()) { |
|
11277 | 637 |
Iterator<WeakReference<ThreadListener>> iter = listeners.iterator(); |
2 | 638 |
while (iter.hasNext()) { |
11277 | 639 |
WeakReference<ThreadListener> ref = iter.next(); |
640 |
ThreadListener listener = ref.get(); |
|
2 | 641 |
if (listener != null) { |
642 |
switch (action.id()) { |
|
643 |
case ThreadAction.THREAD_RESUMABLE: |
|
644 |
if (!listener.threadResumable(action)) { |
|
645 |
iter.remove(); |
|
646 |
} |
|
647 |
break; |
|
648 |
} |
|
649 |
} else { |
|
650 |
// Listener is unreachable; clean up |
|
651 |
iter.remove(); |
|
652 |
} |
|
653 |
} |
|
836
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
654 |
|
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
655 |
// Discard our local cache |
d81b1f62fb82
6700889: Thread resume invalidates all stack frames, even from other threads
jjh
parents:
2
diff
changeset
|
656 |
resetLocalCache(); |
2 | 657 |
} |
658 |
} |
|
659 |
} |