Threads.java revision 9883:903a2e023ffb
1/*
2 * Copyright (c) 2000, 2013, 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
25package sun.jvm.hotspot.runtime;
26
27import java.util.*;
28
29import sun.jvm.hotspot.debugger.*;
30import sun.jvm.hotspot.types.*;
31import sun.jvm.hotspot.runtime.solaris_sparc.SolarisSPARCJavaThreadPDAccess;
32import sun.jvm.hotspot.runtime.solaris_x86.SolarisX86JavaThreadPDAccess;
33import sun.jvm.hotspot.runtime.solaris_amd64.SolarisAMD64JavaThreadPDAccess;
34import sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess;
35import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess;
36import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess;
37import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess;
38import sun.jvm.hotspot.runtime.linux_aarch64.LinuxAARCH64JavaThreadPDAccess;
39import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess;
40import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess;
41import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess;
42import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess;
43import sun.jvm.hotspot.utilities.*;
44
45public class Threads {
46    private static JavaThreadFactory threadFactory;
47    private static AddressField      threadListField;
48    private static CIntegerField     numOfThreadsField;
49    private static VirtualConstructor virtualConstructor;
50    private static JavaThreadPDAccess access;
51
52    static {
53        VM.registerVMInitializedObserver(new Observer() {
54            public void update(Observable o, Object data) {
55                initialize(VM.getVM().getTypeDataBase());
56            }
57        });
58    }
59
60    private static synchronized void initialize(TypeDataBase db) {
61        Type type = db.lookupType("Threads");
62
63        threadListField = type.getAddressField("_thread_list");
64        numOfThreadsField = type.getCIntegerField("_number_of_threads");
65
66        // Instantiate appropriate platform-specific JavaThreadFactory
67        String os  = VM.getVM().getOS();
68        String cpu = VM.getVM().getCPU();
69
70        access = null;
71        // FIXME: find the platform specific PD class by reflection?
72        if (os.equals("solaris")) {
73            if (cpu.equals("sparc")) {
74                access = new SolarisSPARCJavaThreadPDAccess();
75            } else if (cpu.equals("x86")) {
76                access = new SolarisX86JavaThreadPDAccess();
77            } else if (cpu.equals("amd64")) {
78                access = new SolarisAMD64JavaThreadPDAccess();
79            }
80        } else if (os.equals("win32")) {
81            if (cpu.equals("x86")) {
82                access =  new Win32X86JavaThreadPDAccess();
83            } else if (cpu.equals("amd64")) {
84                access =  new Win32AMD64JavaThreadPDAccess();
85            }
86        } else if (os.equals("linux")) {
87            if (cpu.equals("x86")) {
88                access = new LinuxX86JavaThreadPDAccess();
89            } else if (cpu.equals("amd64")) {
90                access = new LinuxAMD64JavaThreadPDAccess();
91            } else if (cpu.equals("sparc")) {
92                access = new LinuxSPARCJavaThreadPDAccess();
93            } else if (cpu.equals("ppc64")) {
94                access = new LinuxPPC64JavaThreadPDAccess();
95            } else if (cpu.equals("aarch64")) {
96                access = new LinuxAARCH64JavaThreadPDAccess();
97            } else {
98              try {
99                access = (JavaThreadPDAccess)
100                  Class.forName("sun.jvm.hotspot.runtime.linux_" +
101                     cpu.toLowerCase() + ".Linux" + cpu.toUpperCase() +
102                     "JavaThreadPDAccess").newInstance();
103              } catch (Exception e) {
104                throw new RuntimeException("OS/CPU combination " + os + "/" + cpu +
105                                           " not yet supported");
106              }
107            }
108        } else if (os.equals("bsd")) {
109            if (cpu.equals("x86")) {
110                access = new BsdX86JavaThreadPDAccess();
111            } else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
112                access = new BsdAMD64JavaThreadPDAccess();
113            }
114        } else if (os.equals("darwin")) {
115            if (cpu.equals("amd64") || cpu.equals("x86_64")) {
116                access = new BsdAMD64JavaThreadPDAccess();
117            }
118        }
119
120        if (access == null) {
121            throw new RuntimeException("OS/CPU combination " + os + "/" + cpu +
122            " not yet supported");
123        }
124
125        virtualConstructor = new VirtualConstructor(db);
126        // Add mappings for all known thread types
127        virtualConstructor.addMapping("JavaThread", JavaThread.class);
128        if (!VM.getVM().isCore()) {
129            virtualConstructor.addMapping("CompilerThread", CompilerThread.class);
130            virtualConstructor.addMapping("CodeCacheSweeperThread", CodeCacheSweeperThread.class);
131        }
132        // for now, use JavaThread itself. fix it later with appropriate class if needed
133        virtualConstructor.addMapping("SurrogateLockerThread", JavaThread.class);
134        virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class);
135        virtualConstructor.addMapping("ServiceThread", ServiceThread.class);
136    }
137
138    public Threads() {
139    }
140
141    /** NOTE: this returns objects of type JavaThread, CompilerThread,
142      JvmtiAgentThread, and ServiceThread.
143      The latter four are subclasses of the former. Most operations
144      (fetching the top frame, etc.) are only allowed to be performed on
145      a "pure" JavaThread. For this reason, {@link
146      sun.jvm.hotspot.runtime.JavaThread#isJavaThread} has been
147      changed from the definition in the VM (which returns true for
148      all of these thread types) to return true for JavaThreads and
149      false for the three subclasses. FIXME: should reconsider the
150      inheritance hierarchy; see {@link
151      sun.jvm.hotspot.runtime.JavaThread#isJavaThread}. */
152    public JavaThread first() {
153        Address threadAddr = threadListField.getValue();
154        if (threadAddr == null) {
155            return null;
156        }
157
158        return createJavaThreadWrapper(threadAddr);
159    }
160
161    public int getNumberOfThreads() {
162        return (int) numOfThreadsField.getValue();
163    }
164
165    /** Routine for instantiating appropriately-typed wrapper for a
166      JavaThread. Currently needs to be public for OopUtilities to
167      access it. */
168    public JavaThread createJavaThreadWrapper(Address threadAddr) {
169        try {
170            JavaThread thread = (JavaThread)virtualConstructor.instantiateWrapperFor(threadAddr);
171            thread.setThreadPDAccess(access);
172            return thread;
173        } catch (Exception e) {
174            throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr +
175            " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, SurrogateLockerThread, or CodeCacheSweeperThread)", e);
176        }
177    }
178
179    /** Memory operations */
180    public void oopsDo(AddressVisitor oopVisitor) {
181        // FIXME: add more of VM functionality
182        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
183            thread.oopsDo(oopVisitor);
184        }
185    }
186
187    // refer to Threads::owning_thread_from_monitor_owner
188    public JavaThread owningThreadFromMonitor(Address o) {
189        if (o == null) return null;
190        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
191            if (o.equals(thread.threadObjectAddress())) {
192                return thread;
193            }
194        }
195
196        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
197          if (thread.isLockOwned(o))
198            return thread;
199        }
200        return null;
201    }
202
203    public JavaThread owningThreadFromMonitor(ObjectMonitor monitor) {
204        return owningThreadFromMonitor(monitor.owner());
205    }
206
207    // refer to Threads::get_pending_threads
208    // Get list of Java threads that are waiting to enter the specified monitor.
209    public List getPendingThreads(ObjectMonitor monitor) {
210        List pendingThreads = new ArrayList();
211        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
212            if (thread.isCompilerThread() || thread.isCodeCacheSweeperThread()) {
213                continue;
214            }
215            ObjectMonitor pending = thread.getCurrentPendingMonitor();
216            if (monitor.equals(pending)) {
217                pendingThreads.add(thread);
218            }
219        }
220        return pendingThreads;
221    }
222
223    // Get list of Java threads that have called Object.wait on the specified monitor.
224    public List getWaitingThreads(ObjectMonitor monitor) {
225        List pendingThreads = new ArrayList();
226        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
227            ObjectMonitor waiting = thread.getCurrentWaitingMonitor();
228            if (monitor.equals(waiting)) {
229                pendingThreads.add(thread);
230            }
231        }
232        return pendingThreads;
233    }
234
235    // FIXME: add other accessors
236}
237