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 /* 23e77b06d2Stomee * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24fb3fb4f3Stomee * Use is subject to license terms. 25fb3fb4f3Stomee */ 26fb3fb4f3Stomee package org.opensolaris.os.dtrace; 27fb3fb4f3Stomee 28fb3fb4f3Stomee import java.io.*; 29fb3fb4f3Stomee import java.util.*; 30fb3fb4f3Stomee import java.net.InetAddress; 31fb3fb4f3Stomee import java.net.UnknownHostException; 32fb3fb4f3Stomee import javax.swing.event.EventListenerList; 33fb3fb4f3Stomee import java.util.logging.*; 34fb3fb4f3Stomee 35fb3fb4f3Stomee /** 36fb3fb4f3Stomee * Interface to the native DTrace library, each instance is a single 37fb3fb4f3Stomee * DTrace consumer. 38fb3fb4f3Stomee * 39fb3fb4f3Stomee * @author Tom Erickson 40fb3fb4f3Stomee */ 41fb3fb4f3Stomee public class LocalConsumer implements Consumer { 42fb3fb4f3Stomee // 43fb3fb4f3Stomee // Implementation notes: 44fb3fb4f3Stomee // 45fb3fb4f3Stomee // libdtrace is *not* thread-safe. You cannot make multiple calls 46fb3fb4f3Stomee // into it simultaneously from different threads, even if those 47fb3fb4f3Stomee // threads are operating on different dtrace_hdl_t's. Calls to 48fb3fb4f3Stomee // libdtrace are synchronized on a global lock, LocalConsumer.class. 49fb3fb4f3Stomee 50fb3fb4f3Stomee static Logger logger = Logger.getLogger(LocalConsumer.class.getName()); 51fb3fb4f3Stomee 524ae67516Stomee // Needs to match the version in dtrace_jni.c 53e77b06d2Stomee private static final int DTRACE_JNI_VERSION = 3; 54fb3fb4f3Stomee 55fb3fb4f3Stomee private static final Option[] DEFAULT_OPTIONS = new Option[] { 56fb3fb4f3Stomee new Option(Option.bufsize, Option.kb(256)), 57fb3fb4f3Stomee new Option(Option.aggsize, Option.kb(256)), 58fb3fb4f3Stomee }; 59fb3fb4f3Stomee _loadJniTable()60fb3fb4f3Stomee private static native void _loadJniTable(); 61fb3fb4f3Stomee 6252aacb45Stomee // Undocumented configuration options 63fb3fb4f3Stomee private static boolean debug; 64fb3fb4f3Stomee private static int maxConsumers; 65fb3fb4f3Stomee 66fb3fb4f3Stomee static { LocalConsumer.configureLogging()6752aacb45Stomee LocalConsumer.configureLogging(); 6852aacb45Stomee // Undocumented configuration options settable using 6952aacb45Stomee // java -Doption=value LocalConsumer.getConfigurationOptions()7052aacb45Stomee LocalConsumer.getConfigurationOptions(); 71fb3fb4f3Stomee 72fb3fb4f3Stomee Utility.loadLibrary("libdtrace_jni.so.1", debug); 73fb3fb4f3Stomee 74fb3fb4f3Stomee _checkVersion(DTRACE_JNI_VERSION); 7552aacb45Stomee _setDebug(debug); 76fb3fb4f3Stomee if (maxConsumers > 0) { 77fb3fb4f3Stomee _setMaximumConsumers(maxConsumers); 78fb3fb4f3Stomee } 79fb3fb4f3Stomee 80fb3fb4f3Stomee // 81fb3fb4f3Stomee // Last of all in case configuration options affect the loading 82fb3fb4f3Stomee // of the JNI table. 83fb3fb4f3Stomee // _loadJniTable()84fb3fb4f3Stomee _loadJniTable(); 85fb3fb4f3Stomee } 86fb3fb4f3Stomee 87fb3fb4f3Stomee // Native JNI interface (see lib/libdtrace_jni/dtrace_jni.c) _checkVersion(int version)88fb3fb4f3Stomee private static native void _checkVersion(int version); _open(OpenFlag[] flags)89fb3fb4f3Stomee private native void _open(OpenFlag[] flags) throws DTraceException; _compileString(String program, String[] args)90fb3fb4f3Stomee private native Program _compileString(String program, String[] args) 91fb3fb4f3Stomee throws DTraceException; _compileFile(String path, String[] args)92fb3fb4f3Stomee private native Program.File _compileFile(String path, String[] args) 93fb3fb4f3Stomee throws DTraceException; _exec(Program program)94fb3fb4f3Stomee private native void _exec(Program program) throws DTraceException; _getProgramInfo(Program program)95fb3fb4f3Stomee private native void _getProgramInfo(Program program) 96fb3fb4f3Stomee throws DTraceException; _setOption(String option, String value)97fb3fb4f3Stomee private native void _setOption(String option, String value) 98fb3fb4f3Stomee throws DTraceException; _getOption(String option)99fb3fb4f3Stomee private native long _getOption(String option) throws DTraceException; _isEnabled()100fb3fb4f3Stomee private native boolean _isEnabled(); _checkProgramEnabling()101fb3fb4f3Stomee private native void _checkProgramEnabling(); _go()102fb3fb4f3Stomee private native void _go() throws DTraceException; _stop()103fb3fb4f3Stomee private native void _stop() throws DTraceException; _consume()104fb3fb4f3Stomee private native void _consume() throws DTraceException; _interrupt()105fb3fb4f3Stomee private native void _interrupt(); _close()106fb3fb4f3Stomee private native void _close(); _getAggregate(AggregateSpec spec)107fb3fb4f3Stomee private native Aggregate _getAggregate(AggregateSpec spec) 108fb3fb4f3Stomee throws DTraceException; _createProcess(String cmd)109fb3fb4f3Stomee private native int _createProcess(String cmd) throws DTraceException; _grabProcess(int pid)110fb3fb4f3Stomee private native void _grabProcess(int pid) throws DTraceException; _listProbes(List <ProbeDescription> probeList, ProbeDescription filter)111fb3fb4f3Stomee private native void _listProbes(List <ProbeDescription> probeList, 112fb3fb4f3Stomee ProbeDescription filter); _listProbeDetail(List <Probe> probeList, ProbeDescription filter)113fb3fb4f3Stomee private native void _listProbeDetail(List <Probe> probeList, 114fb3fb4f3Stomee ProbeDescription filter); _listCompiledProbes( List <ProbeDescription> probeList, Program program)115fb3fb4f3Stomee private native void _listCompiledProbes( 116fb3fb4f3Stomee List <ProbeDescription> probeList, Program program); _listCompiledProbeDetail( List <Probe> probeList, Program program)117fb3fb4f3Stomee private native void _listCompiledProbeDetail( 118fb3fb4f3Stomee List <Probe> probeList, Program program); _getVersion()119fb3fb4f3Stomee private static native String _getVersion(); _openCount()120fb3fb4f3Stomee private static native int _openCount(); 121fb3fb4f3Stomee // 122fb3fb4f3Stomee // Releases memory held in the JNI layer after dtrace_close() has 123fb3fb4f3Stomee // released critical system resources like file descriptors, and 124fb3fb4f3Stomee // calls to libdtrace are no longer needed (or possible). 125fb3fb4f3Stomee // _destroy()126fb3fb4f3Stomee private native void _destroy(); 127fb3fb4f3Stomee // Called by LogDistribution _quantizeBucket(int i)128fb3fb4f3Stomee static native long _quantizeBucket(int i); 129fb3fb4f3Stomee // 130fb3fb4f3Stomee // Cannot be static because the necessary dtrace handle is specific 131fb3fb4f3Stomee // to this Consumer. 132fb3fb4f3Stomee // _lookupKernelFunction(Number address)133fb3fb4f3Stomee private native String _lookupKernelFunction(Number address); _lookupUserFunction(int pid, Number address)134fb3fb4f3Stomee private native String _lookupUserFunction(int pid, Number address); _getExecutableName()135fb3fb4f3Stomee private static native String _getExecutableName(); 136fb3fb4f3Stomee 137fb3fb4f3Stomee // Undocumented configuration options _setMaximumConsumers(int max)138fb3fb4f3Stomee private static native void _setMaximumConsumers(int max); _setDebug(boolean debug)139fb3fb4f3Stomee private static native void _setDebug(boolean debug); 140fb3fb4f3Stomee 141fb3fb4f3Stomee protected EventListenerList listenerList; 142fb3fb4f3Stomee protected ExceptionHandler exceptionHandler; 143fb3fb4f3Stomee 144fb3fb4f3Stomee private int _handle = -1; // native C identifier (do not modify) 145fb3fb4f3Stomee private final Identifier id; // java identifier 146fb3fb4f3Stomee 147fb3fb4f3Stomee private enum State { 148fb3fb4f3Stomee INIT, 149fb3fb4f3Stomee OPEN, 150fb3fb4f3Stomee COMPILED, 151fb3fb4f3Stomee GO, 152fb3fb4f3Stomee STARTED, 153fb3fb4f3Stomee STOPPED, 154fb3fb4f3Stomee CLOSED 155fb3fb4f3Stomee } 156fb3fb4f3Stomee 157fb3fb4f3Stomee private State state = State.INIT; 158fb3fb4f3Stomee private boolean stopCalled; 15943fb4b48Stomee private boolean abortCalled; 160fb3fb4f3Stomee 161fb3fb4f3Stomee // 162fb3fb4f3Stomee // Per-consumer lock used in native code to prevent conflict between 163fb3fb4f3Stomee // the native consumer loop and the getAggregate() thread without 164fb3fb4f3Stomee // locking this LocalConsumer. A distinct per-consumer lock allows 165fb3fb4f3Stomee // the stop() method to be synchronized without causing deadlock 166fb3fb4f3Stomee // when the consumer loop grabs the per-consumer lock before 167fb3fb4f3Stomee // dtrace_work(). 168fb3fb4f3Stomee // 169fb3fb4f3Stomee private Object consumerLock; 17052aacb45Stomee 171fb3fb4f3Stomee // 17252aacb45Stomee // stopLock is a synchronization lock used to ensure that the stop() 17352aacb45Stomee // method does not return until this consumer has actually stopped. 17452aacb45Stomee // Correct lock ordering is needed to ensure that listeners cannot 17552aacb45Stomee // deadlock this consumer: 17652aacb45Stomee // 1. stop() grabs the lock on this consumer before determining if 17752aacb45Stomee // this consumer is running (to ensure valid state). 17852aacb45Stomee // 2. Once stop() determines that this consumer is actually running, 17952aacb45Stomee // it releases the lock on this consumer. Failing to release the 18052aacb45Stomee // lock makes it possible for a ConsumerListener to deadlock this 18152aacb45Stomee // consumer by calling any synchronized LocalConcumer method 18252aacb45Stomee // (because the listener called by the worker thread prevents the 18352aacb45Stomee // worker thread from finishing while it waits for stop() to 18452aacb45Stomee // release the lock, which it will never do until the worker 18552aacb45Stomee // thread finishes). 18652aacb45Stomee // 3. stop() interrupts this consumer and grabs the stopLock, then 18752aacb45Stomee // waits on the stopLock for this consumer to stop (i.e. for the 18852aacb45Stomee // worker thread to finish). 18952aacb45Stomee // 4. The interrupted worker thread grabs the stopLock when it 19052aacb45Stomee // finishes so it can notify waiters on the stopLock (in this 19152aacb45Stomee // case the stop() method) that the worker thread is finished. 19252aacb45Stomee // The workEnded flag (whose access is protected by the 19352aacb45Stomee // stopLock), is used in case the interrupted worker thread 19452aacb45Stomee // finishes and grabs the stopLock before the stop() method does. 19552aacb45Stomee // Setting the flag in that case tells the stop() method it has 19652aacb45Stomee // nothing to wait for (otherwise stop() would wait forever, 19752aacb45Stomee // since there is no one left after the worker thread finishes to 19852aacb45Stomee // notify the stop() method to stop waiting). 19952aacb45Stomee // 5. The worker thread updates the state member to STOPPED and 20052aacb45Stomee // notifies listeners while it holds the stopLock and before it 20152aacb45Stomee // notifies waiters on the stopLock. This is to ensure that 20252aacb45Stomee // state has been updated to STOPPED and that listeners have 20352aacb45Stomee // executed consumerStopped() before the stop() method returns, 20452aacb45Stomee // to ensure valid state and in case the caller of stop() is 20552aacb45Stomee // relying on anything having been done by consumerStopped() 20652aacb45Stomee // before it proceeds to the next statement. 20752aacb45Stomee // 6. The worker thread notifies waiters on the stopLock before 20852aacb45Stomee // releasing it. stop() returns. 209fb3fb4f3Stomee // 210fb3fb4f3Stomee private Object stopLock; 211fb3fb4f3Stomee private boolean workEnded; 212fb3fb4f3Stomee 213fb3fb4f3Stomee private static int sequence = 0; 214fb3fb4f3Stomee 21552aacb45Stomee private static void configureLogging()21652aacb45Stomee configureLogging() 21752aacb45Stomee { 21852aacb45Stomee logger.setUseParentHandlers(false); 21952aacb45Stomee Handler handler = new ConsoleHandler(); 22052aacb45Stomee handler.setLevel(Level.ALL); 22152aacb45Stomee logger.addHandler(handler); 22252aacb45Stomee logger.setLevel(Level.OFF); 22352aacb45Stomee } 22452aacb45Stomee 22552aacb45Stomee private static Integer getIntegerProperty(String name)22652aacb45Stomee getIntegerProperty(String name) 22752aacb45Stomee { 22852aacb45Stomee Integer value = null; 22952aacb45Stomee String property = System.getProperty(name); 23052aacb45Stomee if (property != null && property.length() != 0) { 23152aacb45Stomee try { 23252aacb45Stomee value = Integer.parseInt(property); 23352aacb45Stomee System.out.println(name + "=" + value); 23452aacb45Stomee } catch (NumberFormatException e) { 23552aacb45Stomee System.err.println("Warning: property ignored: " + 23652aacb45Stomee name + "=" + property); 23752aacb45Stomee } 23852aacb45Stomee } 23952aacb45Stomee return value; 24052aacb45Stomee } 24152aacb45Stomee 24252aacb45Stomee private static void getConfigurationOptions()24352aacb45Stomee getConfigurationOptions() 24452aacb45Stomee { 24552aacb45Stomee Integer property; 24652aacb45Stomee property = getIntegerProperty("JAVA_DTRACE_API_DEBUG"); 24752aacb45Stomee if (property != null) { 24852aacb45Stomee debug = (property != 0); 24952aacb45Stomee } 25052aacb45Stomee property = getIntegerProperty("JAVA_DTRACE_MAX_CONSUMERS"); 25152aacb45Stomee if (property != null) { 25252aacb45Stomee maxConsumers = property; 25352aacb45Stomee } 25452aacb45Stomee } 25552aacb45Stomee 256fb3fb4f3Stomee /** 257fb3fb4f3Stomee * Creates a consumer that interacts with the native DTrace library 258fb3fb4f3Stomee * on the local system. 259fb3fb4f3Stomee */ 260fb3fb4f3Stomee public LocalConsumer()261fb3fb4f3Stomee LocalConsumer() 262fb3fb4f3Stomee { 263fb3fb4f3Stomee id = new LocalConsumer.Identifier(this); 264fb3fb4f3Stomee consumerLock = new Object(); 265fb3fb4f3Stomee stopLock = new Object(); 266fb3fb4f3Stomee listenerList = new EventListenerList(); 267fb3fb4f3Stomee } 268fb3fb4f3Stomee 269fb3fb4f3Stomee /** 270fb3fb4f3Stomee * Called by native C code only 271fb3fb4f3Stomee */ 272fb3fb4f3Stomee private int getHandle()273fb3fb4f3Stomee getHandle() 274fb3fb4f3Stomee { 275fb3fb4f3Stomee return _handle; 276fb3fb4f3Stomee } 277fb3fb4f3Stomee 278fb3fb4f3Stomee /** 279fb3fb4f3Stomee * Called by native C code only 280fb3fb4f3Stomee */ 281fb3fb4f3Stomee private void setHandle(int n)282fb3fb4f3Stomee setHandle(int n) 283fb3fb4f3Stomee { 284fb3fb4f3Stomee _handle = n; 285fb3fb4f3Stomee } 286fb3fb4f3Stomee 287fb3fb4f3Stomee public synchronized void open(OpenFlag .... flags)288fb3fb4f3Stomee open(OpenFlag ... flags) throws DTraceException 289fb3fb4f3Stomee { 290fb3fb4f3Stomee if (state == State.CLOSED) { 291fb3fb4f3Stomee throw new IllegalStateException("cannot reopen a closed consumer"); 292fb3fb4f3Stomee } 293fb3fb4f3Stomee if (state != State.INIT) { 294fb3fb4f3Stomee throw new IllegalStateException("consumer already open"); 295fb3fb4f3Stomee } 296fb3fb4f3Stomee 297fb3fb4f3Stomee for (OpenFlag flag : flags) { 298fb3fb4f3Stomee if (flag == null) { 299fb3fb4f3Stomee throw new NullPointerException("open flag is null"); 300fb3fb4f3Stomee } 301fb3fb4f3Stomee } 302fb3fb4f3Stomee 303fb3fb4f3Stomee synchronized (LocalConsumer.class) { 304fb3fb4f3Stomee _open(flags); 305fb3fb4f3Stomee } 306fb3fb4f3Stomee 307fb3fb4f3Stomee state = State.OPEN; 308fb3fb4f3Stomee setOptions(DEFAULT_OPTIONS); 309fb3fb4f3Stomee 31043fb4b48Stomee if (abortCalled) { 31143fb4b48Stomee _interrupt(); 31243fb4b48Stomee } 31343fb4b48Stomee 314fb3fb4f3Stomee if (logger.isLoggable(Level.INFO)) { 315fb3fb4f3Stomee logger.info("consumer table count: " + _openCount()); 316fb3fb4f3Stomee } 317fb3fb4f3Stomee } 318fb3fb4f3Stomee 319fb3fb4f3Stomee private synchronized void checkCompile()320fb3fb4f3Stomee checkCompile() 321fb3fb4f3Stomee { 322fb3fb4f3Stomee switch (state) { 323fb3fb4f3Stomee case INIT: 324fb3fb4f3Stomee throw new IllegalStateException("consumer not open"); 325fb3fb4f3Stomee case OPEN: 326fb3fb4f3Stomee case COMPILED: // caller may compile more than one program 327fb3fb4f3Stomee break; 328fb3fb4f3Stomee case GO: 329fb3fb4f3Stomee case STARTED: 330fb3fb4f3Stomee throw new IllegalStateException("go() already called"); 331fb3fb4f3Stomee case STOPPED: 332fb3fb4f3Stomee throw new IllegalStateException("consumer stopped"); 333fb3fb4f3Stomee case CLOSED: 334fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 335fb3fb4f3Stomee } 336fb3fb4f3Stomee } 337fb3fb4f3Stomee 338fb3fb4f3Stomee public synchronized Program compile(String program, String ... macroArgs)339fb3fb4f3Stomee compile(String program, String ... macroArgs) throws DTraceException 340fb3fb4f3Stomee { 341fb3fb4f3Stomee if (program == null) { 342fb3fb4f3Stomee throw new NullPointerException("program string is null"); 343fb3fb4f3Stomee } 344fb3fb4f3Stomee checkCompile(); 345fb3fb4f3Stomee Program p = null; 346fb3fb4f3Stomee 347fb3fb4f3Stomee String[] argv = null; 348fb3fb4f3Stomee if (macroArgs != null) { 349fb3fb4f3Stomee for (String macroArg : macroArgs) { 350fb3fb4f3Stomee if (macroArg == null) { 351fb3fb4f3Stomee throw new NullPointerException("macro argument is null"); 352fb3fb4f3Stomee } 353fb3fb4f3Stomee } 354fb3fb4f3Stomee argv = new String[macroArgs.length + 1]; 355fb3fb4f3Stomee synchronized (LocalConsumer.class) { 356fb3fb4f3Stomee // 357fb3fb4f3Stomee // Could be an application with an embedded JVM, not 358fb3fb4f3Stomee // necessarily "java". 359fb3fb4f3Stomee // 360fb3fb4f3Stomee argv[0] = _getExecutableName(); 361fb3fb4f3Stomee } 362fb3fb4f3Stomee System.arraycopy(macroArgs, 0, argv, 1, macroArgs.length); 363fb3fb4f3Stomee } else { 364fb3fb4f3Stomee synchronized (LocalConsumer.class) { 365fb3fb4f3Stomee argv = new String[] { _getExecutableName() }; 366fb3fb4f3Stomee } 367fb3fb4f3Stomee } 368fb3fb4f3Stomee synchronized (LocalConsumer.class) { 369fb3fb4f3Stomee p = _compileString(program, argv); 370fb3fb4f3Stomee } 371fb3fb4f3Stomee p.consumerID = id; 372fb3fb4f3Stomee p.contents = program; 373fb3fb4f3Stomee p.validate(); 374fb3fb4f3Stomee state = State.COMPILED; 375fb3fb4f3Stomee 376fb3fb4f3Stomee return p; 377fb3fb4f3Stomee } 378fb3fb4f3Stomee 379fb3fb4f3Stomee public synchronized Program compile(File program, String ... macroArgs)380fb3fb4f3Stomee compile(File program, String ... macroArgs) throws DTraceException, 381fb3fb4f3Stomee IOException, SecurityException 382fb3fb4f3Stomee { 383fb3fb4f3Stomee if (program == null) { 384fb3fb4f3Stomee throw new NullPointerException("program file is null"); 385fb3fb4f3Stomee } 386fb3fb4f3Stomee if (!program.canRead()) { 387fb3fb4f3Stomee throw new FileNotFoundException("failed to open " + 388fb3fb4f3Stomee program.getName()); 389fb3fb4f3Stomee } 390fb3fb4f3Stomee checkCompile(); 391fb3fb4f3Stomee Program.File p = null; 392fb3fb4f3Stomee 393fb3fb4f3Stomee String[] argv = null; 394fb3fb4f3Stomee if (macroArgs != null) { 395fb3fb4f3Stomee for (String macroArg : macroArgs) { 396fb3fb4f3Stomee if (macroArg == null) { 397fb3fb4f3Stomee throw new NullPointerException("macro argument is null"); 398fb3fb4f3Stomee } 399fb3fb4f3Stomee } 400fb3fb4f3Stomee argv = new String[macroArgs.length + 1]; 401fb3fb4f3Stomee argv[0] = program.getPath(); 402fb3fb4f3Stomee System.arraycopy(macroArgs, 0, argv, 1, macroArgs.length); 403fb3fb4f3Stomee } else { 404fb3fb4f3Stomee macroArgs = new String[] { program.getPath() }; 405fb3fb4f3Stomee } 406fb3fb4f3Stomee synchronized (LocalConsumer.class) { 407fb3fb4f3Stomee p = _compileFile(program.getPath(), argv); 408fb3fb4f3Stomee } 409fb3fb4f3Stomee p.consumerID = id; 410fb3fb4f3Stomee p.contents = Program.getProgramString(program); 411fb3fb4f3Stomee p.file = program; 412fb3fb4f3Stomee p.validate(); 41391cfa10aStomee p.validateFile(); 414fb3fb4f3Stomee state = State.COMPILED; 415fb3fb4f3Stomee 416fb3fb4f3Stomee return p; 417fb3fb4f3Stomee } 418fb3fb4f3Stomee 419fb3fb4f3Stomee private synchronized void checkProgram(Program program)420fb3fb4f3Stomee checkProgram(Program program) 421fb3fb4f3Stomee { 422fb3fb4f3Stomee if (program == null) { 423fb3fb4f3Stomee throw new NullPointerException("program is null"); 424fb3fb4f3Stomee } 425fb3fb4f3Stomee if (!id.equals(program.consumerID)) { 426fb3fb4f3Stomee throw new IllegalArgumentException("program not compiled " + 427fb3fb4f3Stomee "by this consumer"); 428fb3fb4f3Stomee } 429fb3fb4f3Stomee } 430fb3fb4f3Stomee 431fb3fb4f3Stomee public void enable()432fb3fb4f3Stomee enable() throws DTraceException 433fb3fb4f3Stomee { 434fb3fb4f3Stomee enable(null); 435fb3fb4f3Stomee } 436fb3fb4f3Stomee 437fb3fb4f3Stomee public synchronized void enable(Program program)438fb3fb4f3Stomee enable(Program program) throws DTraceException 439fb3fb4f3Stomee { 440fb3fb4f3Stomee switch (state) { 441fb3fb4f3Stomee case INIT: 442fb3fb4f3Stomee throw new IllegalStateException("consumer not open"); 443fb3fb4f3Stomee case OPEN: 444fb3fb4f3Stomee throw new IllegalStateException("no compiled program"); 445fb3fb4f3Stomee case COMPILED: 446fb3fb4f3Stomee break; 447fb3fb4f3Stomee case GO: 448fb3fb4f3Stomee case STARTED: 449fb3fb4f3Stomee throw new IllegalStateException("go() already called"); 450fb3fb4f3Stomee case STOPPED: 451fb3fb4f3Stomee throw new IllegalStateException("consumer stopped"); 452fb3fb4f3Stomee case CLOSED: 453fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 454fb3fb4f3Stomee } 455fb3fb4f3Stomee 456fb3fb4f3Stomee // Compile all programs if null 457fb3fb4f3Stomee if (program != null) { 458fb3fb4f3Stomee checkProgram(program); 459fb3fb4f3Stomee } 460fb3fb4f3Stomee 461fb3fb4f3Stomee // 462fb3fb4f3Stomee // Left to native code to throw IllegalArgumentException if the 463fb3fb4f3Stomee // program is already enabled, since only the native code knows 464fb3fb4f3Stomee // the enabled state. 465fb3fb4f3Stomee // 466fb3fb4f3Stomee synchronized (LocalConsumer.class) { 467fb3fb4f3Stomee _exec(program); 468fb3fb4f3Stomee } 469fb3fb4f3Stomee } 470fb3fb4f3Stomee 471fb3fb4f3Stomee public synchronized void getProgramInfo(Program program)472fb3fb4f3Stomee getProgramInfo(Program program) throws DTraceException 473fb3fb4f3Stomee { 474fb3fb4f3Stomee checkProgram(program); 475fb3fb4f3Stomee if (state == State.CLOSED) { 476fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 477fb3fb4f3Stomee } 478fb3fb4f3Stomee 479fb3fb4f3Stomee // 480fb3fb4f3Stomee // The given program was compiled by this consumer, so we can 481fb3fb4f3Stomee // assert the following: 482fb3fb4f3Stomee // 483fb3fb4f3Stomee assert ((state != State.INIT) && (state != State.OPEN)); 484fb3fb4f3Stomee 485fb3fb4f3Stomee synchronized (LocalConsumer.class) { 486fb3fb4f3Stomee _getProgramInfo(program); 487fb3fb4f3Stomee } 488fb3fb4f3Stomee } 489fb3fb4f3Stomee 490fb3fb4f3Stomee private void setOptions(Option[] options)491fb3fb4f3Stomee setOptions(Option[] options) throws DTraceException 492fb3fb4f3Stomee { 493fb3fb4f3Stomee for (Option o : options) { 49452aacb45Stomee setOption(o.getName(), o.getValue()); 495fb3fb4f3Stomee } 496fb3fb4f3Stomee } 497fb3fb4f3Stomee 498fb3fb4f3Stomee public void setOption(String option)499fb3fb4f3Stomee setOption(String option) throws DTraceException 500fb3fb4f3Stomee { 501fb3fb4f3Stomee setOption(option, Option.VALUE_SET); 502fb3fb4f3Stomee } 503fb3fb4f3Stomee 504fb3fb4f3Stomee public void unsetOption(String option)505fb3fb4f3Stomee unsetOption(String option) throws DTraceException 506fb3fb4f3Stomee { 507fb3fb4f3Stomee setOption(option, Option.VALUE_UNSET); 508fb3fb4f3Stomee } 509fb3fb4f3Stomee 510fb3fb4f3Stomee public synchronized void setOption(String option, String value)511fb3fb4f3Stomee setOption(String option, String value) throws DTraceException 512fb3fb4f3Stomee { 513fb3fb4f3Stomee if (option == null) { 514fb3fb4f3Stomee throw new NullPointerException("option is null"); 515fb3fb4f3Stomee } 516fb3fb4f3Stomee if (value == null) { 517fb3fb4f3Stomee throw new NullPointerException("option value is null"); 518fb3fb4f3Stomee } 519fb3fb4f3Stomee 520fb3fb4f3Stomee switch (state) { 521fb3fb4f3Stomee case INIT: 522fb3fb4f3Stomee throw new IllegalStateException("consumer not open"); 523fb3fb4f3Stomee case OPEN: 524fb3fb4f3Stomee case COMPILED: 525fb3fb4f3Stomee case GO: 526fb3fb4f3Stomee case STARTED: // Some options can be set on a running consumer 527fb3fb4f3Stomee case STOPPED: // Allowed (may affect getAggregate()) 528fb3fb4f3Stomee break; 529fb3fb4f3Stomee case CLOSED: 530fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 531fb3fb4f3Stomee } 532fb3fb4f3Stomee 533fb3fb4f3Stomee synchronized (LocalConsumer.class) { 534fb3fb4f3Stomee _setOption(option, value); 535fb3fb4f3Stomee } 536fb3fb4f3Stomee } 537fb3fb4f3Stomee 538fb3fb4f3Stomee public synchronized long getOption(String option)539fb3fb4f3Stomee getOption(String option) throws DTraceException 540fb3fb4f3Stomee { 541fb3fb4f3Stomee if (option == null) { 542fb3fb4f3Stomee throw new NullPointerException("option is null"); 543fb3fb4f3Stomee } 544fb3fb4f3Stomee 545fb3fb4f3Stomee switch (state) { 546fb3fb4f3Stomee case INIT: 547fb3fb4f3Stomee throw new IllegalStateException("consumer not open"); 548fb3fb4f3Stomee case OPEN: 549fb3fb4f3Stomee case COMPILED: 550fb3fb4f3Stomee case GO: 551fb3fb4f3Stomee case STARTED: 552fb3fb4f3Stomee case STOPPED: 553fb3fb4f3Stomee break; 554fb3fb4f3Stomee case CLOSED: 555fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 556fb3fb4f3Stomee } 557fb3fb4f3Stomee 558fb3fb4f3Stomee long value; 559fb3fb4f3Stomee synchronized (LocalConsumer.class) { 560fb3fb4f3Stomee value = _getOption(option); 561fb3fb4f3Stomee } 562fb3fb4f3Stomee return value; 563fb3fb4f3Stomee } 564fb3fb4f3Stomee 565fb3fb4f3Stomee public final synchronized boolean isOpen()566fb3fb4f3Stomee isOpen() 567fb3fb4f3Stomee { 568fb3fb4f3Stomee return ((state != State.INIT) && (state != State.CLOSED)); 569fb3fb4f3Stomee } 570fb3fb4f3Stomee 571fb3fb4f3Stomee public final synchronized boolean isEnabled()572fb3fb4f3Stomee isEnabled() 573fb3fb4f3Stomee { 574fb3fb4f3Stomee if (state != State.COMPILED) { 575fb3fb4f3Stomee return false; 576fb3fb4f3Stomee } 577fb3fb4f3Stomee 578fb3fb4f3Stomee return _isEnabled(); 579fb3fb4f3Stomee } 580fb3fb4f3Stomee 581fb3fb4f3Stomee public final synchronized boolean isRunning()582fb3fb4f3Stomee isRunning() 583fb3fb4f3Stomee { 584fb3fb4f3Stomee return (state == State.STARTED); 585fb3fb4f3Stomee } 586fb3fb4f3Stomee 587fb3fb4f3Stomee public final synchronized boolean isClosed()588fb3fb4f3Stomee isClosed() 589fb3fb4f3Stomee { 590fb3fb4f3Stomee return (state == State.CLOSED); 591fb3fb4f3Stomee } 592fb3fb4f3Stomee 593fb3fb4f3Stomee /** 594fb3fb4f3Stomee * Called in the runnable target of the thread returned by {@link 595fb3fb4f3Stomee * #createThread()} to run this DTrace consumer. 596fb3fb4f3Stomee * 597fb3fb4f3Stomee * @see #createThread() 598fb3fb4f3Stomee */ 599fb3fb4f3Stomee protected final void work()600fb3fb4f3Stomee work() 601fb3fb4f3Stomee { 602fb3fb4f3Stomee try { 603fb3fb4f3Stomee synchronized (this) { 604fb3fb4f3Stomee if (state != State.GO) { 605fb3fb4f3Stomee // 606fb3fb4f3Stomee // stop() was called after go() but before the 607fb3fb4f3Stomee // consumer started 608fb3fb4f3Stomee // 609fb3fb4f3Stomee return; // executes finally block before returning 610fb3fb4f3Stomee } 611fb3fb4f3Stomee 612fb3fb4f3Stomee state = State.STARTED; 613fb3fb4f3Stomee fireConsumerStarted(new ConsumerEvent(this, 614fb3fb4f3Stomee System.nanoTime())); 615fb3fb4f3Stomee } 616fb3fb4f3Stomee 617fb3fb4f3Stomee // 618fb3fb4f3Stomee // We should not prevent other consumers from running 619fb3fb4f3Stomee // concurrently while this consumer blocks on the native 620fb3fb4f3Stomee // consumer loop. Instead, native code will acquire the 621fb3fb4f3Stomee // LocalConsumer.class monitor as needed before calling 622fb3fb4f3Stomee // libdtrace functions. 623fb3fb4f3Stomee // 624fb3fb4f3Stomee _consume(); 625fb3fb4f3Stomee 626fb3fb4f3Stomee } catch (Throwable e) { 627fb3fb4f3Stomee if (exceptionHandler != null) { 628fb3fb4f3Stomee exceptionHandler.handleException(e); 629fb3fb4f3Stomee } else { 630fb3fb4f3Stomee e.printStackTrace(); 631fb3fb4f3Stomee } 632fb3fb4f3Stomee } finally { 633fb3fb4f3Stomee synchronized (stopLock) { 63452aacb45Stomee // Notify listeners while holding stopLock to guarantee 63552aacb45Stomee // that listeners finish executing consumerStopped() 63652aacb45Stomee // before the stop() method returns. 637fb3fb4f3Stomee synchronized (this) { 6384d0eb50eSRichard PALO if (state == State.STOPPED || state == State.CLOSED) { 639127bbe13Stomee // 640127bbe13Stomee // This consumer was stopped just after calling 641127bbe13Stomee // go() but before starting (the premature return 642127bbe13Stomee // case at the top of this work() method). It is 643127bbe13Stomee // possible to call close() on a consumer that has 644127bbe13Stomee // been stopped before starting. In that case the 645127bbe13Stomee // premature return above still takes us here in the 646127bbe13Stomee // finally clause, and we must not revert the CLOSED 647127bbe13Stomee // state to STOPPED. 648127bbe13Stomee // 649127bbe13Stomee } else { 650fb3fb4f3Stomee state = State.STOPPED; 651fb3fb4f3Stomee fireConsumerStopped(new ConsumerEvent(this, 652fb3fb4f3Stomee System.nanoTime())); 653fb3fb4f3Stomee } 654127bbe13Stomee } 65552aacb45Stomee 65652aacb45Stomee // Notify the stop() method to stop waiting 65752aacb45Stomee workEnded = true; 65852aacb45Stomee stopLock.notifyAll(); 659fb3fb4f3Stomee } 660fb3fb4f3Stomee } 661fb3fb4f3Stomee } 662fb3fb4f3Stomee 663fb3fb4f3Stomee /** 664fb3fb4f3Stomee * Creates the background thread started by {@link #go()} to run 665fb3fb4f3Stomee * this consumer. Override this method if you need to set 666fb3fb4f3Stomee * non-default {@code Thread} options or create the thread in a 667fb3fb4f3Stomee * {@code ThreadGroup}. If you don't need to create the thread 668fb3fb4f3Stomee * yourself, set the desired options on {@code super.createThread()} 669fb3fb4f3Stomee * before returning it. Otherwise, the {@code Runnable} target of 670fb3fb4f3Stomee * the created thread must call {@link #work()} in order to run this 671fb3fb4f3Stomee * DTrace consumer. For example, to modify the default background 672fb3fb4f3Stomee * consumer thread: 673fb3fb4f3Stomee * <pre><code> 674fb3fb4f3Stomee * protected Thread 675fb3fb4f3Stomee * createThread() 676fb3fb4f3Stomee * { 677fb3fb4f3Stomee * Thread t = super.createThread(); 678fb3fb4f3Stomee * t.setPriority(Thread.MIN_PRIORITY); 679fb3fb4f3Stomee * return t; 680fb3fb4f3Stomee * } 681fb3fb4f3Stomee * </code></pre> 682fb3fb4f3Stomee * Or if you need to create your own thread: 683*3a931819SPeter Tribble * <pre><code> 684fb3fb4f3Stomee * protected Thread 685fb3fb4f3Stomee * createThread() 686fb3fb4f3Stomee * { 687fb3fb4f3Stomee * Runnable target = new Runnable() { 688fb3fb4f3Stomee * public void run() { 689fb3fb4f3Stomee * work(); 690fb3fb4f3Stomee * } 691fb3fb4f3Stomee * }; 692fb3fb4f3Stomee * String name = "Consumer " + UserApplication.sequence++; 693fb3fb4f3Stomee * Thread t = new Thread(UserApplication.threadGroup, 694fb3fb4f3Stomee * target, name); 695fb3fb4f3Stomee * return t; 696fb3fb4f3Stomee * } 697fb3fb4f3Stomee * </code></pre> 698fb3fb4f3Stomee * Do not start the returned thread, otherwise {@code go()} will 699fb3fb4f3Stomee * throw an {@link IllegalThreadStateException} when it tries to 700fb3fb4f3Stomee * start the returned thread a second time. 701fb3fb4f3Stomee */ 702fb3fb4f3Stomee protected Thread createThread()703fb3fb4f3Stomee createThread() 704fb3fb4f3Stomee { 705fb3fb4f3Stomee Thread t = new Thread(new Runnable() { 706fb3fb4f3Stomee public void run() { 707fb3fb4f3Stomee work(); 708fb3fb4f3Stomee } 709fb3fb4f3Stomee }, "DTrace consumer " + id); 710fb3fb4f3Stomee return t; 711fb3fb4f3Stomee } 712fb3fb4f3Stomee 713fb3fb4f3Stomee /** 714*3a931819SPeter Tribble * {@inheritDoc} 715fb3fb4f3Stomee * @throws IllegalThreadStateException if a subclass calls {@link 716fb3fb4f3Stomee * Thread#start()} on the value of {@link #createThread()} 717fb3fb4f3Stomee * @see #createThread() 718fb3fb4f3Stomee */ 719fb3fb4f3Stomee public void go()720fb3fb4f3Stomee go() throws DTraceException 721fb3fb4f3Stomee { 722fb3fb4f3Stomee go(null); 723fb3fb4f3Stomee } 724fb3fb4f3Stomee 725fb3fb4f3Stomee /** 726*3a931819SPeter Tribble * {@inheritDoc} 727fb3fb4f3Stomee * @throws IllegalThreadStateException if a subclass calls {@link 728fb3fb4f3Stomee * Thread#start()} on the value of {@link #createThread()} 729fb3fb4f3Stomee * @see #createThread() 730fb3fb4f3Stomee */ 731fb3fb4f3Stomee public synchronized void go(ExceptionHandler h)732fb3fb4f3Stomee go(ExceptionHandler h) throws DTraceException 733fb3fb4f3Stomee { 734fb3fb4f3Stomee switch (state) { 735fb3fb4f3Stomee case INIT: 736fb3fb4f3Stomee throw new IllegalStateException("consumer not open"); 737fb3fb4f3Stomee case OPEN: 738fb3fb4f3Stomee throw new IllegalStateException("no compiled program"); 739fb3fb4f3Stomee case COMPILED: 740fb3fb4f3Stomee // 741fb3fb4f3Stomee // Throws IllegalStateException if not all compiled programs are 742fb3fb4f3Stomee // also enabled. Does not make any calls to libdtrace. 743fb3fb4f3Stomee // 744fb3fb4f3Stomee _checkProgramEnabling(); 745fb3fb4f3Stomee break; 746fb3fb4f3Stomee case GO: 747fb3fb4f3Stomee case STARTED: 748fb3fb4f3Stomee throw new IllegalStateException("go() already called"); 749fb3fb4f3Stomee case STOPPED: 750fb3fb4f3Stomee throw new IllegalStateException("consumer stopped"); 751fb3fb4f3Stomee case CLOSED: 752fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 753fb3fb4f3Stomee default: 754fb3fb4f3Stomee throw new IllegalArgumentException("unknown state: " + state); 755fb3fb4f3Stomee } 756fb3fb4f3Stomee 757fb3fb4f3Stomee synchronized (LocalConsumer.class) { 758fb3fb4f3Stomee _go(); 759fb3fb4f3Stomee } 760fb3fb4f3Stomee 761fb3fb4f3Stomee state = State.GO; 762fb3fb4f3Stomee exceptionHandler = h; 763fb3fb4f3Stomee Thread t = createThread(); 764fb3fb4f3Stomee t.start(); 765fb3fb4f3Stomee } 766fb3fb4f3Stomee 767382dbd46Stomee /** 768*3a931819SPeter Tribble * {@inheritDoc} 769382dbd46Stomee * 770382dbd46Stomee * @throws IllegalThreadStateException if attempting to {@code 771382dbd46Stomee * stop()} a running consumer while holding the lock on that 772382dbd46Stomee * consumer 773382dbd46Stomee */ 77452aacb45Stomee public void stop()775fb3fb4f3Stomee stop() 776fb3fb4f3Stomee { 77752aacb45Stomee boolean running = false; 77852aacb45Stomee 77952aacb45Stomee synchronized (this) { 780fb3fb4f3Stomee switch (state) { 781fb3fb4f3Stomee case INIT: 782fb3fb4f3Stomee throw new IllegalStateException("consumer not open"); 783fb3fb4f3Stomee case OPEN: 784fb3fb4f3Stomee case COMPILED: 785fb3fb4f3Stomee throw new IllegalStateException("go() not called"); 786fb3fb4f3Stomee case GO: 787fb3fb4f3Stomee try { 788fb3fb4f3Stomee synchronized (LocalConsumer.class) { 789fb3fb4f3Stomee _stop(); 790fb3fb4f3Stomee } 791fb3fb4f3Stomee state = State.STOPPED; 792127bbe13Stomee fireConsumerStopped(new ConsumerEvent(this, 793127bbe13Stomee System.nanoTime())); 794fb3fb4f3Stomee } catch (DTraceException e) { 795fb3fb4f3Stomee if (exceptionHandler != null) { 796fb3fb4f3Stomee exceptionHandler.handleException(e); 797fb3fb4f3Stomee } else { 798fb3fb4f3Stomee e.printStackTrace(); 799fb3fb4f3Stomee } 800fb3fb4f3Stomee } 801fb3fb4f3Stomee break; 802fb3fb4f3Stomee case STARTED: 80352aacb45Stomee running = true; 804fb3fb4f3Stomee break; 805fb3fb4f3Stomee case STOPPED: 806fb3fb4f3Stomee // 80752aacb45Stomee // The work() thread that runs the native consumer 80852aacb45Stomee // loop may have terminated because of the exit() 80952aacb45Stomee // action in a DTrace program. In that case, a 81052aacb45Stomee // RuntimeException is inappropriate because there 81152aacb45Stomee // is no misuse of the API. Creating a new checked 81252aacb45Stomee // exception type to handle this case seems to offer 81352aacb45Stomee // no benefit for the trouble to the caller. 81452aacb45Stomee // Instead, the situation calls for stop() to be 81552aacb45Stomee // quietly tolerant. 816fb3fb4f3Stomee // 817fb3fb4f3Stomee if (stopCalled) { 81852aacb45Stomee throw new IllegalStateException( 81952aacb45Stomee "consumer already stopped"); 820fb3fb4f3Stomee } 821382dbd46Stomee logger.fine("consumer already stopped"); 822fb3fb4f3Stomee break; 823fb3fb4f3Stomee case CLOSED: 824fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 825fb3fb4f3Stomee default: 82652aacb45Stomee throw new IllegalArgumentException("unknown state: " + 82752aacb45Stomee state); 828fb3fb4f3Stomee } 829fb3fb4f3Stomee 830fb3fb4f3Stomee stopCalled = true; 831fb3fb4f3Stomee } 832fb3fb4f3Stomee 83352aacb45Stomee if (running) { 834382dbd46Stomee if (Thread.holdsLock(this)) { 835382dbd46Stomee throw new IllegalThreadStateException("The current " + 836382dbd46Stomee "thread cannot stop this LocalConsumer while " + 837382dbd46Stomee "holding the lock on this LocalConsumer"); 838382dbd46Stomee } 839382dbd46Stomee 84052aacb45Stomee // 84152aacb45Stomee // Calls no libdtrace methods, so no synchronization is 84252aacb45Stomee // needed. Sets a native flag that causes the consumer 84352aacb45Stomee // thread to exit the consumer loop and call native 84452aacb45Stomee // dtrace_stop() at the end of the current interval (after 84552aacb45Stomee // grabbing the global Consumer.class lock required for any 84652aacb45Stomee // libdtrace call). 84752aacb45Stomee // 84852aacb45Stomee _interrupt(); 84952aacb45Stomee 85052aacb45Stomee synchronized (stopLock) { 85152aacb45Stomee // 85252aacb45Stomee // Wait for work() to set workEnded. If the work() 85352aacb45Stomee // thread got the stopLock first, then workEnded is 85452aacb45Stomee // already set. 85552aacb45Stomee // 85652aacb45Stomee while (!workEnded) { 85752aacb45Stomee try { 85852aacb45Stomee stopLock.wait(); 85952aacb45Stomee } catch (InterruptedException e) { 86052aacb45Stomee logger.warning(e.toString()); 86152aacb45Stomee // do nothing but re-check the condition for 86252aacb45Stomee // waiting 86352aacb45Stomee } 86452aacb45Stomee } 86552aacb45Stomee } 86652aacb45Stomee } 86752aacb45Stomee } 86852aacb45Stomee 86943fb4b48Stomee public synchronized void abort()870382dbd46Stomee abort() 871382dbd46Stomee { 87243fb4b48Stomee if ((state != State.INIT) && (state != State.CLOSED)) { 873382dbd46Stomee _interrupt(); 874382dbd46Stomee } 87543fb4b48Stomee abortCalled = true; 87643fb4b48Stomee } 877382dbd46Stomee 878382dbd46Stomee /** 879*3a931819SPeter Tribble * {@inheritDoc} 880382dbd46Stomee * 881382dbd46Stomee * @throws IllegalThreadStateException if attempting to {@code 882382dbd46Stomee * close()} a running consumer while holding the lock on that 883382dbd46Stomee * consumer 884382dbd46Stomee */ 885382dbd46Stomee public void close()886fb3fb4f3Stomee close() 887fb3fb4f3Stomee { 888382dbd46Stomee synchronized (this) { 889fb3fb4f3Stomee if ((state == State.INIT) || (state == State.CLOSED)) { 890fb3fb4f3Stomee state = State.CLOSED; 891fb3fb4f3Stomee return; 892fb3fb4f3Stomee } 893fb3fb4f3Stomee } 894fb3fb4f3Stomee 895382dbd46Stomee try { 896382dbd46Stomee stop(); 897382dbd46Stomee } catch (IllegalStateException e) { 898382dbd46Stomee // ignore (we don't have synchronized state access because 899382dbd46Stomee // it is illegal to call stop() while holding the lock on 900382dbd46Stomee // this consumer) 901382dbd46Stomee } 902382dbd46Stomee 903382dbd46Stomee synchronized (this) { 904382dbd46Stomee if (state != State.CLOSED) { 905fb3fb4f3Stomee synchronized (LocalConsumer.class) { 906fb3fb4f3Stomee _close(); 907fb3fb4f3Stomee } 908fb3fb4f3Stomee _destroy(); 909fb3fb4f3Stomee state = State.CLOSED; 910fb3fb4f3Stomee 911fb3fb4f3Stomee if (logger.isLoggable(Level.INFO)) { 912fb3fb4f3Stomee logger.info("consumer table count: " + _openCount()); 913fb3fb4f3Stomee } 914fb3fb4f3Stomee } 915382dbd46Stomee } 916382dbd46Stomee } 917fb3fb4f3Stomee 918fb3fb4f3Stomee public void addConsumerListener(ConsumerListener l)919fb3fb4f3Stomee addConsumerListener(ConsumerListener l) 920fb3fb4f3Stomee { 921fb3fb4f3Stomee listenerList.add(ConsumerListener.class, l); 922fb3fb4f3Stomee } 923fb3fb4f3Stomee 924fb3fb4f3Stomee public void removeConsumerListener(ConsumerListener l)925fb3fb4f3Stomee removeConsumerListener(ConsumerListener l) 926fb3fb4f3Stomee { 927fb3fb4f3Stomee listenerList.remove(ConsumerListener.class, l); 928fb3fb4f3Stomee } 929fb3fb4f3Stomee 930fb3fb4f3Stomee public Aggregate getAggregate()931fb3fb4f3Stomee getAggregate() throws DTraceException 932fb3fb4f3Stomee { 933fb3fb4f3Stomee // include all, clear none 934fb3fb4f3Stomee return getAggregate(null, Collections. <String> emptySet()); 935fb3fb4f3Stomee } 936fb3fb4f3Stomee 937fb3fb4f3Stomee public Aggregate getAggregate(Set <String> includedAggregationNames)938fb3fb4f3Stomee getAggregate(Set <String> includedAggregationNames) 939fb3fb4f3Stomee throws DTraceException 940fb3fb4f3Stomee { 941fb3fb4f3Stomee return getAggregate(includedAggregationNames, 942fb3fb4f3Stomee Collections. <String> emptySet()); 943fb3fb4f3Stomee } 944fb3fb4f3Stomee 945fb3fb4f3Stomee public Aggregate getAggregate(Set <String> includedAggregationNames, Set <String> clearedAggregationNames)946fb3fb4f3Stomee getAggregate(Set <String> includedAggregationNames, 947fb3fb4f3Stomee Set <String> clearedAggregationNames) 948fb3fb4f3Stomee throws DTraceException 949fb3fb4f3Stomee { 950fb3fb4f3Stomee AggregateSpec spec = new AggregateSpec(); 951fb3fb4f3Stomee 952fb3fb4f3Stomee if (includedAggregationNames == null) { 953fb3fb4f3Stomee spec.setIncludeByDefault(true); 954fb3fb4f3Stomee } else { 955fb3fb4f3Stomee spec.setIncludeByDefault(false); 956fb3fb4f3Stomee for (String included : includedAggregationNames) { 957fb3fb4f3Stomee spec.addIncludedAggregationName(included); 958fb3fb4f3Stomee } 959fb3fb4f3Stomee } 960fb3fb4f3Stomee 961fb3fb4f3Stomee if (clearedAggregationNames == null) { 962fb3fb4f3Stomee spec.setClearByDefault(true); 963fb3fb4f3Stomee } else { 964fb3fb4f3Stomee spec.setClearByDefault(false); 965fb3fb4f3Stomee for (String cleared : clearedAggregationNames) { 966fb3fb4f3Stomee spec.addClearedAggregationName(cleared); 967fb3fb4f3Stomee } 968fb3fb4f3Stomee } 969fb3fb4f3Stomee 970fb3fb4f3Stomee return getAggregate(spec); 971fb3fb4f3Stomee } 972fb3fb4f3Stomee 973fb3fb4f3Stomee private synchronized Aggregate getAggregate(AggregateSpec spec)974fb3fb4f3Stomee getAggregate(AggregateSpec spec) throws DTraceException 975fb3fb4f3Stomee { 976fb3fb4f3Stomee // 977fb3fb4f3Stomee // It should be possible to request aggregation data after a 978fb3fb4f3Stomee // consumer has stopped but not after it has been closed. 979fb3fb4f3Stomee // 980fb3fb4f3Stomee checkGoCalled(); 981fb3fb4f3Stomee 982fb3fb4f3Stomee // 983fb3fb4f3Stomee // Getting the aggregate is a time-consuming request that should not 984fb3fb4f3Stomee // prevent other consumers from running concurrently. Instead, 985fb3fb4f3Stomee // native code will acquire the LocalConsumer.class monitor as 986fb3fb4f3Stomee // needed before calling libdtrace functions. 987fb3fb4f3Stomee // 988fb3fb4f3Stomee Aggregate aggregate = _getAggregate(spec); 989fb3fb4f3Stomee return aggregate; 990fb3fb4f3Stomee } 991fb3fb4f3Stomee 992fb3fb4f3Stomee private synchronized void checkGoCalled()993fb3fb4f3Stomee checkGoCalled() 994fb3fb4f3Stomee { 995fb3fb4f3Stomee switch (state) { 996fb3fb4f3Stomee case INIT: 997fb3fb4f3Stomee throw new IllegalStateException("consumer not open"); 998fb3fb4f3Stomee case OPEN: 999fb3fb4f3Stomee case COMPILED: 1000fb3fb4f3Stomee throw new IllegalStateException("go() not called"); 1001fb3fb4f3Stomee case GO: 1002fb3fb4f3Stomee case STARTED: 1003fb3fb4f3Stomee case STOPPED: 1004fb3fb4f3Stomee break; 1005fb3fb4f3Stomee case CLOSED: 1006fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 1007fb3fb4f3Stomee } 1008fb3fb4f3Stomee } 1009fb3fb4f3Stomee 1010fb3fb4f3Stomee private synchronized void checkGoNotCalled()1011fb3fb4f3Stomee checkGoNotCalled() 1012fb3fb4f3Stomee { 1013fb3fb4f3Stomee switch (state) { 1014fb3fb4f3Stomee case INIT: 1015fb3fb4f3Stomee throw new IllegalStateException("consumer not open"); 1016fb3fb4f3Stomee case OPEN: 1017fb3fb4f3Stomee case COMPILED: 1018fb3fb4f3Stomee break; 1019fb3fb4f3Stomee case GO: 1020fb3fb4f3Stomee case STARTED: 1021fb3fb4f3Stomee throw new IllegalStateException("go() already called"); 1022fb3fb4f3Stomee case STOPPED: 1023fb3fb4f3Stomee throw new IllegalStateException("consumer stopped"); 1024fb3fb4f3Stomee case CLOSED: 1025fb3fb4f3Stomee throw new IllegalStateException("consumer closed"); 1026fb3fb4f3Stomee } 1027fb3fb4f3Stomee } 1028fb3fb4f3Stomee 1029fb3fb4f3Stomee public synchronized int createProcess(String command)1030fb3fb4f3Stomee createProcess(String command) throws DTraceException 1031fb3fb4f3Stomee { 1032fb3fb4f3Stomee if (command == null) { 1033fb3fb4f3Stomee throw new NullPointerException("command is null"); 1034fb3fb4f3Stomee } 1035fb3fb4f3Stomee 1036fb3fb4f3Stomee checkGoNotCalled(); 1037fb3fb4f3Stomee 1038fb3fb4f3Stomee int pid; 1039fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1040fb3fb4f3Stomee pid = _createProcess(command); 1041fb3fb4f3Stomee } 1042fb3fb4f3Stomee return pid; 1043fb3fb4f3Stomee } 1044fb3fb4f3Stomee 1045fb3fb4f3Stomee public synchronized void grabProcess(int pid)1046fb3fb4f3Stomee grabProcess(int pid) throws DTraceException 1047fb3fb4f3Stomee { 1048fb3fb4f3Stomee checkGoNotCalled(); 1049fb3fb4f3Stomee 1050fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1051fb3fb4f3Stomee _grabProcess(pid); 1052fb3fb4f3Stomee } 1053fb3fb4f3Stomee } 1054fb3fb4f3Stomee 1055fb3fb4f3Stomee public synchronized List <ProbeDescription> listProbes(ProbeDescription filter)1056fb3fb4f3Stomee listProbes(ProbeDescription filter) throws DTraceException 1057fb3fb4f3Stomee { 1058fb3fb4f3Stomee checkGoNotCalled(); 1059fb3fb4f3Stomee List <ProbeDescription> probeList = 1060fb3fb4f3Stomee new LinkedList <ProbeDescription> (); 1061fb3fb4f3Stomee if (filter == ProbeDescription.EMPTY) { 1062fb3fb4f3Stomee filter = null; 1063fb3fb4f3Stomee } 1064fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1065fb3fb4f3Stomee _listProbes(probeList, filter); 1066fb3fb4f3Stomee } 1067fb3fb4f3Stomee return probeList; 1068fb3fb4f3Stomee } 1069fb3fb4f3Stomee 1070fb3fb4f3Stomee public synchronized List <Probe> listProbeDetail(ProbeDescription filter)1071fb3fb4f3Stomee listProbeDetail(ProbeDescription filter) throws DTraceException 1072fb3fb4f3Stomee { 1073fb3fb4f3Stomee checkGoNotCalled(); 1074fb3fb4f3Stomee List <Probe> probeList = new LinkedList <Probe> (); 1075fb3fb4f3Stomee if (filter == ProbeDescription.EMPTY) { 1076fb3fb4f3Stomee filter = null; 1077fb3fb4f3Stomee } 1078fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1079fb3fb4f3Stomee _listProbeDetail(probeList, filter); 1080fb3fb4f3Stomee } 1081fb3fb4f3Stomee return probeList; 1082fb3fb4f3Stomee } 1083fb3fb4f3Stomee 1084fb3fb4f3Stomee public synchronized List <ProbeDescription> listProgramProbes(Program program)1085fb3fb4f3Stomee listProgramProbes(Program program) throws DTraceException 1086fb3fb4f3Stomee { 1087fb3fb4f3Stomee checkProgram(program); 1088fb3fb4f3Stomee checkGoNotCalled(); 1089fb3fb4f3Stomee List <ProbeDescription> probeList = 1090fb3fb4f3Stomee new LinkedList <ProbeDescription> (); 1091fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1092fb3fb4f3Stomee _listCompiledProbes(probeList, program); 1093fb3fb4f3Stomee } 1094fb3fb4f3Stomee return probeList; 1095fb3fb4f3Stomee } 1096fb3fb4f3Stomee 1097fb3fb4f3Stomee public synchronized List <Probe> listProgramProbeDetail(Program program)1098fb3fb4f3Stomee listProgramProbeDetail(Program program) throws DTraceException 1099fb3fb4f3Stomee { 1100fb3fb4f3Stomee checkProgram(program); 1101fb3fb4f3Stomee checkGoNotCalled(); 1102fb3fb4f3Stomee List <Probe> probeList = new LinkedList <Probe> (); 1103fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1104fb3fb4f3Stomee _listCompiledProbeDetail(probeList, program); 1105fb3fb4f3Stomee } 1106fb3fb4f3Stomee return probeList; 1107fb3fb4f3Stomee } 1108fb3fb4f3Stomee 1109fb3fb4f3Stomee public synchronized String lookupKernelFunction(int address)1110fb3fb4f3Stomee lookupKernelFunction(int address) 1111fb3fb4f3Stomee { 1112fb3fb4f3Stomee checkGoCalled(); 1113fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1114fb3fb4f3Stomee return _lookupKernelFunction(new Integer(address)); 1115fb3fb4f3Stomee } 1116fb3fb4f3Stomee } 1117fb3fb4f3Stomee 1118fb3fb4f3Stomee public synchronized String lookupKernelFunction(long address)1119fb3fb4f3Stomee lookupKernelFunction(long address) 1120fb3fb4f3Stomee { 1121fb3fb4f3Stomee checkGoCalled(); 1122fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1123fb3fb4f3Stomee return _lookupKernelFunction(new Long(address)); 1124fb3fb4f3Stomee } 1125fb3fb4f3Stomee } 1126fb3fb4f3Stomee 1127fb3fb4f3Stomee public synchronized String lookupUserFunction(int pid, int address)1128fb3fb4f3Stomee lookupUserFunction(int pid, int address) 1129fb3fb4f3Stomee { 1130fb3fb4f3Stomee checkGoCalled(); 1131fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1132fb3fb4f3Stomee return _lookupUserFunction(pid, new Integer(address)); 1133fb3fb4f3Stomee } 1134fb3fb4f3Stomee } 1135fb3fb4f3Stomee 1136fb3fb4f3Stomee public synchronized String lookupUserFunction(int pid, long address)1137fb3fb4f3Stomee lookupUserFunction(int pid, long address) 1138fb3fb4f3Stomee { 1139fb3fb4f3Stomee checkGoCalled(); 1140fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1141fb3fb4f3Stomee return _lookupUserFunction(pid, new Long(address)); 1142fb3fb4f3Stomee } 1143fb3fb4f3Stomee } 1144fb3fb4f3Stomee 1145fb3fb4f3Stomee public String getVersion()1146fb3fb4f3Stomee getVersion() 1147fb3fb4f3Stomee { 1148fb3fb4f3Stomee synchronized (LocalConsumer.class) { 1149fb3fb4f3Stomee return LocalConsumer._getVersion(); 1150fb3fb4f3Stomee } 1151fb3fb4f3Stomee } 1152fb3fb4f3Stomee 1153fb3fb4f3Stomee /** 1154fb3fb4f3Stomee * Called by native code. 1155fb3fb4f3Stomee */ 1156fb3fb4f3Stomee private void nextProbeData(ProbeData probeData)1157fb3fb4f3Stomee nextProbeData(ProbeData probeData) throws ConsumerException 1158fb3fb4f3Stomee { 1159fb3fb4f3Stomee fireDataReceived(new DataEvent(this, probeData)); 1160fb3fb4f3Stomee } 1161fb3fb4f3Stomee 1162fb3fb4f3Stomee /** 1163fb3fb4f3Stomee * Called by native code. 1164fb3fb4f3Stomee */ 1165fb3fb4f3Stomee private void dataDropped(Drop drop)1166fb3fb4f3Stomee dataDropped(Drop drop) throws ConsumerException 1167fb3fb4f3Stomee { 1168fb3fb4f3Stomee fireDataDropped(new DropEvent(this, drop)); 1169fb3fb4f3Stomee } 1170fb3fb4f3Stomee 1171fb3fb4f3Stomee /** 1172fb3fb4f3Stomee * Called by native code. 1173fb3fb4f3Stomee */ 1174fb3fb4f3Stomee private void errorEncountered(Error error)1175fb3fb4f3Stomee errorEncountered(Error error) throws ConsumerException 1176fb3fb4f3Stomee { 1177fb3fb4f3Stomee fireErrorEncountered(new ErrorEvent(this, error)); 1178fb3fb4f3Stomee } 1179fb3fb4f3Stomee 1180fb3fb4f3Stomee /** 1181fb3fb4f3Stomee * Called by native code. 1182fb3fb4f3Stomee */ 1183fb3fb4f3Stomee private void processStateChanged(ProcessState processState)1184fb3fb4f3Stomee processStateChanged(ProcessState processState) throws ConsumerException 1185fb3fb4f3Stomee { 1186fb3fb4f3Stomee fireProcessStateChanged(new ProcessEvent(this, processState)); 1187fb3fb4f3Stomee } 1188fb3fb4f3Stomee 1189fb3fb4f3Stomee protected void fireDataReceived(DataEvent e)1190fb3fb4f3Stomee fireDataReceived(DataEvent e) throws ConsumerException 1191fb3fb4f3Stomee { 1192fb3fb4f3Stomee // Guaranteed to return a non-null array 1193fb3fb4f3Stomee Object[] listeners = listenerList.getListenerList(); 1194fb3fb4f3Stomee // Process the listeners last to first, notifying 1195fb3fb4f3Stomee // those that are interested in this event 1196fb3fb4f3Stomee for (int i = listeners.length - 2; i >= 0; i -= 2) { 1197fb3fb4f3Stomee if (listeners[i] == ConsumerListener.class) { 1198fb3fb4f3Stomee ((ConsumerListener)listeners[i + 1]).dataReceived(e); 1199fb3fb4f3Stomee } 1200fb3fb4f3Stomee } 1201fb3fb4f3Stomee } 1202fb3fb4f3Stomee 1203fb3fb4f3Stomee protected void fireDataDropped(DropEvent e)1204fb3fb4f3Stomee fireDataDropped(DropEvent e) throws ConsumerException 1205fb3fb4f3Stomee { 1206fb3fb4f3Stomee // Guaranteed to return a non-null array 1207fb3fb4f3Stomee Object[] listeners = listenerList.getListenerList(); 1208fb3fb4f3Stomee // Process the listeners last to first, notifying 1209fb3fb4f3Stomee // those that are interested in this event 1210fb3fb4f3Stomee for (int i = listeners.length - 2; i >= 0; i -= 2) { 1211fb3fb4f3Stomee if (listeners[i] == ConsumerListener.class) { 1212fb3fb4f3Stomee ((ConsumerListener)listeners[i + 1]).dataDropped(e); 1213fb3fb4f3Stomee } 1214fb3fb4f3Stomee } 1215fb3fb4f3Stomee } 1216fb3fb4f3Stomee 1217fb3fb4f3Stomee protected void fireErrorEncountered(ErrorEvent e)1218fb3fb4f3Stomee fireErrorEncountered(ErrorEvent e) throws ConsumerException 1219fb3fb4f3Stomee { 1220fb3fb4f3Stomee // Guaranteed to return a non-null array 1221fb3fb4f3Stomee Object[] listeners = listenerList.getListenerList(); 1222fb3fb4f3Stomee // Process the listeners last to first, notifying 1223fb3fb4f3Stomee // those that are interested in this event 1224fb3fb4f3Stomee for (int i = listeners.length - 2; i >= 0; i -= 2) { 1225fb3fb4f3Stomee if (listeners[i] == ConsumerListener.class) { 1226fb3fb4f3Stomee ((ConsumerListener)listeners[i + 1]).errorEncountered(e); 1227fb3fb4f3Stomee } 1228fb3fb4f3Stomee } 1229fb3fb4f3Stomee } 1230fb3fb4f3Stomee 1231fb3fb4f3Stomee protected void fireProcessStateChanged(ProcessEvent e)1232fb3fb4f3Stomee fireProcessStateChanged(ProcessEvent e) throws ConsumerException 1233fb3fb4f3Stomee { 1234fb3fb4f3Stomee // Guaranteed to return a non-null array 1235fb3fb4f3Stomee Object[] listeners = listenerList.getListenerList(); 1236fb3fb4f3Stomee // Process the listeners last to first, notifying 1237fb3fb4f3Stomee // those that are interested in this event 1238fb3fb4f3Stomee for (int i = listeners.length - 2; i >= 0; i -= 2) { 1239fb3fb4f3Stomee if (listeners[i] == ConsumerListener.class) { 1240fb3fb4f3Stomee ((ConsumerListener)listeners[i + 1]).processStateChanged(e); 1241fb3fb4f3Stomee } 1242fb3fb4f3Stomee } 1243fb3fb4f3Stomee } 1244fb3fb4f3Stomee 1245fb3fb4f3Stomee protected void fireConsumerStarted(ConsumerEvent e)1246fb3fb4f3Stomee fireConsumerStarted(ConsumerEvent e) 1247fb3fb4f3Stomee { 1248fb3fb4f3Stomee // Guaranteed to return a non-null array 1249fb3fb4f3Stomee Object[] listeners = listenerList.getListenerList(); 1250fb3fb4f3Stomee // Process the listeners last to first, notifying 1251fb3fb4f3Stomee // those that are interested in this event 1252fb3fb4f3Stomee for (int i = listeners.length - 2; i >= 0; i -= 2) { 1253fb3fb4f3Stomee if (listeners[i] == ConsumerListener.class) { 1254fb3fb4f3Stomee ((ConsumerListener)listeners[i + 1]).consumerStarted(e); 1255fb3fb4f3Stomee } 1256fb3fb4f3Stomee } 1257fb3fb4f3Stomee } 1258fb3fb4f3Stomee 1259fb3fb4f3Stomee protected void fireConsumerStopped(ConsumerEvent e)1260fb3fb4f3Stomee fireConsumerStopped(ConsumerEvent e) 1261fb3fb4f3Stomee { 1262fb3fb4f3Stomee // Guaranteed to return a non-null array 1263fb3fb4f3Stomee Object[] listeners = listenerList.getListenerList(); 1264fb3fb4f3Stomee // Process the listeners last to first, notifying 1265fb3fb4f3Stomee // those that are interested in this event 1266fb3fb4f3Stomee for (int i = listeners.length - 2; i >= 0; i -= 2) { 1267fb3fb4f3Stomee if (listeners[i] == ConsumerListener.class) { 1268fb3fb4f3Stomee ((ConsumerListener)listeners[i + 1]).consumerStopped(e); 1269fb3fb4f3Stomee } 1270fb3fb4f3Stomee } 1271fb3fb4f3Stomee } 1272fb3fb4f3Stomee 1273fb3fb4f3Stomee // Called by native code 1274fb3fb4f3Stomee private void intervalBegan()1275fb3fb4f3Stomee intervalBegan() 1276fb3fb4f3Stomee { 1277fb3fb4f3Stomee fireIntervalBegan(new ConsumerEvent(this, System.nanoTime())); 1278fb3fb4f3Stomee } 1279fb3fb4f3Stomee 1280fb3fb4f3Stomee protected void fireIntervalBegan(ConsumerEvent e)1281fb3fb4f3Stomee fireIntervalBegan(ConsumerEvent e) 1282fb3fb4f3Stomee { 1283fb3fb4f3Stomee // Guaranteed to return a non-null array 1284fb3fb4f3Stomee Object[] listeners = listenerList.getListenerList(); 1285fb3fb4f3Stomee // Process the listeners last to first, notifying 1286fb3fb4f3Stomee // those that are interested in this event 1287fb3fb4f3Stomee for (int i = listeners.length - 2; i >= 0; i -= 2) { 1288fb3fb4f3Stomee if (listeners[i] == ConsumerListener.class) { 1289fb3fb4f3Stomee ((ConsumerListener)listeners[i + 1]).intervalBegan(e); 1290fb3fb4f3Stomee } 1291fb3fb4f3Stomee } 1292fb3fb4f3Stomee } 1293fb3fb4f3Stomee 1294fb3fb4f3Stomee // Called by native code 1295fb3fb4f3Stomee private void intervalEnded()1296fb3fb4f3Stomee intervalEnded() 1297fb3fb4f3Stomee { 1298fb3fb4f3Stomee fireIntervalEnded(new ConsumerEvent(this, System.nanoTime())); 1299fb3fb4f3Stomee } 1300fb3fb4f3Stomee 1301fb3fb4f3Stomee protected void fireIntervalEnded(ConsumerEvent e)1302fb3fb4f3Stomee fireIntervalEnded(ConsumerEvent e) 1303fb3fb4f3Stomee { 1304fb3fb4f3Stomee // Guaranteed to return a non-null array 1305fb3fb4f3Stomee Object[] listeners = listenerList.getListenerList(); 1306fb3fb4f3Stomee // Process the listeners last to first, notifying 1307fb3fb4f3Stomee // those that are interested in this event 1308fb3fb4f3Stomee for (int i = listeners.length - 2; i >= 0; i -= 2) { 1309fb3fb4f3Stomee if (listeners[i] == ConsumerListener.class) { 1310fb3fb4f3Stomee ((ConsumerListener)listeners[i + 1]).intervalEnded(e); 1311fb3fb4f3Stomee } 1312fb3fb4f3Stomee } 1313fb3fb4f3Stomee } 1314fb3fb4f3Stomee 1315fb3fb4f3Stomee /** 1316fb3fb4f3Stomee * Gets a string representation of this consumer useful for logging 1317fb3fb4f3Stomee * and not intended for display. The exact details of the 1318fb3fb4f3Stomee * representation are unspecified and subject to change, but the 1319fb3fb4f3Stomee * following format may be regarded as typical: 1320fb3fb4f3Stomee * <pre><code> 1321fb3fb4f3Stomee * class-name[property1 = value1, property2 = value2] 1322fb3fb4f3Stomee * </code></pre> 1323fb3fb4f3Stomee */ 1324fb3fb4f3Stomee public String toString()1325fb3fb4f3Stomee toString() 1326fb3fb4f3Stomee { 13274ae67516Stomee StringBuilder buf = new StringBuilder(LocalConsumer.class.getName()); 1328fb3fb4f3Stomee synchronized (this) { 1329fb3fb4f3Stomee buf.append("[open = "); 1330fb3fb4f3Stomee buf.append(isOpen()); 1331fb3fb4f3Stomee buf.append(", enabled = "); 1332fb3fb4f3Stomee buf.append(isEnabled()); 1333fb3fb4f3Stomee buf.append(", running = "); 1334fb3fb4f3Stomee buf.append(isRunning()); 1335fb3fb4f3Stomee buf.append(", closed = "); 1336fb3fb4f3Stomee buf.append(isClosed()); 1337fb3fb4f3Stomee } 1338fb3fb4f3Stomee buf.append(']'); 1339fb3fb4f3Stomee return buf.toString(); 1340fb3fb4f3Stomee } 1341fb3fb4f3Stomee 1342fb3fb4f3Stomee /** 1343fb3fb4f3Stomee * Ensures that the {@link #close()} method of this consumer has 1344fb3fb4f3Stomee * been called before it is garbage-collected. The intended safety 1345fb3fb4f3Stomee * net is weak because the JVM does not guarantee that an object 1346fb3fb4f3Stomee * will be garbage-collected when it is no longer referenced. Users 1347fb3fb4f3Stomee * of the API should call {@code close()} to ensure that all 1348fb3fb4f3Stomee * resources associated with this consumer are reclaimed in a timely 1349fb3fb4f3Stomee * manner. 1350fb3fb4f3Stomee * 1351fb3fb4f3Stomee * @see #close() 1352fb3fb4f3Stomee */ 1353fb3fb4f3Stomee protected void finalize()1354fb3fb4f3Stomee finalize() 1355fb3fb4f3Stomee { 1356fb3fb4f3Stomee close(); 1357fb3fb4f3Stomee } 1358fb3fb4f3Stomee 1359fb3fb4f3Stomee private String getTag()1360fb3fb4f3Stomee getTag() 1361fb3fb4f3Stomee { 1362fb3fb4f3Stomee return super.toString(); 1363fb3fb4f3Stomee } 1364fb3fb4f3Stomee 1365fb3fb4f3Stomee // 1366fb3fb4f3Stomee // Uniquely identifies a consumer across systems so it is possible 1367fb3fb4f3Stomee // to validate that an object such as a Program passed to a remote 1368fb3fb4f3Stomee // client over a socket was created by this consumer and no other. 1369fb3fb4f3Stomee // 1370fb3fb4f3Stomee static class Identifier implements Serializable { 1371fb3fb4f3Stomee static final long serialVersionUID = 2183165132305302834L; 1372fb3fb4f3Stomee 1373fb3fb4f3Stomee // local identifier 1374fb3fb4f3Stomee private int id; 1375fb3fb4f3Stomee private long timestamp; 1376fb3fb4f3Stomee // remote identifier 1377fb3fb4f3Stomee private InetAddress localHost; 1378fb3fb4f3Stomee private String tag; // in case localHost not available 1379fb3fb4f3Stomee 1380fb3fb4f3Stomee private Identifier(LocalConsumer consumer)1381fb3fb4f3Stomee Identifier(LocalConsumer consumer) 1382fb3fb4f3Stomee { 1383fb3fb4f3Stomee id = LocalConsumer.sequence++; 1384fb3fb4f3Stomee timestamp = System.currentTimeMillis(); 1385fb3fb4f3Stomee try { 1386fb3fb4f3Stomee localHost = InetAddress.getLocalHost(); 1387fb3fb4f3Stomee } catch (UnknownHostException e) { 1388fb3fb4f3Stomee localHost = null; 1389fb3fb4f3Stomee } 1390fb3fb4f3Stomee tag = consumer.getTag(); 1391fb3fb4f3Stomee } 1392fb3fb4f3Stomee 1393fb3fb4f3Stomee @Override 1394fb3fb4f3Stomee public boolean equals(Object o)1395fb3fb4f3Stomee equals(Object o) 1396fb3fb4f3Stomee { 1397fb3fb4f3Stomee if (o == this) { 1398fb3fb4f3Stomee return true; 1399fb3fb4f3Stomee } 1400fb3fb4f3Stomee if (o instanceof Identifier) { 1401fb3fb4f3Stomee Identifier i = (Identifier)o; 1402fb3fb4f3Stomee return ((id == i.id) && 1403fb3fb4f3Stomee (timestamp == i.timestamp) && 1404fb3fb4f3Stomee ((localHost == null) ? (i.localHost == null) : 1405fb3fb4f3Stomee localHost.equals(i.localHost)) && 1406fb3fb4f3Stomee tag.equals(i.tag)); 1407fb3fb4f3Stomee } 1408fb3fb4f3Stomee return false; 1409fb3fb4f3Stomee } 1410fb3fb4f3Stomee 1411fb3fb4f3Stomee @Override 1412fb3fb4f3Stomee public int hashCode()1413fb3fb4f3Stomee hashCode() 1414fb3fb4f3Stomee { 1415fb3fb4f3Stomee int hash = 17; 1416fb3fb4f3Stomee hash = (37 * hash) + id; 1417fb3fb4f3Stomee hash = (37 * hash) + ((int)(timestamp ^ (timestamp >>> 32))); 1418fb3fb4f3Stomee hash = (37 * hash) + (localHost == null ? 0 : 1419fb3fb4f3Stomee localHost.hashCode()); 1420fb3fb4f3Stomee hash = (37 * hash) + tag.hashCode(); 1421fb3fb4f3Stomee return hash; 1422fb3fb4f3Stomee } 1423fb3fb4f3Stomee 1424fb3fb4f3Stomee @Override 1425fb3fb4f3Stomee public String toString()1426fb3fb4f3Stomee toString() 1427fb3fb4f3Stomee { 14284ae67516Stomee StringBuilder buf = new StringBuilder(); 1429fb3fb4f3Stomee buf.append(Identifier.class.getName()); 1430fb3fb4f3Stomee buf.append("[id = "); 1431fb3fb4f3Stomee buf.append(id); 1432fb3fb4f3Stomee buf.append(", timestamp = "); 1433fb3fb4f3Stomee buf.append(timestamp); 1434fb3fb4f3Stomee buf.append(", localHost = "); 1435fb3fb4f3Stomee buf.append(localHost); 1436fb3fb4f3Stomee buf.append(", tag = "); 1437fb3fb4f3Stomee buf.append(tag); 1438fb3fb4f3Stomee buf.append(']'); 1439fb3fb4f3Stomee return buf.toString(); 1440fb3fb4f3Stomee } 1441fb3fb4f3Stomee } 1442fb3fb4f3Stomee } 1443