1 /*
2  * Copyright (c) 2003, 2012, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package sun.management.snmp.jvminstr;
26 
27 // java imports
28 //
29 import java.io.Serializable;
30 import java.lang.management.ThreadInfo;
31 import java.lang.management.ManagementFactory;
32 import java.lang.management.ThreadMXBean;
33 
34 // jmx imports
35 //
36 import com.sun.jmx.snmp.SnmpStatusException;
37 
38 // jdmk imports
39 //
40 import com.sun.jmx.snmp.agent.SnmpMib;
41 import com.sun.jmx.snmp.SnmpOid;
42 import com.sun.jmx.snmp.SnmpDefinitions;
43 import com.sun.jmx.snmp.SnmpOidTable;
44 import com.sun.jmx.snmp.SnmpOidRecord;
45 
46 import sun.management.snmp.jvmmib.JvmThreadInstanceEntryMBean;
47 import sun.management.snmp.jvmmib.JVM_MANAGEMENT_MIBOidTable;
48 import sun.management.snmp.util.MibLogger;
49 
50 /**
51  * The class is used for implementing the "JvmThreadInstanceEntry" group.
52  */
53 public class JvmThreadInstanceEntryImpl
54     implements JvmThreadInstanceEntryMBean, Serializable {
55 
56     static final long serialVersionUID = 910173589985461347L;
57 
58     public final static class ThreadStateMap {
59         public final static class Byte0 {
60             public final static byte inNative     = (byte)0x80; // bit 1
61             public final static byte suspended    = (byte)0x40; // bit 2
62             public final static byte newThread    = (byte)0x20; // bit 3
63             public final static byte runnable     = (byte)0x10; // bit 4
64             public final static byte blocked      = (byte)0x08; // bit 5
65             public final static byte terminated   = (byte)0x04; // bit 6
66             public final static byte waiting      = (byte)0x02; // bit 7
67             public final static byte timedWaiting = (byte)0x01; // bit 8
68         }
69         public final static class Byte1 {
70             public final static byte other        = (byte)0x80; // bit 9
71             public final static byte reserved10   = (byte)0x40; // bit 10
72             public final static byte reserved11   = (byte)0x20; // bit 11
73             public final static byte reserved12   = (byte)0x10; // bit 12
74             public final static byte reserved13   = (byte)0x08; // bit 13
75             public final static byte reserved14   = (byte)0x04; // bit 14
76             public final static byte reserved15   = (byte)0x02; // bit 15
77             public final static byte reserved16   = (byte)0x01; // bit 16
78         }
79 
80         public final static byte mask0 = (byte)0x3F;
81         public final static byte mask1 = (byte)0x80;
82 
setBit(byte[] bitmap, int index, byte state)83         private static void setBit(byte[] bitmap, int index, byte state) {
84             bitmap[index] = (byte) (bitmap[index] | state);
85         }
setNative(byte[] bitmap)86         public static void setNative(byte[] bitmap) {
87             setBit(bitmap,0,Byte0.inNative);
88         }
setSuspended(byte[] bitmap)89         public static void setSuspended(byte[] bitmap) {
90             setBit(bitmap,0,Byte0.suspended);
91         }
setState(byte[] bitmap, Thread.State state)92         public static void setState(byte[] bitmap, Thread.State state) {
93             switch(state) {
94             case BLOCKED:
95                 setBit(bitmap,0,Byte0.blocked);
96                 return;
97             case NEW:
98                 setBit(bitmap,0,Byte0.newThread);
99                 return;
100             case RUNNABLE:
101                 setBit(bitmap,0,Byte0.runnable);
102                 return;
103             case TERMINATED:
104                 setBit(bitmap,0,Byte0.terminated);
105                 return;
106             case TIMED_WAITING:
107                 setBit(bitmap,0,Byte0.timedWaiting);
108                 return;
109             case WAITING:
110                 setBit(bitmap,0,Byte0.waiting);
111                 return;
112             }
113         }
114 
checkOther(byte[] bitmap)115         public static void checkOther(byte[] bitmap) {
116             if (((bitmap[0]&mask0)==(byte)0x00) &&
117                 ((bitmap[1]&mask1)==(byte)0x00))
118                 setBit(bitmap,1,Byte1.other);
119         }
120 
getState(ThreadInfo info)121         public static Byte[] getState(ThreadInfo info) {
122             byte[] bitmap = new byte[] {(byte)0x00, (byte)0x00};
123             try {
124                 final Thread.State state = info.getThreadState();
125                 final boolean inNative  = info.isInNative();
126                 final boolean suspended = info.isSuspended();
127                 log.debug("getJvmThreadInstState",
128                           "[State=" + state +
129                           ",isInNative=" + inNative +
130                           ",isSuspended=" + suspended + "]");
131                 setState(bitmap,state);
132                 if (inNative)  setNative(bitmap);
133                 if (suspended) setSuspended(bitmap);
134                 checkOther(bitmap);
135             } catch (RuntimeException r) {
136                 bitmap[0]=(byte)0x00;
137                 bitmap[1]=Byte1.other;
138                 log.trace("getJvmThreadInstState",
139                           "Unexpected exception: " + r);
140                 log.debug("getJvmThreadInstState",r);
141             }
142             Byte[] result = { new Byte(bitmap[0]), new Byte(bitmap[1]) };
143             return result;
144         }
145     }
146 
147     private final ThreadInfo info;
148     private final Byte[] index;
149 
150     /**
151      * Constructor for the "JvmThreadInstanceEntry" group.
152      */
JvmThreadInstanceEntryImpl(ThreadInfo info, Byte[] index)153     public JvmThreadInstanceEntryImpl(ThreadInfo info,
154                                       Byte[] index) {
155         this.info = info;
156         this.index = index;
157     }
158 
159 
160     private static String  jvmThreadInstIndexOid = null;
getJvmThreadInstIndexOid()161     public static String getJvmThreadInstIndexOid()
162         throws SnmpStatusException {
163         if (jvmThreadInstIndexOid == null) {
164             final SnmpOidTable  table = new JVM_MANAGEMENT_MIBOidTable();
165             final SnmpOidRecord record =
166                 table.resolveVarName("jvmThreadInstIndex");
167             jvmThreadInstIndexOid = record.getOid();
168         }
169         return jvmThreadInstIndexOid;
170     }
171 
172 
173 
174     /**
175      * Getter for the "JvmThreadInstLockedOwnerId" variable.
176      */
getJvmThreadInstLockOwnerPtr()177     public String getJvmThreadInstLockOwnerPtr() throws SnmpStatusException {
178        long id = info.getLockOwnerId();
179 
180        if(id == -1)
181            return new String("0.0");
182 
183        SnmpOid oid = JvmThreadInstanceTableMetaImpl.makeOid(id);
184 
185        return getJvmThreadInstIndexOid() + "." + oid.toString();
186     }
187 
validDisplayStringTC(String str)188     private String validDisplayStringTC(String str) {
189         return JVM_MANAGEMENT_MIB_IMPL.validDisplayStringTC(str);
190     }
191 
validJavaObjectNameTC(String str)192     private String validJavaObjectNameTC(String str) {
193         return JVM_MANAGEMENT_MIB_IMPL.validJavaObjectNameTC(str);
194     }
195 
validPathElementTC(String str)196     private String validPathElementTC(String str) {
197         return JVM_MANAGEMENT_MIB_IMPL.validPathElementTC(str);
198     }
199 
200     /**
201      * Getter for the "JvmThreadInstLockName" variable.
202      */
getJvmThreadInstLockName()203     public String getJvmThreadInstLockName() throws SnmpStatusException {
204         return validJavaObjectNameTC(info.getLockName());
205     }
206 
207     /**
208      * Getter for the "JvmThreadInstName" variable.
209      */
getJvmThreadInstName()210     public String getJvmThreadInstName() throws SnmpStatusException {
211         return validJavaObjectNameTC(info.getThreadName());
212     }
213 
214     /**
215      * Getter for the "JvmThreadInstCpuTimeNs" variable.
216      */
getJvmThreadInstCpuTimeNs()217     public Long getJvmThreadInstCpuTimeNs() throws SnmpStatusException {
218         long l = 0;
219         final ThreadMXBean tmb = JvmThreadingImpl.getThreadMXBean();
220 
221         try {
222             if (tmb.isThreadCpuTimeSupported()) {
223                 l = tmb.getThreadCpuTime(info.getThreadId());
224                 log.debug("getJvmThreadInstCpuTimeNs", "Cpu time ns : " + l);
225 
226                 //Cpu time measurement is disabled or the id is not valid.
227                 if(l == -1) l = 0;
228             }
229         } catch (UnsatisfiedLinkError e) {
230             // XXX Revisit: catch TO BE EVENTUALLY REMOVED
231             log.debug("getJvmThreadInstCpuTimeNs",
232                       "Operation not supported: " + e);
233         }
234         return new Long(l);
235     }
236 
237     /**
238      * Getter for the "JvmThreadInstBlockTimeMs" variable.
239      */
getJvmThreadInstBlockTimeMs()240     public Long getJvmThreadInstBlockTimeMs() throws SnmpStatusException {
241         long l = 0;
242 
243         final ThreadMXBean tmb = JvmThreadingImpl.getThreadMXBean();
244 
245         if (tmb.isThreadContentionMonitoringSupported()) {
246             l = info.getBlockedTime();
247 
248             //Monitoring is disabled
249             if(l == -1) l = 0;
250         }
251         return new Long(l);
252     }
253 
254     /**
255      * Getter for the "JvmThreadInstBlockCount" variable.
256      */
getJvmThreadInstBlockCount()257     public Long getJvmThreadInstBlockCount() throws SnmpStatusException {
258         return new Long(info.getBlockedCount());
259     }
260 
261     /**
262      * Getter for the "JvmThreadInstWaitTimeMs" variable.
263      */
getJvmThreadInstWaitTimeMs()264     public Long getJvmThreadInstWaitTimeMs() throws SnmpStatusException {
265         long l = 0;
266 
267         final ThreadMXBean tmb = JvmThreadingImpl.getThreadMXBean();
268 
269         if (tmb.isThreadContentionMonitoringSupported()) {
270             l = info.getWaitedTime();
271 
272             //Monitoring is disabled
273             if(l == -1) l = 0;
274         }
275         return new Long(l);
276     }
277 
278     /**
279      * Getter for the "JvmThreadInstWaitCount" variable.
280      */
getJvmThreadInstWaitCount()281     public Long getJvmThreadInstWaitCount() throws SnmpStatusException {
282         return new Long(info.getWaitedCount());
283     }
284 
285     /**
286      * Getter for the "JvmThreadInstState" variable.
287      */
getJvmThreadInstState()288     public Byte[] getJvmThreadInstState()
289         throws SnmpStatusException {
290         return ThreadStateMap.getState(info);
291     }
292 
293     /**
294      * Getter for the "JvmThreadInstId" variable.
295      */
getJvmThreadInstId()296     public Long getJvmThreadInstId() throws SnmpStatusException {
297         return new Long(info.getThreadId());
298     }
299 
300     /**
301      * Getter for the "JvmThreadInstIndex" variable.
302      */
getJvmThreadInstIndex()303     public Byte[] getJvmThreadInstIndex() throws SnmpStatusException {
304         return index;
305     }
306 
307     /**
308      * Getter for the "JvmThreadInstStackTrace" variable.
309      */
getJvmThreadInstStackTrace()310     private String getJvmThreadInstStackTrace() throws SnmpStatusException {
311         StackTraceElement[] stackTrace = info.getStackTrace();
312         //We append the stack trace in a buffer
313         // XXX Revisit: should check isDebugOn()
314         StringBuffer b = new StringBuffer();
315         final int stackSize = stackTrace.length;
316         log.debug("getJvmThreadInstStackTrace", "Stack size : " + stackSize);
317         for(int i = 0; i < stackSize; i++) {
318             log.debug("getJvmThreadInstStackTrace", "Append " +
319                       stackTrace[i].toString());
320             b.append(stackTrace[i].toString());
321             //Append \n at the end of each line except the last one
322             if(i < stackSize)
323                 b.append("\n");
324         }
325         //The stack trace is truncated if its size exceeds 255.
326         return validPathElementTC(b.toString());
327     }
328     static final MibLogger log =
329         new MibLogger(JvmThreadInstanceEntryImpl.class);
330 }
331