2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A#
pragma ident "%Z%%M% %I% %E% SMI" 2N/A * Implements the work done in the running consumer loop. The native Java 2N/A/* Record handler passed to dtrace_work() */ 2N/A/* Probe data handler passed to dtrace_work() */ 2N/A/* Processes requests from LocalConsumer enqueued during dtrace_sleep() */ 2N/A * Callback handlers set in dtj_set_callback_handlers(), called from libdtrace 2N/A * in the consumer loop (from dtrace_work()) 2N/A * Buffered output handler called from libdtrace in both the consumer loop (from 2N/A * dtrace_work()) and the get_aggregate() function (from 2N/A * dtrace_aggregate_print()). 2N/A/* Conversion of libdtrace data into Java Objects */ 2N/A/* Aggregation data */ 2N/A/* Aggregation functions */ 2N/A * The consumer loop needs to protect calls to libdtrace functions with a global 2N/A * lock. JNI native method calls in dtrace_jni.c are already protected and do 2N/A * not need this function. 2N/A /* Must not call MonitorEnter with a pending exception */ 2N/A /* Grab global lock */ 2N/A * Java_org_opensolaris_os_dtrace_LocalConsumer__1go() 2N/A "failed to establish buffered handler: %s",
2N/A "failed to establish drop handler: %s",
2N/A "failed to establish error handler: %s",
2N/A "failed to establish proc handler: %s",
2N/A "couldn't get option %s: %s",
"flowindent",
2N/A "failed to establish setopt handler: %s",
2N/A * Since the function signature does not allow us to return an abort signal, we 2N/A * need to temporarily clear any pending exception before returning, since 2N/A * without the abort we can't guarantee that the exception will be checked in 2N/A * time to prevent invalid JNI function calls. 2N/A * PS_DEAD not handled by dtrace.c prochandler, still this is a 2N/A * case of process termination and it can't hurt to handle it. 2N/A * Unexpected, but erring on the side of tolerance by not 2N/A * crashing the consumer. Failure to notify listeners of 2N/A * process state not handled by the dtrace.c prochandler does 2N/A /* valid exit status */ 2N/A * Save the exception so we can rethrow it later when it's safe. 2N/A * If the byte stream is a series of printable characters, followed by 2N/A * a terminating byte, we print it out as a string. Otherwise, we 2N/A * assume that it's something else and just print the bytes. 2N/A * We define a "printable character" to be one for which 2N/A * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 2N/A * or a character which is either backspace or the bell. 2N/A * Backspace and the bell are regrettably special because 2N/A * they fail the first two tests -- and yet they are entirely 2N/A * printable. These are the only two control characters that 2N/A * have meaning for the terminal and for which isprint(3C) and 2N/A * isspace(3C) return 0. 2N/A c[i] ==
'\b' || c[i] ==
'\a')
2N/A if (c[i] ==
'\0' && i > 0) {
2N/A * This looks like it might be a string. Before we 2N/A * assume that it is indeed a string, check the 2N/A * remainder of the byte range; if it contains 2N/A * additional non-nul characters, we'll assume that 2N/A * it's a binary stream that just happens to look like 2N/A * The byte range is all printable characters, but there is 2N/A * no trailing nul byte. We'll assume that it's a string. 2N/A "failed to allocate string value");
2N/A /* return byte array */ 2N/A * Return NULL if memory could not be allocated (OutOfMemoryError is thrown in 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A return (
NULL);
/* OutOfMemoryError pending */ 2N/A * This is the record handling function passed to dtrace_work(). It differs 2N/A * from the bufhandler registered with dtrace_handle_buffered() as follows: 2N/A * 1. It does not have access to libdtrace formatted output. 2N/A * 2. It is called once for every D program statement, not for every 2N/A * output-producing D action or aggregation record. A statement may be a 2N/A * variable assignment, having no size and producing no output. 2N/A * 3. It is called for the D exit() action; the bufhandler is not. 2N/A * 4. In response to the printa() action, it is called with a record having an 2N/A * action of type DTRACEACT_PRINTA. The bufhandler never sees that action 2N/A * value. It only sees the output-producing aggregation records. 2N/A * 5. It is called with a NULL record at the end of each probedata. 2N/A * Update the record index to that of the current record, or to that of 2N/A * the last record if rec is NULL (signalling end of probe data). 2N/A * This record handler is called once for the printf() action, 2N/A * but there may be multiple records in the probedata 2N/A * corresponding to the unformatted elements of that printf(). 2N/A * We don't know ahead of time how many probedata records 2N/A * libdtrace will consume to produce output for one printf() 2N/A * action, so we look back at the previous call to dtj_chewrec() 2N/A * to see how many probedata records were consumed. All 2N/A * non-null elements in the range from the previous record index 2N/A * up to and not including the current record index are assumed 2N/A * to be unformatted printf() elements, and will be attached to 2N/A * the PrintfRecord from the previous call. A null element in 2N/A * that range is the result of a D program statement preceding 2N/A * the printf() that is not a D action. These generate 2N/A * probedata records accounted for by the null placeholder, but 2N/A * do not advance the probedata offset and are not part of the 2N/A * subsequent printf(). 2N/A * If rec->dtrd_size == 0, the record represents a D program 2N/A * statement that is not a D action. It has no size and does 2N/A * not advance the offset in the probedata. Handle it normally 2N/A * without special-casing or premature return, since in all 2N/A * cases we look at the previous record later in this function. 2N/A * Attach the Java representations of the libdtrace data elements 2N/A * pertaining to the previous call to this record handler to the 2N/A * previous Java Record. (All data elements belonging to the current 2N/A * probedata are added to a single list by the probedata consumer 2N/A * function dtj_chew() before this record consumer function is ever 2N/A * called.) For example, if the previous Record was generated by the 2N/A * printf() action, and dtj_chew() listed 3 records for its 3 2N/A * unformatted elements, those 3 libdtrace records comprise 1 2N/A * PrintfRecord. Note that we cannot know how many data elements apply 2N/A * to the current rec until we find out the data index where the next 2N/A * rec starts. (The knowledge of how many probedata records to consume 2N/A * is private to libdtrace.) 2N/A * End of probe data. Notify listeners of the new ProbeData 2N/A /* previous probedata */ 2N/A * Do not wrap exception thrown from 2N/A /* Set previous record action and data index to current */ 2N/A * The current record is not a D action, but a program 2N/A * statement such as a variable assignment, not to be 2N/A * confused with the trace() action. 2N/A * Add a Record for the trace() action that references the 2N/A * native probedata element listed at the current index. 2N/A * Just add an empty PrintfRecord for now. We'll attach the 2N/A * unformatted elements in a subsequent call to this function. 2N/A * (We don't know how many there will be.) 2N/A /* defer formatted string to dtj_bufhandler() */ 2N/A * Create a StringBuilder to collect the pieces of 2N/A * formatted output into a single String. 2N/A /* OutOfMemoryError pending */ 2N/A /* defer aggregation records to dtj_bufhandler() */ 2N/A * Add a Record for the exit() action that references the native 2N/A * probedata element listed at the current index. 2N/A * This is the probe handling function passed to dtrace_work(). It is is called 2N/A * once every time a probe fires. It is the first of all the callbacks for the 2N/A * current probe. It is followed by multiple callbacks to dtj_chewrec(), one 2N/A * for each probedata record. Each call to dtj_chewrec() is followed by zero or 2N/A * more callbacks to the bufhandler, one for each output-producing action or 2N/A * aggregation record. 2N/A /* java exception pending */ 2N/A * Use the knowledge that libdtrace indents 2 spaces per 2N/A * level in the call stack to calculate the depth. 2N/A /* Create ProbeData instance */ 2N/A * Populate the ProbeData list of Java data elements in advance so we 2N/A * don't need to peek back in the record handler at libdtrace records 2N/A * that have already been consumed. In the Java API, each ProbeData 2N/A * Record is generated by one D action, while in the native libdtrace 2N/A * there may be more than one probedata record (each a single data 2N/A * element) per D action. For example PrintfRecord has multiple 2N/A * unformatted elements, each represented by a native probedata record, 2N/A * but combined by the API into a single PrintfRecord. 2N/A * A statement that is not a D action, such as assignment to a 2N/A * variable, has no size. Add a NULL placeholder to the scratch 2N/A * list of Java probedata elements in that case. 2N/A /* Initialize per-consumer probedata fields */ 2N/A * This is the buffered output handler registered with dtrace_handle_buffered(). 2N/A * It's purpose is to make the output of the libdtrace print routines available 2N/A * to this API, without writing any of it to a file (such as stdout). This is 2N/A * needed for the stack(), ustack(), and jstack() actions to get human-readable 2N/A * stack values, since there is no public function in libdtrace to convert stack 2N/A * values to strings. It is also used to get the formatted output of the D 2N/A * printf() and printa() actions. 2N/A * The bufhandler is called once for each output-producing, non-aggregating D 2N/A * action, such as trace() or printf(), and once for each libdtrace aggregation 2N/A * record (whether in response to the D printa() action, or the Consumer 2N/A * getAggregate() method). In the simple printa() case that takes one 2N/A * aggregation and does not specify a format string, there is one libdtrace 2N/A * record per tuple element plus one for the corresponding value. The complete 2N/A * tuple/value pair becomes a single AggregationRecord exported by the API. 2N/A * When multiple aggregations are passed to printa(), each tuple is associated 2N/A * with a list of values, one from each aggregation. If a printa() format 2N/A * string does not specify placeholders for every aggregation value and tuple 2N/A * member, callbacks for those values and tuple members are omitted (and the 2N/A * data is omitted from the resulting PrintaRecord). 2N/A * Notes to characterize some non-obvious bufhandler behavior: 2N/A * 1. dtj_bufhandler() is never called with bufdata->dtbda_recdesc->dtrd_action 2N/A * DTRACEACT_PRINTA. That action only appears in the probedata consumer 2N/A * functions dtj_chew() and dtj_chewrec() before the bufhandler is called with 2N/A * subsequent aggregation records. 2N/A * 2. If printa() specifies a format string argument, then the bufhandler is 2N/A * called only for those elements of the tuple/value pair that are included in 2N/A * the format string. If a stack() tuple member is omitted from the format 2N/A * string, its human-readable representation will not be available to this API, 2N/A * so the stack frame array is also omitted from the resulting 2N/A * AggregationRecord. The bufhandler is also called once for each string of 2N/A * characters surrounding printa() format string placeholders. For example, 2N/A * " %@d %d stack%k\n" results in the following callbacks: 2N/A * - the aggregation value 2N/A * - the first tuple member (an integer) 2N/A * - the second tuple member (a stack) 2N/A * A NULL record (NULL dtbda_recdesc) distinguishes a callback with interstitial 2N/A * format string characters from a callback with a tuple member or aggregation 2N/A * value (which has a non-NULL recdesc). The contents are also distinguished by 2N/A * the following flags: 2N/A * DTRACE_BUFDATA_AGGKEY 2N/A * DTRACE_BUFDATA_AGGVAL 2N/A * DTRACE_BUFDATA_AGGFORMAT 2N/A * DTRACE_BUFDATA_AGGLAST 2N/A * There is no final callback with the complete formatted string, so that must 2N/A * be concatenated across multiple callbacks to the bufhandler. 2N/A * 3. bufdata->dtbda_probe->dtpda_data may be overwritten by libdtrace print 2N/A * routines. The address is cached in the dtj_chew() function in case it is 2N/A * needed in the bufhandler. 2N/A * Get the thread-specific java consumer. The bufhandler needs access 2N/A * to the correct JNI state specific to either the consumer loop or the 2N/A * getAggregate() call (aggregation snapshots can be requested 2N/A * asynchronously while the consumer loop generates PrintaRecords in 2N/A * dtrace_work() for ConsumerListeners). 2N/A * In at least one corner case (printa with multiple aggregations and a 2N/A * format string that does not completely specify the tuple), returning 2N/A * DTRACE_HANDLE_ABORT does not prevent a subsequent callback to this 2N/A * bufhandler. This check ensures that the invalid call is ignored. 2N/A /* trace() action */ 2N/A * Only the formatted string was not available to dtj_chewrec(), 2N/A * so we attach that now. 2N/A /* stand-alone stack(), ustack(), or jstack() action */ 2N/A /* OutOfMemoryError pending */ 2N/A /* stand-alone symbol lookup action */ 2N/A /* OutOfMemoryError pending */ 2N/A * The record handler dtj_chewrec() defers nothing else to this 2N/A * Called by get_aggregate() to clear only those aggregations specified by the 2N/A /* java exception pending */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A /* LINTED - alignment */ 2N/A * Return NULL if a java exception is pending, otherwise return a new 2N/A * StddevValue instance. 2N/A /* Get raw stack data */ 2N/A /* Get raw stack data */ 2N/A return (
NULL);
/* java exception pending */ 2N/A return (
NULL);
/* java exception pending */ 2N/A /* Get symbol lookup */ 2N/A /* OutOfMemoryError pending */ 2N/A /* Trim leading and trailing whitespace */ 2N/A /* trim() returns a new string; don't leak the old one */ 2N/A/* Caller must be holding per-consumer lock */ 2N/A /* assert without crashing */ 2N/A "stale aggregation tuple");
2N/A int size;
/* size of raw bytes not including trailing zeros */ 2N/A int i;
/* index of last non-zero byte */ 2N/A /* trim trailing zeros */ 2N/A return (
NULL);
/* OutOfMemoryError pending */ 2N/A /* Create StackValueRecord instance from raw stack data */ 2N/A /* Get pid of user process */ 2N/A "Expected stack action, got %d\n",
act);
2N/A /* LINTED - alignment */ 2N/A /* Get pid of user process */ 2N/A "Expected stack action, got %d\n",
act);
2N/A * Return NULL if java exception pending, otherwise return Distribution value. 2N/A /* LINTED - alignment */ 2N/A int n;
/* number of buckets */ 2N/A /* first "bucket" used for range and step */ 2N/A * Add one for the base bucket and one for the bucket of values 2N/A * less than the base. 2N/A "size mismatch: record %d, buckets %d",
size,
2N/A return (
NULL);
/* exception pending */ 2N/A /* check for ArrayIndexOutOfBounds */ 2N/A /* Must pass 64-bit base and step or constructor gets junk. */ 2N/A return (
NULL);
/* exception pending */ 2N/A * Note: It is not valid to look outside the current libdtrace record in the 2N/A * given aggdata (except to get the aggregation ID from the first record). 2N/A * Return DTRACE_HANDLE_ABORT if java exception pending, otherwise 2N/A /* Assert without crashing */ 2N/A * Get the aggregation ID from the first record. 2N/A /* LINTED - alignment */ 2N/A /* Assert without crashing */ 2N/A /* Append buffered output if this is a printa() callback. */ 2N/A * StringBuilder append() returns a reference to the 2N/A * StringBuilder; must not leak the returned reference. 2N/A * Test whether to include the aggregation if this is a 2N/A * getAggregate() call. Optimization: perform the inclusion 2N/A * test only when the aggregation has changed. 2N/A * Determine the expected number of tuple members. While it is not 2N/A * technically valid to look outside the current record in the current 2N/A * aggdata, this implementation does so without a known failure case. 2N/A * Any method relying only on the current callback record makes riskier 2N/A * assumptions and still does not cover every corner case (for example, 2N/A * counting the records from index 1 up to and not including the index 2N/A * of the current DTRACE_BUFDATA_AGGVAL record, which fails when a 2N/A * format string specifies the value ahead of one or more tuple 2N/A * elements). Knowing that the calculation of the expected tuple size 2N/A * is technically invalid (because it looks outside the current record), 2N/A * we make the calculation at the earliest opportunity, before anything 2N/A * might happen to invalidate any part of the aggdata. It ought to be 2N/A * safe in any case: dtrd_action and dtrd_size do not appear ever to be 2N/A * overwritten, and dtrd_offset is not used outside the current record. 2N/A * It is possible (if the assumptions here ever prove untrue) that the 2N/A * libdtrace buffered output handler may need to be enhanced to provide 2N/A * the expected number of tuple members. 2N/A /* record value is a tuple member */ 2N/A /* java exception pending */ 2N/A /* java exception pending */ 2N/A * Record value is that of an aggregating action. The printa() 2N/A * format string may place the tuple ahead of the aggregation 2N/A * value(s), so we can't be sure we have the tuple until we get 2N/A * the AGGLAST flag indicating the last callback associated with 2N/A * the current tuple. Save the aggregation value or values 2N/A * (multiple values if more than one aggregation is passed to 2N/A * printa()) until then. 2N/A /* java exception pending */ 2N/A /* OutOfMemoryError pending */ 2N/A /* deletes jvalue reference */ 2N/A /* No more values associated with the current tuple. */ 2N/A * singleton aggregation declared in D with no square 2N/A "Failed to reference Tuple.EMPTY");
2N/A * new AggregationRecord: Combine the aggregation value 2N/A * with the saved tuple and add it to the current 2N/A * Aggregate or PrintaRecord. 2N/A /* java exception pending */ 2N/A /* aggregation name */ 2N/A /* OutOfMemoryError pending */ 2N/A * If the printa() format string specifies the value of 2N/A * the aggregating action multiple times, PrintaRecord 2N/A * ignores the attempt to add the duplicate record. 2N/A /* add to PrintaRecord */ 2N/A /* add to Aggregate */ 2N/A * Get the formatted string associated with the current 2N/A * tuple if this is a printa() callback. 2N/A * Clear the StringBuilder: this does not throw 2N/A * exceptions. Reuse the StringBuilder until the end of 2N/A * the current probedata then dispose of it. 2N/A /* Add formatted string to PrintaRecord */ 2N/A * Return B_TRUE if the aggregation is included, B_FALSE otherwise. Only in the 2N/A * latter case might there be an exception pending. 2N/A /* java exception pending */ 2N/A * Return NULL if a java exception is pending, otherwise return a new 2N/A * AggregationValue instance. 2N/A /* LINTED - alignment */ 2N/A "unexpected aggregation action: %d",
act);
2N/A * Stops the given consumer if it is running. Throws DTraceException if 2N/A * dtrace_stop() fails and no other exception is already pending. Clears and 2N/A * rethrows any pending exception in order to grab the global lock safely. 2N/A /* Do not wrap DTraceException */ 2N/A "couldn't stop tracing: %s",
2N/A /* safe to call with pending exception */ 2N/A * Favor earlier pending exception over 2N/A * exception thrown in this function. 2N/A * Return Aggregate instance, or null if java exception pending. 2N/A /* Must not call MonitorEnter with a pending exception */ 2N/A * Aggregations must be snapped, walked, and cleared atomically, 2N/A * otherwise clearing loses data accumulated since the most recent snap. 2N/A * This per-consumer lock prevents dtrace_work() from snapping or 2N/A * clearing aggregations while we're in the middle of this atomic 2N/A * operation, so we continue to hold it until done clearing. 2N/A /* release per-consumer lock */ 2N/A * We need to record the snaptime here for the caller. Leaving it to 2N/A * the caller to record the snaptime before calling getAggregate() may 2N/A * be inaccurate because of the indeterminate delay waiting on the 2N/A * consumer lock before calling dtrace_aggregate_snap(). 2N/A * The dataDropped() ConsumerListener method can throw an 2N/A * exception in the getAggregate() thread if the drop handler is 2N/A * invoked during dtrace_aggregate_snap(). 2N/A /* Do not wrap exception thrown from ConsumerListener */ 2N/A /* release per-consumer lock */ 2N/A /* Do not wrap DTraceException */ 2N/A /* release per-consumer lock */ 2N/A * Wrap the exception thrown from ConsumerListener in this case, 2N/A * so we can see that it unexpectedly reached this spot in 2N/A * native code (dtrace_aggregate_snap should have returned 2N/A /* release per-consumer lock */ 2N/A /* Create the Java representation of the aggregate snapshot. */ 2N/A /* release per-consumer lock */ 2N/A * Walk the aggregate, converting the data into Java Objects. Traverse 2N/A * in the order determined by libdtrace, respecting the various 2N/A * "aggsort" options, just as dtrace_work does when generating 2N/A * aggregations for the printa() action. libdtrace ordering is preserved 2N/A * in the "ordinal" property of AggregationRecord, since it would 2N/A * otherwise be lost when the records are hashed into the Aggregation's 2N/A * map. Neither the consumer loop nor the competing getAggregate() 2N/A * thread should depend on any particular record ordering (such as 2N/A * ordering by tuple key) to process records correctly. 2N/A * It is impractical to hold the global lock around 2N/A * dtrace_aggregate_print(), since it may take a long time (e.g. an 2N/A * entire second) if it performs expensive conversions such as that 2N/A * needed for user stack traces. Most libdtrace functions are not 2N/A * guaranteed to be MT-safe, even when each thread has its own dtrace 2N/A * handle; or even if they are safe, there is no guarantee that future 2N/A * changes may not make them unsafe. Fortunately in this case, however, 2N/A * only a per-consumer lock is necessary to avoid conflict with 2N/A * dtrace_work() running in another thread (the consumer loop). 2N/A /* release per-consumer lock */ 2N/A /* release per-consumer lock */ 2N/A /* Do not wrap DTraceException */ 2N/A /* release per-consumer lock */ 2N/A /* release per-consumer lock */ 2N/A * dtrace_aggregate_clear() clears all aggregations, and we need to 2N/A * clear aggregations selectively. It also fails to preserve the 2N/A * lquantize() range and step size; using aggregate_walk() to clear 2N/A * aggregations does not have this problem. 2N/A /* release per-consumer lock */ 2N/A /* Do not wrap DTraceException */ 2N/A /* release per-consumer lock */ 2N/A * Process any requests, such as the setting of runtime options, enqueued during 2N/A * dtrace_sleep(). A Java exception is pending if this function returns 2N/A /* Do not wrap DTraceException */ 2N/A * Return DTJ_OK if the consumer loop is stopped normally by either the exit() 2N/A * action or the Consumer stop() method. Otherwise return DTJ_ERR if the 2N/A * consumer loop terminates abnormally with an exception pending. 2N/A * Exception left pending by Consumer 2N/A * getAggregate() method. 2N/A * Functions like dtrace_setopt() are not safe to call during 2N/A * dtrace_sleep(). Check the request list every time we wake up 2N/A * from dtrace_sleep(). 2N/A /* Do not wrap DTraceException */ 2N/A /* Must not call MonitorEnter with a pending exception */ 2N/A * Use the per-consumer lock to avoid conflict with 2N/A * get_aggregate() called from another thread. 2N/A /* Don't wrap exception thrown from ConsumerListener */ 2N/A * Check for a pending exception that got us to this 2N/A * error workstatus case. 2N/A * Ensure valid initial state before releasing 2N/A /* Do not wrap DTraceException */ 2N/A /* Release per-consumer lock */ 2N/A /* java exception pending */ 2N/A /* Release per-consumer lock */ 2N/A /* Do not wrap DTraceException */ 2N/A /* Release per-consumer lock */ 2N/A * Check for ConsumerException before doing anything else with 2N/A * Do not wrap exception thrown from ConsumerListener. 2N/A /* Release per-consumer lock */ 2N/A * Notify ConsumerListeners the the dtrace_work() interval ended 2N/A * before releasing the lock. 2N/A /* Don't wrap exception thrown from ConsumerListener */ 2N/A * Check for a temporarily cleared exception set by a handler 2N/A * that could not safely leave the exception pending because it 2N/A * could not return an abort signal. Rethrow it now that it's 2N/A * safe to do so (when it's possible to ensure that no JNI calls 2N/A * will be made that are unsafe while an exception is pending).