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 
  83         private static void setBit(byte[] bitmap, int index, byte state) {
  84             bitmap[index] = (byte) (bitmap[index] | state);
  85         }
  86         public static void setNative(byte[] bitmap) {
  87             setBit(bitmap,0,Byte0.inNative);
  88         }
  89         public static void setSuspended(byte[] bitmap) {
  90             setBit(bitmap,0,Byte0.suspended);
  91         }
  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 
 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 
 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 = {bitmap[0], 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      */
 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;
 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      */
 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 
 188     private String validDisplayStringTC(String str) {
 189         return JVM_MANAGEMENT_MIB_IMPL.validDisplayStringTC(str);
 190     }
 191 
 192     private String validJavaObjectNameTC(String str) {
 193         return JVM_MANAGEMENT_MIB_IMPL.validJavaObjectNameTC(str);
 194     }
 195 
 196     private String validPathElementTC(String str) {
 197         return JVM_MANAGEMENT_MIB_IMPL.validPathElementTC(str);
 198     }
 199 
 200     /**
 201      * Getter for the "JvmThreadInstLockName" variable.
 202      */
 203     public String getJvmThreadInstLockName() throws SnmpStatusException {
 204         return validJavaObjectNameTC(info.getLockName());
 205     }
 206 
 207     /**
 208      * Getter for the "JvmThreadInstName" variable.
 209      */
 210     public String getJvmThreadInstName() throws SnmpStatusException {
 211         return validJavaObjectNameTC(info.getThreadName());
 212     }
 213 
 214     /**
 215      * Getter for the "JvmThreadInstCpuTimeNs" variable.
 216      */
 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 l;
 235     }
 236 
 237     /**
 238      * Getter for the "JvmThreadInstBlockTimeMs" variable.
 239      */
 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 l;
 252     }
 253 
 254     /**
 255      * Getter for the "JvmThreadInstBlockCount" variable.
 256      */
 257     public Long getJvmThreadInstBlockCount() throws SnmpStatusException {
 258         return info.getBlockedCount();
 259     }
 260 
 261     /**
 262      * Getter for the "JvmThreadInstWaitTimeMs" variable.
 263      */
 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 l;
 276     }
 277 
 278     /**
 279      * Getter for the "JvmThreadInstWaitCount" variable.
 280      */
 281     public Long getJvmThreadInstWaitCount() throws SnmpStatusException {
 282         return info.getWaitedCount();
 283     }
 284 
 285     /**
 286      * Getter for the "JvmThreadInstState" variable.
 287      */
 288     public Byte[] getJvmThreadInstState()
 289         throws SnmpStatusException {
 290         return ThreadStateMap.getState(info);
 291     }
 292 
 293     /**
 294      * Getter for the "JvmThreadInstId" variable.
 295      */
 296     public Long getJvmThreadInstId() throws SnmpStatusException {
 297         return info.getThreadId();
 298     }
 299 
 300     /**
 301      * Getter for the "JvmThreadInstIndex" variable.
 302      */
 303     public Byte[] getJvmThreadInstIndex() throws SnmpStatusException {
 304         return index;
 305     }
 306 
 307     /**
 308      * Getter for the "JvmThreadInstStackTrace" variable.
 309      */
 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         StringBuilder sb = new StringBuilder();
 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             sb.append(stackTrace[i].toString());
 321             //Append \n at the end of each line except the last one
 322             if(i < stackSize)
 323                 sb.append("\n");
 324         }
 325         //The stack trace is truncated if its size exceeds 255.
 326         return validPathElementTC(sb.toString());
 327     }
 328     static final MibLogger log =
 329         new MibLogger(JvmThreadInstanceEntryImpl.class);
 330 }