001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.debugger.jpda.models;
043:
044: import com.sun.jdi.AbsentInformationException;
045: import com.sun.jdi.IncompatibleThreadStateException;
046: import com.sun.jdi.InvalidStackFrameException;
047: import com.sun.jdi.InternalException;
048: import com.sun.jdi.NativeMethodException;
049: import com.sun.jdi.ObjectCollectedException;
050: import com.sun.jdi.ObjectReference;
051: import com.sun.jdi.StackFrame;
052: import com.sun.jdi.ThreadGroupReference;
053: import com.sun.jdi.ThreadReference;
054: import com.sun.jdi.VMDisconnectedException;
055:
056: import java.beans.PropertyChangeListener;
057: import java.beans.PropertyChangeSupport;
058: import java.beans.PropertyVetoException;
059: import java.util.ArrayList;
060: import java.util.List;
061: import java.util.logging.Level;
062: import java.util.logging.Logger;
063:
064: import org.netbeans.api.debugger.jpda.CallStackFrame;
065: import org.netbeans.api.debugger.jpda.JPDAThread;
066: import org.netbeans.api.debugger.jpda.JPDAThreadGroup;
067: import org.netbeans.api.debugger.jpda.ObjectVariable;
068: import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
069: import org.netbeans.spi.debugger.jpda.EditorContext.Operation;
070: import org.openide.ErrorManager;
071: import org.openide.util.NbBundle;
072:
073: /**
074: * The implementation of JPDAThread.
075: */
076: public final class JPDAThreadImpl implements JPDAThread {
077:
078: /**
079: * Suspended property of the thread. Fired when isSuspended() changes.
080: */
081: public static final String PROP_SUSPENDED = "suspended";
082:
083: private ThreadReference threadReference;
084: private JPDADebuggerImpl debugger;
085: private boolean suspended;
086: private int suspendCount;
087: private Operation currentOperation;
088: private List<Operation> lastOperations;
089: private boolean doKeepLastOperations;
090: private ReturnVariableImpl returnVariable;
091: private PropertyChangeSupport pch = new PropertyChangeSupport(this );
092: private CallStackFrame[] cachedFrames;
093: private int cachedFramesFrom = -1;
094: private int cachedFramesTo = -1;
095: private Object cachedFramesLock = new Object();
096:
097: public JPDAThreadImpl(ThreadReference threadReference,
098: JPDADebuggerImpl debugger) {
099: this .threadReference = threadReference;
100: this .debugger = debugger;
101: suspended = threadReference.isSuspended();
102: suspendCount = threadReference.suspendCount();
103: }
104:
105: /**
106: * Getter for the name of thread property.
107: *
108: * @return name of thread.
109: */
110: public String getName() {
111: try {
112: return threadReference.name();
113: } catch (IllegalThreadStateException ex) {
114: return ""; // Thrown when thread has exited
115: } catch (ObjectCollectedException ex) {
116: return "";
117: } catch (VMDisconnectedException ex) {
118: return "";
119: }
120: }
121:
122: /**
123: * Returns parent thread group.
124: *
125: * @return parent thread group.
126: */
127: public JPDAThreadGroup getParentThreadGroup() {
128: try {
129: ThreadGroupReference tgr = threadReference.threadGroup();
130: if (tgr == null)
131: return null;
132: return debugger.getThreadGroup(tgr);
133: } catch (IllegalThreadStateException ex) {
134: return null; // Thrown when thread has exited
135: } catch (ObjectCollectedException ex) {
136: return null;
137: } catch (VMDisconnectedException ex) {
138: return null;
139: }
140: }
141:
142: /**
143: * Returns line number of the location this thread stopped at.
144: * The thread should be suspended at the moment this method is called.
145: *
146: * @return line number of the current location if the thread is suspended,
147: * contains at least one frame and the topmost frame does not
148: * represent a native method invocation; <CODE>-1</CODE> otherwise
149: * @see CallStackFrame
150: */
151: public int getLineNumber(String stratum) {
152: try {
153: if (threadReference.frameCount() < 1)
154: return -1;
155: return threadReference.frame(0).location().lineNumber(
156: stratum);
157: } catch (ObjectCollectedException ex) {
158: } catch (InvalidStackFrameException ex) {
159: } catch (IncompatibleThreadStateException ex) {
160: } catch (IllegalThreadStateException ex) {
161: // Thrown when thread has exited
162: } catch (VMDisconnectedException ex) {
163: }
164: return -1;
165: }
166:
167: public synchronized Operation getCurrentOperation() {
168: return currentOperation;
169: }
170:
171: public synchronized void setCurrentOperation(Operation operation) { // Set the current operation for the default stratum.
172: this .currentOperation = operation;
173: }
174:
175: public synchronized List<Operation> getLastOperations() {
176: return lastOperations;
177: }
178:
179: public synchronized void addLastOperation(Operation operation) {
180: if (lastOperations == null) {
181: lastOperations = new ArrayList<Operation>();
182: }
183: lastOperations.add(operation);
184: }
185:
186: public synchronized void clearLastOperations() {
187: if (lastOperations != null) {
188: for (Operation last : lastOperations) {
189: last.setReturnValue(null); // reset the returned value.
190: // Operation might be reused, but the execution path is gone.
191: }
192: }
193: lastOperations = null;
194: }
195:
196: public synchronized void holdLastOperations(boolean doHold) {
197: doKeepLastOperations = doHold;
198: }
199:
200: /**
201: * Returns current state of this thread.
202: *
203: * @return current state of this thread
204: */
205: public int getState() {
206: try {
207: return threadReference.status();
208: } catch (IllegalThreadStateException ex) {
209: // Thrown when thread has exited
210: } catch (ObjectCollectedException ex) {
211: } catch (VMDisconnectedException ex) {
212: }
213: return STATE_UNKNOWN;
214: }
215:
216: /**
217: * Returns true if this thread is suspended by debugger.
218: *
219: * @return true if this thread is suspended by debugger
220: */
221: public synchronized boolean isSuspended() {
222: return suspended;
223: }
224:
225: /**
226: * Returns true if this thread is suspended by debugger.
227: *
228: * @return true if this thread is suspended by debugger
229: */
230: public boolean isThreadSuspended() {
231: try {
232: return threadReference.isSuspended();
233: } catch (IllegalThreadStateException ex) {
234: // Thrown when thread has exited
235: } catch (ObjectCollectedException ex) {
236: } catch (VMDisconnectedException ex) {
237: }
238: return false;
239: }
240:
241: /**
242: * If this thread is suspended returns class name where this thread is stopped.
243: *
244: * @return class name where this thread is stopped.
245: */
246: public String getClassName() {
247: try {
248: if (threadReference.frameCount() < 1)
249: return "";
250: return threadReference.frame(0).location().declaringType()
251: .name();
252: } catch (ObjectCollectedException ex) {
253: } catch (InvalidStackFrameException ex) {
254: } catch (IncompatibleThreadStateException ex) {
255: } catch (IllegalThreadStateException ex) {
256: // Thrown when thread has exited
257: } catch (VMDisconnectedException ex) {
258: }
259: return "";
260: }
261:
262: /**
263: * If this thread is suspended returns method name where this thread is stopped.
264: *
265: * @return method name where this thread is stopped.
266: */
267: public String getMethodName() {
268: try {
269: if (threadReference.frameCount() < 1)
270: return "";
271: return threadReference.frame(0).location().method().name();
272: } catch (ObjectCollectedException ex) {
273: } catch (InvalidStackFrameException ex) {
274: } catch (IncompatibleThreadStateException ex) {
275: } catch (IllegalThreadStateException ex) {
276: // Thrown when thread has exited
277: } catch (VMDisconnectedException ex) {
278: }
279: return "";
280: }
281:
282: /**
283: * Returns name of file of this frame or null if thread has no frame.
284: *
285: * @return Returns name of file of this frame.
286: */
287: public String getSourceName(String stratum)
288: throws AbsentInformationException {
289: try {
290: if (threadReference.frameCount() < 1)
291: return "";
292: return threadReference.frame(0).location().sourceName(
293: stratum);
294: } catch (ObjectCollectedException ex) {
295: } catch (InvalidStackFrameException ex) {
296: } catch (IncompatibleThreadStateException ex) {
297: } catch (IllegalThreadStateException ex) {
298: // Thrown when thread has exited
299: } catch (VMDisconnectedException ex) {
300: }
301: return "";
302: }
303:
304: /**
305: * Returns name of file of this frame or null if thread has no frame.
306: *
307: * @return Returns name of file of this frame.
308: */
309: public String getSourcePath(String stratum)
310: throws AbsentInformationException {
311: try {
312: if (threadReference.frameCount() < 1)
313: return "";
314: return threadReference.frame(0).location().sourcePath(
315: stratum);
316: } catch (ObjectCollectedException ex) {
317: } catch (InvalidStackFrameException ex) {
318: } catch (IncompatibleThreadStateException ex) {
319: } catch (IllegalThreadStateException ex) {
320: // Thrown when thread has exited
321: } catch (VMDisconnectedException ex) {
322: }
323: return "";
324: }
325:
326: /**
327: * Returns call stack for this thread.
328: *
329: * @throws AbsentInformationException if the thread is running or not able
330: * to return callstack. If the thread is in an incompatible state
331: * (e.g. running), the AbsentInformationException has
332: * IncompatibleThreadStateException as a cause.
333: * If the thread is collected, the AbsentInformationException has
334: * ObjectCollectedException as a cause.
335: * @return call stack
336: */
337: public CallStackFrame[] getCallStack()
338: throws AbsentInformationException {
339: return getCallStack(0, getStackDepth());
340: }
341:
342: private Object lastBottomSF;
343:
344: /**
345: * Returns call stack for this thread on the given indexes.
346: *
347: * @param from a from index, inclusive
348: * @param to a to index, exclusive
349: * @throws AbsentInformationException if the thread is running or not able
350: * to return callstack. If the thread is in an incompatible state
351: * (e.g. running), the AbsentInformationException has
352: * IncompatibleThreadStateException as a cause.
353: * If the thread is collected, the AbsentInformationException has
354: * ObjectCollectedException as a cause.
355: * @return call stack
356: */
357: public CallStackFrame[] getCallStack(int from, int to)
358: throws AbsentInformationException {
359: try {
360: int max = threadReference.frameCount();
361: from = Math.min(from, max);
362: to = Math.min(to, max);
363: if (to - from > 1) {
364: synchronized (cachedFramesLock) {
365: if (from == cachedFramesFrom
366: && to == cachedFramesTo) {
367: return cachedFrames;
368: }
369: }
370: }
371: if (from < 0) {
372: throw new IndexOutOfBoundsException("from = " + from);
373: }
374: if (from == to) {
375: return new CallStackFrame[0];
376: }
377: if (from >= max) {
378: throw new IndexOutOfBoundsException("from = " + from
379: + " is too high, frame count = " + max);
380: }
381: int length = to - from;
382: if (length < 0 || (from + length) > max) {
383: throw new IndexOutOfBoundsException("from = " + from
384: + ", to = " + to + ", frame count = " + max);
385: }
386: List l = threadReference.frames(from, length);
387: int n = l.size();
388: CallStackFrame[] frames = new CallStackFrame[n];
389: for (int i = 0; i < n; i++) {
390: frames[i] = new CallStackFrameImpl((StackFrame) l
391: .get(i), from + i, debugger);
392: if (from == 0 && i == 0 && currentOperation != null) {
393: ((CallStackFrameImpl) frames[i])
394: .setCurrentOperation(currentOperation);
395: }
396: }
397: if (to - from > 1) {
398: synchronized (cachedFramesLock) {
399: cachedFrames = frames;
400: cachedFramesFrom = from;
401: cachedFramesTo = to;
402: }
403: }
404: return frames;
405: } catch (IncompatibleThreadStateException ex) {
406: AbsentInformationException aiex = new AbsentInformationException(
407: ex.getLocalizedMessage());
408: aiex.initCause(ex);
409: throw aiex;
410: } catch (ObjectCollectedException ocex) {
411: AbsentInformationException aiex = new AbsentInformationException(
412: ocex.getLocalizedMessage());
413: aiex.initCause(ocex);
414: throw aiex;
415: } catch (IllegalThreadStateException itsex) {
416: // Thrown when thread has exited
417: AbsentInformationException aiex = new AbsentInformationException(
418: itsex.getLocalizedMessage());
419: aiex.initCause(itsex);
420: throw aiex;
421: } catch (VMDisconnectedException ex) {
422: return new CallStackFrame[0];
423: }
424: }
425:
426: private void cleanCachedFrames() {
427: synchronized (cachedFramesLock) {
428: cachedFrames = null;
429: cachedFramesFrom = -1;
430: cachedFramesTo = -1;
431: }
432: }
433:
434: /**
435: * Returns length of current call stack.
436: *
437: * @return length of current call stack
438: */
439: public int getStackDepth() {
440: try {
441: return threadReference.frameCount();
442: } catch (IllegalThreadStateException ex) {
443: // Thrown when thread has exited
444: } catch (ObjectCollectedException ex) {
445: } catch (IncompatibleThreadStateException e) {
446: }
447: return 0;
448: }
449:
450: public void popFrames(StackFrame sf)
451: throws IncompatibleThreadStateException {
452: try {
453: threadReference.popFrames(sf);
454: cleanCachedFrames();
455: setReturnVariable(null); // Clear the return var
456: } catch (IllegalThreadStateException ex) {
457: throw new IncompatibleThreadStateException("Thread exited.");
458: } catch (ObjectCollectedException ex) {
459: throw new IncompatibleThreadStateException("Thread died.");
460: } catch (NativeMethodException nmex) {
461: cleanCachedFrames();
462: ErrorManager.getDefault().notify(
463: ErrorManager.getDefault().annotate(
464: nmex,
465: NbBundle.getMessage(JPDAThreadImpl.class,
466: "MSG_NativeMethodPop")));
467: } catch (InternalException iex) {
468: cleanCachedFrames();
469: if (iex.errorCode() == 32) {
470: ErrorManager.getDefault().notify(
471: ErrorManager.getDefault().annotate(
472: iex,
473: NbBundle.getMessage(
474: JPDAThreadImpl.class,
475: "MSG_NativeMethodPop")));
476: } else {
477: throw iex;
478: }
479: }
480: }
481:
482: /**
483: * Suspends thread.
484: */
485: public void suspend() {
486: Boolean suspendedToFire = null;
487: synchronized (this ) {
488: try {
489: if (!isSuspended()) {
490: threadReference.suspend();
491: suspendedToFire = Boolean.TRUE;
492: suspendCount++;
493: }
494: //System.err.println("suspend("+getName()+") suspended = true");
495: suspended = true;
496: } catch (IllegalThreadStateException ex) {
497: // Thrown when thread has exited
498: } catch (ObjectCollectedException ex) {
499: } catch (VMDisconnectedException ex) {
500: }
501: }
502: if (suspendedToFire != null) {
503: pch.firePropertyChange(PROP_SUSPENDED, Boolean
504: .valueOf(!suspendedToFire.booleanValue()),
505: suspendedToFire);
506: }
507: }
508:
509: /**
510: * Unsuspends thread.
511: */
512: public void resume() {
513: if (this == debugger.getCurrentThread()) {
514: boolean can = debugger.currentThreadToBeResumed();
515: if (!can)
516: return;
517: }
518: Boolean suspendedToFire = null;
519: synchronized (this ) {
520: waitUntilMethodInvokeDone();
521: setReturnVariable(null); // Clear the return var on resume
522: setCurrentOperation(null);
523: if (!doKeepLastOperations) {
524: clearLastOperations();
525: }
526: try {
527: if (isSuspended()) {
528: int count = threadReference.suspendCount();
529: while (count > 0) {
530: threadReference.resume();
531: count--;
532: }
533: suspendedToFire = Boolean.FALSE;
534: }
535: suspendCount = 0;
536: //System.err.println("resume("+getName()+") suspended = false");
537: suspended = false;
538: methodInvokingDisabledUntilResumed = false;
539: } catch (IllegalThreadStateException ex) {
540: // Thrown when thread has exited
541: } catch (ObjectCollectedException ex) {
542: } catch (VMDisconnectedException ex) {
543: }
544: }
545: cleanCachedFrames();
546: if (suspendedToFire != null) {
547: pch.firePropertyChange(PROP_SUSPENDED, Boolean
548: .valueOf(!suspendedToFire.booleanValue()),
549: suspendedToFire);
550: }
551: }
552:
553: public void notifyToBeResumed() {
554: //System.err.println("notifyToBeResumed("+getName()+")");
555: notifyToBeRunning(true, true);
556: }
557:
558: private void notifyToBeRunning(boolean clearVars, boolean resumed) {
559: Boolean suspendedToFire = null;
560: synchronized (this ) {
561: if (resumed) {
562: waitUntilMethodInvokeDone();
563: }
564: //System.err.println("notifyToBeRunning("+getName()+"), resumed = "+resumed+", suspendCount = "+suspendCount+", thread's suspendCount = "+threadReference.suspendCount());
565: if (resumed && (--suspendCount > 0))
566: return;
567: //System.err.println(" suspendCount = 0, var suspended = "+suspended);
568: suspendCount = 0;
569: if (clearVars) {
570: setCurrentOperation(null);
571: setReturnVariable(null); // Clear the return var on resume
572: if (!doKeepLastOperations) {
573: clearLastOperations();
574: }
575: }
576: if (suspended) {
577: //System.err.println("notifyToBeRunning("+getName()+") suspended = false");
578: suspended = false;
579: suspendedToFire = Boolean.FALSE;
580: methodInvokingDisabledUntilResumed = false;
581: }
582: }
583: cleanCachedFrames();
584: if (suspendedToFire != null) {
585: pch.firePropertyChange(PROP_SUSPENDED, Boolean
586: .valueOf(!suspendedToFire.booleanValue()),
587: suspendedToFire);
588: }
589: }
590:
591: public void notifySuspended() {
592: Boolean suspendedToFire = null;
593: synchronized (this ) {
594: try {
595: suspendCount = threadReference.suspendCount();
596: } catch (IllegalThreadStateException ex) {
597: return; // Thrown when thread has exited
598: } catch (ObjectCollectedException ocex) {
599: return; // The thread is gone
600: }
601: //System.err.println("notifySuspended("+getName()+") suspendCount = "+suspendCount+", var suspended = "+suspended);
602: if (!suspended && isThreadSuspended()) {
603: //System.err.println(" setting suspended = true");
604: suspended = true;
605: suspendedToFire = Boolean.TRUE;
606: }
607: }
608: if (suspendedToFire != null) {
609: pch.firePropertyChange(PROP_SUSPENDED, Boolean
610: .valueOf(!suspendedToFire.booleanValue()),
611: suspendedToFire);
612: }
613: }
614:
615: private boolean methodInvoking;
616: private boolean methodInvokingDisabledUntilResumed;
617:
618: public void notifyMethodInvoking() throws PropertyVetoException {
619: synchronized (this ) {
620: if (methodInvokingDisabledUntilResumed) {
621: throw new PropertyVetoException(
622: "disabled until resumed", null);
623: }
624: if (methodInvoking) {
625: throw new PropertyVetoException("Already invoking!",
626: null);
627: }
628: methodInvoking = true;
629: }
630: notifyToBeRunning(false, false);
631: }
632:
633: public void notifyMethodInvokeDone() {
634: synchronized (this ) {
635: methodInvoking = false;
636: this .notifyAll();
637: }
638: notifySuspended();
639: }
640:
641: public synchronized boolean isMethodInvoking() {
642: return methodInvoking;
643: }
644:
645: public void waitUntilMethodInvokeDone() {
646: synchronized (this ) {
647: while (methodInvoking) {
648: try {
649: this .wait();
650: } catch (InterruptedException iex) {
651: break;
652: }
653: }
654: }
655: }
656:
657: public synchronized void disableMethodInvokeUntilResumed() {
658: methodInvokingDisabledUntilResumed = true;
659: }
660:
661: public void interrupt() {
662: try {
663: if (isSuspended())
664: return;
665: threadReference.interrupt();
666: } catch (IllegalThreadStateException ex) {
667: // Thrown when thread has exited
668: } catch (ObjectCollectedException ex) {
669: } catch (VMDisconnectedException ex) {
670: }
671: }
672:
673: /**
674: * Sets this thread current.
675: *
676: * @see JPDADebugger#getCurrentThread
677: */
678: public void makeCurrent() {
679: debugger.setCurrentThread(this );
680: }
681:
682: /**
683: * Returns monitor this thread is waiting on.
684: *
685: * @return monitor this thread is waiting on
686: */
687: public ObjectVariable getContendedMonitor() {
688: try {
689: if (!threadReference.virtualMachine()
690: .canGetCurrentContendedMonitor()) {
691: return null;
692: }
693: } catch (IllegalThreadStateException ex) {
694: // Thrown when thread has exited
695: return null;
696: } catch (ObjectCollectedException ocex) {
697: return null;
698: }
699: ObjectReference or;
700: synchronized (this ) {
701: if (!isSuspended())
702: return null;
703: if ("DestroyJavaVM".equals(threadReference.name())) {
704: // See defect #6474293
705: return null;
706: }
707: try {
708: or = threadReference.currentContendedMonitor();
709: } catch (IllegalThreadStateException ex) {
710: // Thrown when thread has exited
711: return null;
712: } catch (ObjectCollectedException ex) {
713: return null;
714: } catch (IncompatibleThreadStateException e) {
715: String msg = "Thread '" + threadReference.name()
716: + "': status = " + threadReference.status()
717: + ", is suspended = "
718: + threadReference.isSuspended()
719: + ", suspend count = "
720: + threadReference.suspendCount()
721: + ", is at breakpoint = "
722: + threadReference.isAtBreakpoint()
723: + ", internal suspend status = " + suspended;
724: Logger.getLogger(JPDAThreadImpl.class.getName()).log(
725: Level.WARNING, msg, e);
726: return null;
727: } catch (com.sun.jdi.InternalException iex) {
728: String msg = "Thread '" + threadReference.name()
729: + "': status = " + threadReference.status()
730: + ", is suspended = "
731: + threadReference.isSuspended()
732: + ", suspend count = "
733: + threadReference.suspendCount()
734: + ", is at breakpoint = "
735: + threadReference.isAtBreakpoint()
736: + ", internal suspend status = " + suspended;
737: Logger.getLogger(JPDAThreadImpl.class.getName()).log(
738: Level.WARNING, msg, iex);
739: return null;
740: }
741: }
742: if (or == null)
743: return null;
744: return new ThisVariable(debugger, or, "");
745: }
746:
747: /**
748: * Returns monitors owned by this thread.
749: *
750: * @return monitors owned by this thread
751: */
752: public ObjectVariable[] getOwnedMonitors() {
753: try {
754: if (!threadReference.virtualMachine()
755: .canGetOwnedMonitorInfo()) {
756: return new ObjectVariable[0];
757: }
758: } catch (IllegalThreadStateException ex) {
759: // Thrown when thread has exited
760: return new ObjectVariable[0];
761: } catch (ObjectCollectedException ocex) {
762: return new ObjectVariable[0];
763: }
764: List l;
765: synchronized (this ) {
766: if (!isSuspended())
767: return new ObjectVariable[0];
768: if ("DestroyJavaVM".equals(threadReference.name())) {
769: // See defect #6474293
770: return new ObjectVariable[0];
771: }
772: try {
773: l = threadReference.ownedMonitors();
774: } catch (IllegalThreadStateException ex) {
775: // Thrown when thread has exited
776: return new ObjectVariable[0];
777: } catch (ObjectCollectedException ex) {
778: return new ObjectVariable[0];
779: } catch (IncompatibleThreadStateException e) {
780: String msg = "Thread '" + threadReference.name()
781: + "': status = " + threadReference.status()
782: + ", is suspended = "
783: + threadReference.isSuspended()
784: + ", suspend count = "
785: + threadReference.suspendCount()
786: + ", is at breakpoint = "
787: + threadReference.isAtBreakpoint()
788: + ", internal suspend status = " + suspended;
789: Logger.getLogger(JPDAThreadImpl.class.getName()).log(
790: Level.WARNING, msg, e);
791: return new ObjectVariable[0];
792: } catch (com.sun.jdi.InternalException iex) {
793: String msg = "Thread '" + threadReference.name()
794: + "': status = " + threadReference.status()
795: + ", is suspended = "
796: + threadReference.isSuspended()
797: + ", suspend count = "
798: + threadReference.suspendCount()
799: + ", is at breakpoint = "
800: + threadReference.isAtBreakpoint()
801: + ", internal suspend status = " + suspended;
802: Logger.getLogger(JPDAThreadImpl.class.getName()).log(
803: Level.WARNING, msg, iex);
804: return new ObjectVariable[0];
805: }
806: }
807: int i, k = l.size();
808: ObjectVariable[] vs = new ObjectVariable[k];
809: for (i = 0; i < k; i++) {
810: vs[i] = new ThisVariable(debugger, (ObjectReference) l
811: .get(i), "");
812: }
813: return vs;
814: }
815:
816: public ThreadReference getThreadReference() {
817: return threadReference;
818: }
819:
820: public synchronized ReturnVariableImpl getReturnVariable() {
821: return returnVariable;
822: }
823:
824: public synchronized void setReturnVariable(
825: ReturnVariableImpl returnVariable) {
826: this .returnVariable = returnVariable;
827: }
828:
829: public void addPropertyChangeListener(PropertyChangeListener l) {
830: pch.addPropertyChangeListener(l);
831: }
832:
833: public void removePropertyChangeListener(PropertyChangeListener l) {
834: pch.removePropertyChangeListener(l);
835: }
836:
837: private void fireSuspended(boolean suspended) {
838: pch.firePropertyChange(PROP_SUSPENDED, Boolean
839: .valueOf(!suspended), Boolean.valueOf(suspended));
840: }
841:
842: }
|