1/*
2 * Copyright (c) 2000, 2016, 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        virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class);
133        virtualConstructor.addMapping("ServiceThread", ServiceThread.class);
134    }
135
136    public Threads() {
137    }
138
139    /** NOTE: this returns objects of type JavaThread, CompilerThread,
140      JvmtiAgentThread, and ServiceThread.
141      The latter four are subclasses of the former. Most operations
142      (fetching the top frame, etc.) are only allowed to be performed on
143      a "pure" JavaThread. For this reason, {@link
144      sun.jvm.hotspot.runtime.JavaThread#isJavaThread} has been
145      changed from the definition in the VM (which returns true for
146      all of these thread types) to return true for JavaThreads and
147      false for the three subclasses. FIXME: should reconsider the
148      inheritance hierarchy; see {@link
149      sun.jvm.hotspot.runtime.JavaThread#isJavaThread}. */
150    public JavaThread first() {
151        Address threadAddr = threadListField.getValue();
152        if (threadAddr == null) {
153            return null;
154        }
155
156        return createJavaThreadWrapper(threadAddr);
157    }
158
159    public int getNumberOfThreads() {
160        return (int) numOfThreadsField.getValue();
161    }
162
163    /** Routine for instantiating appropriately-typed wrapper for a
164      JavaThread. Currently needs to be public for OopUtilities to
165      access it. */
166    public JavaThread createJavaThreadWrapper(Address threadAddr) {
167        try {
168            JavaThread thread = (JavaThread)virtualConstructor.instantiateWrapperFor(threadAddr);
169            thread.setThreadPDAccess(access);
170            return thread;
171        } catch (Exception e) {
172            throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr +
173            " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread or CodeCacheSweeperThread)", e);
174        }
175    }
176
177    /** Memory operations */
178    public void oopsDo(AddressVisitor oopVisitor) {
179        // FIXME: add more of VM functionality
180        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
181            thread.oopsDo(oopVisitor);
182        }
183    }
184
185    // refer to Threads::owning_thread_from_monitor_owner
186    public JavaThread owningThreadFromMonitor(Address o) {
187        if (o == null) return null;
188        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
189            if (o.equals(thread.threadObjectAddress())) {
190                return thread;
191            }
192        }
193
194        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
195          if (thread.isLockOwned(o))
196            return thread;
197        }
198        return null;
199    }
200
201    public JavaThread owningThreadFromMonitor(ObjectMonitor monitor) {
202        return owningThreadFromMonitor(monitor.owner());
203    }
204
205    // refer to Threads::get_pending_threads
206    // Get list of Java threads that are waiting to enter the specified monitor.
207    public List getPendingThreads(ObjectMonitor monitor) {
208        List pendingThreads = new ArrayList();
209        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
210            if (thread.isCompilerThread() || thread.isCodeCacheSweeperThread()) {
211                continue;
212            }
213            ObjectMonitor pending = thread.getCurrentPendingMonitor();
214            if (monitor.equals(pending)) {
215                pendingThreads.add(thread);
216            }
217        }
218        return pendingThreads;
219    }
220
221    // Get list of Java threads that have called Object.wait on the specified monitor.
222    public List getWaitingThreads(ObjectMonitor monitor) {
223        List pendingThreads = new ArrayList();
224        for (JavaThread thread = first(); thread != null; thread = thread.next()) {
225            ObjectMonitor waiting = thread.getCurrentWaitingMonitor();
226            if (monitor.equals(waiting)) {
227                pendingThreads.add(thread);
228            }
229        }
230        return pendingThreads;
231    }
232
233    // FIXME: add other accessors
234}
235