| /******************************************************************************* |
| * Copyright (c) 2000, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdi.internal; |
| |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; |
| import org.eclipse.jdi.internal.jdwp.JdwpID; |
| import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; |
| import org.eclipse.jdi.internal.jdwp.JdwpThreadGroupID; |
| |
| import com.sun.jdi.ThreadGroupReference; |
| import com.sun.jdi.ThreadReference; |
| |
| /** |
| * this class implements the corresponding interfaces declared by the JDI |
| * specification. See the com.sun.jdi package for more information. |
| * |
| */ |
| public class ThreadGroupReferenceImpl extends ObjectReferenceImpl implements |
| ThreadGroupReference { |
| /** JDWP Tag. */ |
| public static final byte tag = JdwpID.THREAD_GROUP_TAG; |
| /** |
| * The cached name of this thread group. This value is safe to cache because |
| * there is no API for changing the name of a ThreadGroup. |
| */ |
| private String fName; |
| /** |
| * The cached parent of this thread group. Once set, this value cannot be |
| * changed |
| */ |
| private ThreadGroupReference fParent = fgUnsetParent; |
| private static ThreadGroupReferenceImpl fgUnsetParent = new ThreadGroupReferenceImpl( |
| null, null); |
| |
| /** |
| * Creates new ThreadGroupReferenceImpl. |
| */ |
| public ThreadGroupReferenceImpl(VirtualMachineImpl vmImpl, |
| JdwpThreadGroupID threadGroupID) { |
| super("ThreadGroupReference", vmImpl, threadGroupID); //$NON-NLS-1$ |
| } |
| |
| /** |
| * @returns Value tag. |
| */ |
| @Override |
| public byte getTag() { |
| return tag; |
| } |
| |
| /* (non-Javadoc) |
| * @see com.sun.jdi.ThreadGroupReference#name() |
| */ |
| @Override |
| public String name() { |
| if (fName != null) { |
| return fName; |
| } |
| initJdwpRequest(); |
| try { |
| JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.TGR_NAME, |
| this); |
| defaultReplyErrorHandler(replyPacket.errorCode()); |
| DataInputStream replyData = replyPacket.dataInStream(); |
| fName = readString("name", replyData); //$NON-NLS-1$ |
| return fName; |
| } catch (IOException e) { |
| defaultIOExceptionHandler(e); |
| return null; |
| } finally { |
| handledJdwpRequest(); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see com.sun.jdi.ThreadGroupReference#parent() |
| */ |
| @Override |
| public ThreadGroupReference parent() { |
| if (fParent != fgUnsetParent) { |
| return fParent; |
| } |
| initJdwpRequest(); |
| try { |
| JdwpReplyPacket replyPacket = requestVM( |
| JdwpCommandPacket.TGR_PARENT, this); |
| defaultReplyErrorHandler(replyPacket.errorCode()); |
| DataInputStream replyData = replyPacket.dataInStream(); |
| fParent = ThreadGroupReferenceImpl.read(this, replyData); |
| return fParent; |
| } catch (IOException e) { |
| defaultIOExceptionHandler(e); |
| return null; |
| } finally { |
| handledJdwpRequest(); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see com.sun.jdi.ThreadGroupReference#resume() |
| */ |
| @Override |
| public void resume() { |
| Iterator<ThreadReference> iter = allThreads().iterator(); |
| while (iter.hasNext()) { |
| ThreadReference thr = iter.next(); |
| thr.resume(); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see com.sun.jdi.ThreadGroupReference#suspend() |
| */ |
| @Override |
| public void suspend() { |
| Iterator<ThreadReference> iter = allThreads().iterator(); |
| while (iter.hasNext()) { |
| ThreadReference thr = iter.next(); |
| thr.suspend(); |
| } |
| } |
| |
| /** |
| * Inner class used to return children info. |
| */ |
| private class ChildrenInfo { |
| List<ThreadReference> childThreads; |
| List<ThreadGroupReference> childThreadGroups; |
| } |
| |
| /** |
| * @return Returns a List containing each ThreadReference in this thread |
| * group. |
| */ |
| public ChildrenInfo childrenInfo() { |
| // Note that this information should not be cached. |
| initJdwpRequest(); |
| try { |
| JdwpReplyPacket replyPacket = requestVM( |
| JdwpCommandPacket.TGR_CHILDREN, this); |
| defaultReplyErrorHandler(replyPacket.errorCode()); |
| DataInputStream replyData = replyPacket.dataInStream(); |
| ChildrenInfo result = new ChildrenInfo(); |
| int nrThreads = readInt("nr threads", replyData); //$NON-NLS-1$ |
| result.childThreads = new ArrayList<>(nrThreads); |
| for (int i = 0; i < nrThreads; i++) |
| result.childThreads.add(ThreadReferenceImpl.read(this, |
| replyData)); |
| int nrThreadGroups = readInt("nr thread groups", replyData); //$NON-NLS-1$ |
| result.childThreadGroups = new ArrayList<>(nrThreadGroups); |
| for (int i = 0; i < nrThreadGroups; i++) |
| result.childThreadGroups.add(ThreadGroupReferenceImpl.read( |
| this, replyData)); |
| return result; |
| } catch (IOException e) { |
| defaultIOExceptionHandler(e); |
| return null; |
| } finally { |
| handledJdwpRequest(); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see com.sun.jdi.ThreadGroupReference#threadGroups() |
| */ |
| @Override |
| public List<ThreadGroupReference> threadGroups() { |
| return childrenInfo().childThreadGroups; |
| } |
| |
| /* (non-Javadoc) |
| * @see com.sun.jdi.ThreadGroupReference#threads() |
| */ |
| @Override |
| public List<ThreadReference> threads() { |
| return childrenInfo().childThreads; |
| } |
| |
| /** |
| * @return Returns a List containing each ThreadGroupReference in this |
| * thread group and all of its subgroups. |
| */ |
| private List<ThreadReference> allThreads() { |
| ChildrenInfo info = childrenInfo(); |
| List<ThreadReference> result = info.childThreads; |
| Iterator<ThreadGroupReference> iter = info.childThreadGroups.iterator(); |
| while (iter.hasNext()) { |
| ThreadGroupReferenceImpl tg = (ThreadGroupReferenceImpl) iter.next(); |
| result.addAll(tg.allThreads()); |
| } |
| return result; |
| } |
| |
| /** |
| * @return Returns description of Mirror object. |
| */ |
| @Override |
| public String toString() { |
| try { |
| return name(); |
| } catch (Exception e) { |
| return fDescription; |
| } |
| } |
| |
| /** |
| * @return Reads JDWP representation and returns new instance. |
| */ |
| public static ThreadGroupReferenceImpl read(MirrorImpl target, |
| DataInputStream in) throws IOException { |
| VirtualMachineImpl vmImpl = target.virtualMachineImpl(); |
| JdwpThreadGroupID ID = new JdwpThreadGroupID(vmImpl); |
| ID.read(in); |
| if (target.fVerboseWriter != null) |
| target.fVerboseWriter.println("threadGroupReference", ID.value()); //$NON-NLS-1$ |
| |
| if (ID.isNull()) |
| return null; |
| |
| ThreadGroupReferenceImpl mirror = (ThreadGroupReferenceImpl) vmImpl |
| .getCachedMirror(ID); |
| if (mirror == null) { |
| mirror = new ThreadGroupReferenceImpl(vmImpl, ID); |
| vmImpl.addCachedMirror(mirror); |
| } |
| return mirror; |
| } |
| } |