1 /* 2 * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. 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 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.runtime; 26 27 import java.util.*; 28 29 import sun.jvm.hotspot.debugger.*; 30 import sun.jvm.hotspot.types.*; 31 import sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess; 32 import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess; 33 import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess; 34 import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess; 35 import sun.jvm.hotspot.runtime.linux_aarch64.LinuxAARCH64JavaThreadPDAccess; 36 import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess; 37 import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess; 38 import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess; 39 import sun.jvm.hotspot.utilities.*; 40 import sun.jvm.hotspot.utilities.Observable; 41 import sun.jvm.hotspot.utilities.Observer; 42 43 class ThreadsList extends VMObject { 44 private static AddressField threadsField; 45 private static CIntegerField lengthField; 46 47 static { 48 VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase())); 49 } 50 51 private static synchronized void initialize(TypeDataBase db) { 52 Type type = db.lookupType("ThreadsList"); 53 lengthField = type.getCIntegerField("_length"); 54 threadsField = type.getAddressField("_threads"); 55 } 56 57 public Address getJavaThreadAddressAt(int i) { 58 Address threadAddr = threadsField.getValue(addr); 59 Address at = threadAddr.getAddressAt(VM.getVM().getAddressSize() * i); 60 return at; 61 } 62 63 public long length() { 64 return lengthField.getValue(addr); 65 } 66 67 public ThreadsList(Address addr) { 68 super(addr); 69 } 70 } 71 72 public class Threads { 73 private static JavaThreadFactory threadFactory; 74 private static AddressField threadListField; 75 private static VirtualConstructor virtualConstructor; 76 private static JavaThreadPDAccess access; 77 private static ThreadsList _list; 78 79 static { 80 VM.registerVMInitializedObserver(new Observer() { 81 public void update(Observable o, Object data) { 82 initialize(VM.getVM().getTypeDataBase()); 83 } 84 }); 85 } 86 87 private static synchronized void initialize(TypeDataBase db) { 88 Type type = db.lookupType("ThreadsSMRSupport"); 89 threadListField = type.getAddressField("_java_thread_list"); 90 91 // Instantiate appropriate platform-specific JavaThreadFactory 92 String os = VM.getVM().getOS(); 93 String cpu = VM.getVM().getCPU(); 94 95 access = null; 96 // FIXME: find the platform specific PD class by reflection? 97 if (os.equals("win32")) { 98 if (cpu.equals("x86")) { 99 access = new Win32X86JavaThreadPDAccess(); 100 } else if (cpu.equals("amd64")) { 101 access = new Win32AMD64JavaThreadPDAccess(); 102 } 103 } else if (os.equals("linux")) { 104 if (cpu.equals("x86")) { 105 access = new LinuxX86JavaThreadPDAccess(); 106 } else if (cpu.equals("amd64")) { 107 access = new LinuxAMD64JavaThreadPDAccess(); 108 } else if (cpu.equals("ppc64")) { 109 access = new LinuxPPC64JavaThreadPDAccess(); 110 } else if (cpu.equals("aarch64")) { 111 access = new LinuxAARCH64JavaThreadPDAccess(); 112 } else { 113 try { 114 access = (JavaThreadPDAccess) 115 Class.forName("sun.jvm.hotspot.runtime.linux_" + 116 cpu.toLowerCase() + ".Linux" + cpu.toUpperCase() + 117 "JavaThreadPDAccess").getDeclaredConstructor().newInstance(); 118 } catch (Exception e) { 119 throw new RuntimeException("OS/CPU combination " + os + "/" + cpu + 120 " not yet supported"); 121 } 122 } 123 } else if (os.equals("bsd")) { 124 if (cpu.equals("x86")) { 125 access = new BsdX86JavaThreadPDAccess(); 126 } else if (cpu.equals("amd64") || cpu.equals("x86_64")) { 127 access = new BsdAMD64JavaThreadPDAccess(); 128 } 129 } else if (os.equals("darwin")) { 130 if (cpu.equals("amd64") || cpu.equals("x86_64")) { 131 access = new BsdAMD64JavaThreadPDAccess(); 132 } 133 } 134 135 if (access == null) { 136 throw new RuntimeException("OS/CPU combination " + os + "/" + cpu + 137 " not yet supported"); 138 } 139 140 virtualConstructor = new VirtualConstructor(db); 141 // Add mappings for all known thread types 142 virtualConstructor.addMapping("JavaThread", JavaThread.class); 143 if (!VM.getVM().isCore()) { 144 virtualConstructor.addMapping("CompilerThread", CompilerThread.class); 145 virtualConstructor.addMapping("CodeCacheSweeperThread", CodeCacheSweeperThread.class); 146 } 147 virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class); 148 virtualConstructor.addMapping("ServiceThread", ServiceThread.class); 149 virtualConstructor.addMapping("NotificationThread", NotificationThread.class); 150 } 151 152 public Threads() { 153 _list = VMObjectFactory.newObject(ThreadsList.class, threadListField.getValue()); 154 } 155 156 /** NOTE: this returns objects of type JavaThread, CompilerThread, 157 JvmtiAgentThread, NotificationThread, and ServiceThread. 158 The latter four are subclasses of the former. Most operations 159 (fetching the top frame, etc.) are only allowed to be performed on 160 a "pure" JavaThread. For this reason, {@link 161 sun.jvm.hotspot.runtime.JavaThread#isJavaThread} has been 162 changed from the definition in the VM (which returns true for 163 all of these thread types) to return true for JavaThreads and 164 false for the four subclasses. FIXME: should reconsider the 165 inheritance hierarchy; see {@link 166 sun.jvm.hotspot.runtime.JavaThread#isJavaThread}. */ 167 public JavaThread getJavaThreadAt(int i) { 168 if (i < _list.length()) { 169 return createJavaThreadWrapper(_list.getJavaThreadAddressAt(i)); 170 } 171 return null; 172 } 173 174 public int getNumberOfThreads() { 175 return (int) _list.length(); 176 } 177 178 /** Routine for instantiating appropriately-typed wrapper for a 179 JavaThread. Currently needs to be public for OopUtilities to 180 access it. */ 181 public JavaThread createJavaThreadWrapper(Address threadAddr) { 182 try { 183 JavaThread thread = (JavaThread)virtualConstructor.instantiateWrapperFor(threadAddr); 184 thread.setThreadPDAccess(access); 185 return thread; 186 } catch (Exception e) { 187 throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr + 188 " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread or CodeCacheSweeperThread)", e); 189 } 190 } 191 192 /** Memory operations */ 193 public void oopsDo(AddressVisitor oopVisitor) { 194 // FIXME: add more of VM functionality 195 Threads threads = VM.getVM().getThreads(); 196 for (int i = 0; i < threads.getNumberOfThreads(); i++) { 197 JavaThread thread = threads.getJavaThreadAt(i); 198 thread.oopsDo(oopVisitor); 199 } 200 } 201 202 // refer to Threads::owning_thread_from_monitor_owner 203 public JavaThread owningThreadFromMonitor(Address o) { 204 if (o == null) return null; 205 for (int i = 0; i < getNumberOfThreads(); i++) { 206 JavaThread thread = getJavaThreadAt(i); 207 if (o.equals(thread.threadObjectAddress())) { 208 return thread; 209 } 210 } 211 212 for (int i = 0; i < getNumberOfThreads(); i++) { 213 JavaThread thread = getJavaThreadAt(i); 214 if (thread.isLockOwned(o)) 215 return thread; 216 } 217 return null; 218 } 219 220 public JavaThread owningThreadFromMonitor(ObjectMonitor monitor) { 221 return owningThreadFromMonitor(monitor.owner()); 222 } 223 224 // refer to Threads::get_pending_threads 225 // Get list of Java threads that are waiting to enter the specified monitor. 226 public List<JavaThread> getPendingThreads(ObjectMonitor monitor) { 227 List<JavaThread> pendingThreads = new ArrayList<>(); 228 for (int i = 0; i < getNumberOfThreads(); i++) { 229 JavaThread thread = getJavaThreadAt(i); 230 if (thread.isCompilerThread() || thread.isCodeCacheSweeperThread()) { 231 continue; 232 } 233 ObjectMonitor pending = thread.getCurrentPendingMonitor(); 234 if (monitor.equals(pending)) { 235 pendingThreads.add(thread); 236 } 237 } 238 return pendingThreads; 239 } 240 241 // Get list of Java threads that have called Object.wait on the specified monitor. 242 public List<JavaThread> getWaitingThreads(ObjectMonitor monitor) { 243 List<JavaThread> pendingThreads = new ArrayList<>(); 244 for (int i = 0; i < getNumberOfThreads(); i++) { 245 JavaThread thread = getJavaThreadAt(i); 246 ObjectMonitor waiting = thread.getCurrentWaitingMonitor(); 247 if (monitor.equals(waiting)) { 248 pendingThreads.add(thread); 249 } 250 } 251 return pendingThreads; 252 } 253 254 // FIXME: add other accessors 255 }