1fb3fb4f3Stomee /* 2fb3fb4f3Stomee * CDDL HEADER START 3fb3fb4f3Stomee * 4fb3fb4f3Stomee * The contents of this file are subject to the terms of the 5fb3fb4f3Stomee * Common Development and Distribution License (the "License"). 6fb3fb4f3Stomee * You may not use this file except in compliance with the License. 7fb3fb4f3Stomee * 8fb3fb4f3Stomee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fb3fb4f3Stomee * or http://www.opensolaris.org/os/licensing. 10fb3fb4f3Stomee * See the License for the specific language governing permissions 11fb3fb4f3Stomee * and limitations under the License. 12fb3fb4f3Stomee * 13fb3fb4f3Stomee * When distributing Covered Code, include this CDDL HEADER in each 14fb3fb4f3Stomee * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fb3fb4f3Stomee * If applicable, add the following below this CDDL HEADER, with the 16fb3fb4f3Stomee * fields enclosed by brackets "[]" replaced with your own identifying 17fb3fb4f3Stomee * information: Portions Copyright [yyyy] [name of copyright owner] 18fb3fb4f3Stomee * 19fb3fb4f3Stomee * CDDL HEADER END 20fb3fb4f3Stomee */ 21fb3fb4f3Stomee 22fb3fb4f3Stomee /* 2391cfa10aStomee * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24fb3fb4f3Stomee * Use is subject to license terms. 25fb3fb4f3Stomee * 26fb3fb4f3Stomee * ident "%Z%%M% %I% %E% SMI" 27fb3fb4f3Stomee */ 28fb3fb4f3Stomee package org.opensolaris.os.dtrace; 29fb3fb4f3Stomee 30fb3fb4f3Stomee import java.io.*; 31fb3fb4f3Stomee import java.beans.*; 32fb3fb4f3Stomee 33fb3fb4f3Stomee /** 34fb3fb4f3Stomee * State of a target process designated by {@link 35fb3fb4f3Stomee * Consumer#createProcess(String command)} or {@link 36fb3fb4f3Stomee * Consumer#grabProcess(int pid)}. 37fb3fb4f3Stomee * <p> 38fb3fb4f3Stomee * Immutable. Supports persistence using {@link java.beans.XMLEncoder}. 39fb3fb4f3Stomee * 40fb3fb4f3Stomee * @see ConsumerListener#processStateChanged(ProcessEvent e) 41fb3fb4f3Stomee * 42fb3fb4f3Stomee * @author Tom Erickson 43fb3fb4f3Stomee */ 44fb3fb4f3Stomee public final class ProcessState implements Serializable { 45fb3fb4f3Stomee static final long serialVersionUID = -3395911213431317292L; 46fb3fb4f3Stomee 47fb3fb4f3Stomee static { 48fb3fb4f3Stomee try { 49fb3fb4f3Stomee BeanInfo info = Introspector.getBeanInfo(ProcessState.class); 50fb3fb4f3Stomee PersistenceDelegate persistenceDelegate = 51fb3fb4f3Stomee new DefaultPersistenceDelegate( 52fb3fb4f3Stomee new String[] {"processID", "state", 53fb3fb4f3Stomee "terminationSignal", "terminationSignalName", 54fb3fb4f3Stomee "exitStatus", "message"}) 55fb3fb4f3Stomee { 56fb3fb4f3Stomee /* 57fb3fb4f3Stomee * Need to prevent DefaultPersistenceDelegate from using 58fb3fb4f3Stomee * overridden equals() method, resulting in a 59fb3fb4f3Stomee * StackOverFlowError. Revert to PersistenceDelegate 60fb3fb4f3Stomee * implementation. See 61fb3fb4f3Stomee * http://forum.java.sun.com/thread.jspa?threadID= 62fb3fb4f3Stomee * 477019&tstart=135 63fb3fb4f3Stomee */ 64fb3fb4f3Stomee protected boolean 65fb3fb4f3Stomee mutatesTo(Object oldInstance, Object newInstance) 66fb3fb4f3Stomee { 67fb3fb4f3Stomee return (newInstance != null && oldInstance != null && 68fb3fb4f3Stomee oldInstance.getClass() == newInstance.getClass()); 69fb3fb4f3Stomee } 70fb3fb4f3Stomee 71fb3fb4f3Stomee protected Expression 72fb3fb4f3Stomee instantiate(Object oldInstance, Encoder out) 73fb3fb4f3Stomee { 74fb3fb4f3Stomee ProcessState pstate = (ProcessState)oldInstance; 75fb3fb4f3Stomee return new Expression(oldInstance, oldInstance.getClass(), 76fb3fb4f3Stomee "new", new Object[] { pstate.getProcessID(), 77fb3fb4f3Stomee pstate.getState().name(), 78fb3fb4f3Stomee pstate.getTerminationSignal(), 79fb3fb4f3Stomee pstate.getTerminationSignalName(), 80fb3fb4f3Stomee pstate.getExitStatus(), 81fb3fb4f3Stomee pstate.getMessage() }); 82fb3fb4f3Stomee } 83fb3fb4f3Stomee }; 84fb3fb4f3Stomee BeanDescriptor d = info.getBeanDescriptor(); 85fb3fb4f3Stomee d.setValue("persistenceDelegate", persistenceDelegate); 86fb3fb4f3Stomee } catch (IntrospectionException e) { 87fb3fb4f3Stomee System.out.println(e); 88fb3fb4f3Stomee } 89fb3fb4f3Stomee } 90fb3fb4f3Stomee 91fb3fb4f3Stomee /** 92fb3fb4f3Stomee * State of a target process. 93fb3fb4f3Stomee */ 94fb3fb4f3Stomee public enum State { 95fb3fb4f3Stomee /** Process is running. */ 96fb3fb4f3Stomee RUN, 97fb3fb4f3Stomee /** Process is stopped. */ 98fb3fb4f3Stomee STOP, 99fb3fb4f3Stomee /** Process is lost to control. */ 100fb3fb4f3Stomee LOST, 101fb3fb4f3Stomee /** Process is terminated (zombie). */ 102fb3fb4f3Stomee UNDEAD, 103fb3fb4f3Stomee /** Process is terminated (core file). */ 104fb3fb4f3Stomee DEAD 105fb3fb4f3Stomee } 106fb3fb4f3Stomee 107fb3fb4f3Stomee /** @serial */ 108fb3fb4f3Stomee private int processID; 109fb3fb4f3Stomee /** @serial */ 110fb3fb4f3Stomee private State state; 111fb3fb4f3Stomee /** @serial */ 112fb3fb4f3Stomee private int terminationSignal; 113fb3fb4f3Stomee /** @serial */ 114fb3fb4f3Stomee private String terminationSignalName; 115fb3fb4f3Stomee /** @serial */ 116fb3fb4f3Stomee private Integer exitStatus; 117fb3fb4f3Stomee /** @serial */ 118fb3fb4f3Stomee private String message; 119fb3fb4f3Stomee 120fb3fb4f3Stomee /** 121fb3fb4f3Stomee * Creates a {@code ProcessState} instance with the given state. 122fb3fb4f3Stomee * 123fb3fb4f3Stomee * @param pid non-negative target process ID 124fb3fb4f3Stomee * @param processState target process state 125fb3fb4f3Stomee * @param processTerminationSignal signal that terminated the target 126fb3fb4f3Stomee * process, {@code -1} if the process was not terminated by a signal 127fb3fb4f3Stomee * or if the terminating signal is unknown 128fb3fb4f3Stomee * @param processTerminationSignalName name of the signal that 129fb3fb4f3Stomee * terminated the target process, {@code null} if the process was 130fb3fb4f3Stomee * not terminated by a signal or if the terminating signal is 131fb3fb4f3Stomee * unknown 132fb3fb4f3Stomee * @param processExitStatus target process exit status, {@code null} 133fb3fb4f3Stomee * if the process has not exited or the exit status is unknown 134fb3fb4f3Stomee * @param msg message included by DTrace, if any 135fb3fb4f3Stomee * @throws NullPointerException if the given process state is {@code 136fb3fb4f3Stomee * null} 137fb3fb4f3Stomee * @throws IllegalArgumentException if the given process ID is negative 138fb3fb4f3Stomee */ 139fb3fb4f3Stomee public ProcessState(int pid, State processState, int processTerminationSignal, String processTerminationSignalName, Integer processExitStatus, String msg)140fb3fb4f3Stomee ProcessState(int pid, State processState, 141fb3fb4f3Stomee int processTerminationSignal, 142fb3fb4f3Stomee String processTerminationSignalName, 143fb3fb4f3Stomee Integer processExitStatus, String msg) 144fb3fb4f3Stomee { 145fb3fb4f3Stomee processID = pid; 146fb3fb4f3Stomee state = processState; 147fb3fb4f3Stomee terminationSignal = processTerminationSignal; 148fb3fb4f3Stomee terminationSignalName = processTerminationSignalName; 149fb3fb4f3Stomee exitStatus = processExitStatus; 150fb3fb4f3Stomee message = msg; 151fb3fb4f3Stomee validate(); 152fb3fb4f3Stomee } 153fb3fb4f3Stomee 154fb3fb4f3Stomee /** 155fb3fb4f3Stomee * Supports XML persistence. 156fb3fb4f3Stomee * 157fb3fb4f3Stomee * @see #ProcessState(int pid, State processState, int 158fb3fb4f3Stomee * processTerminationSignal, String processTerminationSignalName, 159fb3fb4f3Stomee * Integer processExitStatus, String msg) 160fb3fb4f3Stomee * @throws IllegalArgumentException if there is no {@link 161fb3fb4f3Stomee * ProcessState.State} value with the given state name. 162fb3fb4f3Stomee */ 163fb3fb4f3Stomee public ProcessState(int pid, String processStateName, int processTerminationSignal, String processTerminationSignalName, Integer processExitStatus, String msg)164fb3fb4f3Stomee ProcessState(int pid, String processStateName, 165fb3fb4f3Stomee int processTerminationSignal, 166fb3fb4f3Stomee String processTerminationSignalName, 167fb3fb4f3Stomee Integer processExitStatus, String msg) 168fb3fb4f3Stomee { 169fb3fb4f3Stomee processID = pid; 170fb3fb4f3Stomee state = Enum.valueOf(State.class, processStateName); 171fb3fb4f3Stomee terminationSignal = processTerminationSignal; 172fb3fb4f3Stomee terminationSignalName = processTerminationSignalName; 173fb3fb4f3Stomee exitStatus = processExitStatus; 174fb3fb4f3Stomee message = msg; 175fb3fb4f3Stomee validate(); 176fb3fb4f3Stomee } 177fb3fb4f3Stomee 17891cfa10aStomee private final void validate()179fb3fb4f3Stomee validate() 180fb3fb4f3Stomee { 181fb3fb4f3Stomee if (processID < 0) { 182fb3fb4f3Stomee throw new IllegalArgumentException("pid is negative"); 183fb3fb4f3Stomee } 184fb3fb4f3Stomee if (state == null) { 185fb3fb4f3Stomee throw new NullPointerException("process state is null"); 186fb3fb4f3Stomee } 187fb3fb4f3Stomee } 188fb3fb4f3Stomee 189fb3fb4f3Stomee /** 190fb3fb4f3Stomee * Gets the process ID. 191fb3fb4f3Stomee * 192fb3fb4f3Stomee * @return non-negative target process ID 193fb3fb4f3Stomee */ 194fb3fb4f3Stomee public int getProcessID()195fb3fb4f3Stomee getProcessID() 196fb3fb4f3Stomee { 197fb3fb4f3Stomee return processID; 198fb3fb4f3Stomee } 199fb3fb4f3Stomee 200fb3fb4f3Stomee /** 201fb3fb4f3Stomee * Gets the process state. 202fb3fb4f3Stomee * 203fb3fb4f3Stomee * @return non-null target process state 204fb3fb4f3Stomee */ 205fb3fb4f3Stomee public State getState()206fb3fb4f3Stomee getState() 207fb3fb4f3Stomee { 208fb3fb4f3Stomee return state; 209fb3fb4f3Stomee } 210fb3fb4f3Stomee 211fb3fb4f3Stomee /** 212fb3fb4f3Stomee * Gets the signal that terminated the process. 213fb3fb4f3Stomee * 214fb3fb4f3Stomee * @return termination signal, {@code -1} if the process was not 215fb3fb4f3Stomee * terminated by a signal or if the terminating signal is unknown 216fb3fb4f3Stomee */ 217fb3fb4f3Stomee public int getTerminationSignal()218fb3fb4f3Stomee getTerminationSignal() 219fb3fb4f3Stomee { 220fb3fb4f3Stomee return terminationSignal; 221fb3fb4f3Stomee } 222fb3fb4f3Stomee 223fb3fb4f3Stomee /** 224fb3fb4f3Stomee * Gets the name of the signal that terminated the process. 225fb3fb4f3Stomee * 226fb3fb4f3Stomee * @return termination signal name, {@code null} if the process was 227fb3fb4f3Stomee * not terminated by a signal or if the terminating signal is 228fb3fb4f3Stomee * unknown 229fb3fb4f3Stomee */ 230fb3fb4f3Stomee public String getTerminationSignalName()231fb3fb4f3Stomee getTerminationSignalName() 232fb3fb4f3Stomee { 233fb3fb4f3Stomee return terminationSignalName; 234fb3fb4f3Stomee } 235fb3fb4f3Stomee 236fb3fb4f3Stomee /** 237fb3fb4f3Stomee * Gets the process exit status. 238fb3fb4f3Stomee * 239fb3fb4f3Stomee * @return exit status, or {@code null} if the process has not 240fb3fb4f3Stomee * exited or the exit status is unknown 241fb3fb4f3Stomee */ 242fb3fb4f3Stomee public Integer getExitStatus()243fb3fb4f3Stomee getExitStatus() 244fb3fb4f3Stomee { 245fb3fb4f3Stomee return exitStatus; 246fb3fb4f3Stomee } 247fb3fb4f3Stomee 248fb3fb4f3Stomee /** 249fb3fb4f3Stomee * Called by native code. 250fb3fb4f3Stomee */ 251fb3fb4f3Stomee private void setExitStatus(int status)252fb3fb4f3Stomee setExitStatus(int status) 253fb3fb4f3Stomee { 254fb3fb4f3Stomee exitStatus = new Integer(status); 255fb3fb4f3Stomee } 256fb3fb4f3Stomee 257fb3fb4f3Stomee /** 258fb3fb4f3Stomee * Gets the message from DTrace describing this process state. 259fb3fb4f3Stomee * 260fb3fb4f3Stomee * @return DTrace message, or {@code null} if DTrace did not include 261fb3fb4f3Stomee * a message with this process state 262fb3fb4f3Stomee */ 263fb3fb4f3Stomee public String getMessage()264fb3fb4f3Stomee getMessage() 265fb3fb4f3Stomee { 266fb3fb4f3Stomee return message; 267fb3fb4f3Stomee } 268fb3fb4f3Stomee 269fb3fb4f3Stomee /** 270fb3fb4f3Stomee * Compares the specified object with this {@code ProcessState} 271fb3fb4f3Stomee * instance for equality. Defines equality as having the same 272fb3fb4f3Stomee * attributes. 273fb3fb4f3Stomee * 274fb3fb4f3Stomee * @return {@code true} if and only if the specified object is also 275fb3fb4f3Stomee * a {@code ProcessState} and both instances have the same 276fb3fb4f3Stomee * attributes 277fb3fb4f3Stomee */ 278fb3fb4f3Stomee @Override 279fb3fb4f3Stomee public boolean equals(Object o)280fb3fb4f3Stomee equals(Object o) 281fb3fb4f3Stomee { 282fb3fb4f3Stomee if (o instanceof ProcessState) { 283fb3fb4f3Stomee ProcessState s = (ProcessState)o; 284fb3fb4f3Stomee return ((processID == s.processID) && 285fb3fb4f3Stomee (state == s.state) && 286fb3fb4f3Stomee (terminationSignal == s.terminationSignal) && 287fb3fb4f3Stomee ((terminationSignalName == null) ? 288fb3fb4f3Stomee (s.terminationSignalName == null) : 289fb3fb4f3Stomee terminationSignalName.equals(s.terminationSignalName)) && 290fb3fb4f3Stomee ((exitStatus == null) ? 291fb3fb4f3Stomee (s.exitStatus == null) : 292fb3fb4f3Stomee exitStatus.equals(s.exitStatus)) && 293fb3fb4f3Stomee ((message == null) ? (s.message == null) : 294fb3fb4f3Stomee message.equals(s.message))); 295fb3fb4f3Stomee } 296fb3fb4f3Stomee return false; 297fb3fb4f3Stomee } 298fb3fb4f3Stomee 299fb3fb4f3Stomee /** 300fb3fb4f3Stomee * Overridden to ensure that equal instances have equal hash codes. 301fb3fb4f3Stomee */ 302fb3fb4f3Stomee @Override 303fb3fb4f3Stomee public int hashCode()304fb3fb4f3Stomee hashCode() 305fb3fb4f3Stomee { 306fb3fb4f3Stomee int hash = 17; 307fb3fb4f3Stomee hash = (37 * hash) + processID; 308fb3fb4f3Stomee hash = (37 * hash) + state.hashCode(); 309fb3fb4f3Stomee hash = (37 * hash) + terminationSignal; 310fb3fb4f3Stomee hash = (37 * hash) + (exitStatus == null ? 0 : 311fb3fb4f3Stomee exitStatus.hashCode()); 312fb3fb4f3Stomee hash = (37 * hash) + (message == null ? 0 : message.hashCode()); 313fb3fb4f3Stomee return hash; 314fb3fb4f3Stomee } 315fb3fb4f3Stomee 316fb3fb4f3Stomee private void readObject(ObjectInputStream s)317fb3fb4f3Stomee readObject(ObjectInputStream s) 318fb3fb4f3Stomee throws IOException, ClassNotFoundException 319fb3fb4f3Stomee { 320fb3fb4f3Stomee s.defaultReadObject(); 321fb3fb4f3Stomee // check class invariants 322fb3fb4f3Stomee try { 323fb3fb4f3Stomee validate(); 324fb3fb4f3Stomee } catch (Exception e) { 325*4ae67516Stomee InvalidObjectException x = new InvalidObjectException( 326*4ae67516Stomee e.getMessage()); 327*4ae67516Stomee x.initCause(e); 328*4ae67516Stomee throw x; 329fb3fb4f3Stomee } 330fb3fb4f3Stomee } 331fb3fb4f3Stomee 332fb3fb4f3Stomee /** 333fb3fb4f3Stomee * Gets a string representation of this process state useful for 334fb3fb4f3Stomee * logging and not intended for display. The exact details of the 335fb3fb4f3Stomee * representation are unspecified and subject to change, but the 336fb3fb4f3Stomee * following format may be regarded as typical: 337fb3fb4f3Stomee * <pre><code> 338fb3fb4f3Stomee * class-name[property1 = value1, property2 = value2] 339fb3fb4f3Stomee * </code></pre> 340fb3fb4f3Stomee */ 341fb3fb4f3Stomee public String toString()342fb3fb4f3Stomee toString() 343fb3fb4f3Stomee { 344*4ae67516Stomee StringBuilder buf = new StringBuilder(); 345fb3fb4f3Stomee buf.append(ProcessState.class.getName()); 346fb3fb4f3Stomee buf.append("[pid = "); 347fb3fb4f3Stomee buf.append(processID); 348fb3fb4f3Stomee buf.append(", state = "); 349fb3fb4f3Stomee buf.append(state); 350fb3fb4f3Stomee buf.append(", terminationSignal = "); 351fb3fb4f3Stomee buf.append(terminationSignal); 352fb3fb4f3Stomee buf.append(", terminationSignalName = "); 353fb3fb4f3Stomee buf.append(terminationSignalName); 354fb3fb4f3Stomee buf.append(", exitStatus = "); 355fb3fb4f3Stomee buf.append(exitStatus); 356fb3fb4f3Stomee buf.append(", message = "); 357fb3fb4f3Stomee buf.append(message); 358fb3fb4f3Stomee buf.append(']'); 359fb3fb4f3Stomee return buf.toString(); 360fb3fb4f3Stomee } 361fb3fb4f3Stomee } 362