/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DTRACE_JNI_H #define _DTRACE_JNI_H #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* Java DTrace API native library */ /* * Thread-specific data key used to obtain JNI state specific to either the * consumer loop (calls dtrace_work()) or the getAggregate() method (calls * dtrace_aggregate_print()). */ extern pthread_key_t g_dtj_consumer_key; typedef enum dtj_consumer_state { DTJ_CONSUMER_INIT, DTJ_CONSUMER_GO, DTJ_CONSUMER_START, DTJ_CONSUMER_STOP } dtj_consumer_state_t; typedef struct dtj_error { int dtje_number; /* dtrace_errno() */ const char *dtje_message; /* dtrace_errmsg() */ } dtj_error_t; /* * Identifies which function should handle a request dequeued after * dtrace_sleep(). */ typedef enum dtj_request_type { DTJ_REQUEST_OPTION /* set DTrace runtime option */ } dtj_request_type_t; /* * A request made from Java (by native method call) that is unsafe to process * until just after the consumer loop wakes up from dtrace_sleep(). */ typedef struct dtj_request { dtj_request_type_t dtjr_type; /* request handler ID */ uu_list_t *dtjr_args; /* string args to request handler */ uu_list_node_t dtjr_node; /* points to next and prev requests */ } dtj_request_t; typedef enum dtj_program_type { DTJ_PROGRAM_NONE, DTJ_PROGRAM_STRING, /* dtrace_program_strcompile() */ DTJ_PROGRAM_FILE /* dtrace_program_fcompile() */ } dtj_program_type_t; /* Identifier and description of a compiled DTrace program */ typedef struct dtj_program { dtj_program_type_t dtjp_type; /* string or file */ const char *dtjp_name; /* string or filename for err msg */ dtrace_prog_t *dtjp_program; /* libdtrace program handle */ dtrace_proginfo_t dtjp_info; /* program attributes */ boolean_t dtjp_enabled; /* dtrace_program_exec() flag */ uu_list_node_t dtjp_node; /* points to next and prev programs */ } dtj_program_t; /* * An entry used to maintain the association between the value of an aggregating * action (such as count()) and the aggregation to which the value belongs until * all the data associated with a single tuple is available to the callback * handler. */ typedef struct dtj_aggval { jobject dtja_value; /* value of aggregating action */ const char *dtja_aggname; /* aggregation name */ int64_t dtja_aggid; /* libdtrace aggregation ID */ uu_list_node_t dtja_node; /* points to next and prev aggvals */ } dtj_aggval_t; /* * Per-consumer state, including the libdtrace consumer handle, is valid across * multiple threads. One consumer entry is added to a global table per * dtrace_open(). */ typedef struct dtj_consumer { /* Consumer state */ dtrace_hdl_t *dtjc_dtp; /* libdtrace consumer handle */ uu_list_t *dtjc_program_list; /* program_t list */ uu_list_t *dtjc_process_list; /* proc handle list */ /* * Count of processes that have ended. The consumer is stopped when * this count equals the number of outstanding target processes and * grabbed processes (see the Java Consumer createProcess() and * grabProcess() methods). */ int dtjc_procs_ended; /* * Bit-field passed to dtrace_program_strcompile() and * dtrace_program_fcompile() containing compile flags. The flags are * set from Java by the setOption() Consumer method (just like the * runtime options handled by dtrace_setopt(), except that they must be * set before program compilation to have any effect). */ uint_t dtjc_cflags; boolean_t dtjc_flow; /* current value of the flowindent option */ dtj_consumer_state_t dtjc_state; /* execution state */ boolean_t dtjc_interrupt; /* flag that stops consumer */ /* Pending requests */ uu_list_t *dtjc_request_list; /* request_t queue */ pthread_mutex_t dtjc_request_list_lock; /* Cached for optimization and for use across functions */ /* * Nanosecond timestamp cached in the consumer loop just before * dtrace_work(). The timestamp is applied to each Java PrintaRecord * generated in that iteration of the consumer loop. A value of zero * indicates that we are not in the consumer loop, but that the * callback was triggered instead by the Consumer getAggregate() method * (from dtrace_aggregate_print()). */ hrtime_t dtjc_printa_snaptime; /* * The aggregation ID is used to optimize aggregation inclusion by * testing for inclusion only when the aggregation has changed. */ int64_t dtjc_aggid; boolean_t dtjc_included; /* * The expected tuple member count is used to determine whether or not * the aggregation tuple values are completely specified in the printa() * format string. */ int dtjc_expected; int dtjc_probedata_rec_i; /* probe data record index */ /* * The current DTrace action may apply across multiple libdtrace probe * data records. */ dtrace_actkind_t dtjc_probedata_act; /* Placeholder used when listing probes */ dtrace_ecbdesc_t *dtjc_last_probe; /* Function used by statement iterator when listing probes */ dtrace_probe_f *dtjc_plistfunc; } dtj_consumer_t; /* * A view of a dtj_consumer_t that lasts only as long as a single native method * call. This view attaches state needed for interaction with Java and specific * to the JNI. */ typedef struct dtj_java_consumer { /* Per-consumer state in global consumer table */ dtj_consumer_t *dtjj_consumer; JNIEnv *dtjj_jenv; /* Java environment pointer */ jobject dtjj_caller; /* Java Consumer to call back with probe data */ /* * Java Object references used across function boundaries, valid only * within the current native method call. */ jobject dtjj_probedata; /* instance of class ProbeData */ /* * StringBuffer used to concatenate buffered printa() output associated * with the current tuple. */ jobject dtjj_printa_buffer; jobject dtjj_aggregate; /* instance of class Aggregate */ jobject dtjj_tuple; /* instance of class Tuple */ /* * AggregationValue instances cached until we receive the * DTRACE_BUFDATA_AGGLAST flag indicating the last callback associated * with the current tuple. */ uu_list_t *dtjj_aggval_list; /* AggregateSpec used by get_aggregate() */ jobject dtjj_aggregate_spec; jobject dtjj_probelist; /* java.util.List returned by listProbes() */ /* * Exception temporarily cleared by callback handlers who cannot return * a signal to abort the consumer. At a safe point when the consumer * loop gets control back from libdtrace, the exception is rethrown. */ jthrowable dtjj_exception; jobject dtjj_consumer_lock; /* per-consumer lock */ } dtj_java_consumer_t; /* * Cache of jclass, jmethodID, and jfieldID values, usable across multiple * native method calls and multiple threads. Caching all of them up front * rather than as-needed guarantees early detection of incorrect class, method, * or field definitions, and eliminates the need for test cases to cover * seldom-used definitions. * * Suffix conventions: * jc java class * jm java method * jsm java static method * jf java field * jsf java static field */ /* LocalConsumer */ extern jclass g_caller_jc; extern jmethodID g_gethandle_jm; extern jmethodID g_sethandle_jm; extern jmethodID g_pdatanext_jm; extern jmethodID g_drop_jm; extern jmethodID g_error_jm; extern jmethodID g_proc_jm; extern jmethodID g_interval_began_jm; extern jmethodID g_interval_ended_jm; extern jfieldID g_consumer_lock_jf; /* DTraceException */ extern jclass g_dtx_jc; extern jmethodID g_dtxinit_jm; /* InterfaceAttributes */ extern jclass g_attr_jc; extern jmethodID g_attrinit_jm; extern jmethodID g_attrset_name_jm; extern jmethodID g_attrset_data_jm; extern jmethodID g_attrset_class_jm; /* ProbeDescription */ extern jclass g_probedesc_jc; extern jmethodID g_probedescinit_jm; extern jfieldID g_probedesc_id_jf; /* ProbeInfo */ extern jclass g_probeinfo_jc; extern jmethodID g_probeinfoinit_jm; /* Probe */ extern jclass g_probe_jc; extern jmethodID g_probeinit_jm; /* Program */ extern jclass g_program_jc; extern jmethodID g_proginit_jm; extern jfieldID g_progid_jf; extern jfieldID g_proginfo_jf; /* Program.File */ extern jclass g_programfile_jc; extern jmethodID g_fproginit_jm; /* ProgramInfo */ extern jclass g_proginfo_jc; extern jmethodID g_proginfoinit_jm; /* Flow */ extern jclass g_flow_jc; extern jmethodID g_flowinit_jm; /* ProbeData */ extern jclass g_pdata_jc; extern jmethodID g_pdatainit_jm; extern jmethodID g_pdataadd_jm; extern jmethodID g_pdataadd_rec_jm; extern jmethodID g_pdataadd_trace_jm; extern jmethodID g_pdataadd_stack_jm; extern jmethodID g_pdataadd_symbol_jm; extern jmethodID g_pdataadd_printf_jm; extern jmethodID g_pdataadd_printa_jm; extern jmethodID g_pdatainvalidate_printa_jm; extern jmethodID g_pdataadd_aggrec_jm; extern jmethodID g_pdataadd_printa_str_jm; extern jmethodID g_pdataadd_exit_jm; extern jmethodID g_pdataattach_jm; extern jmethodID g_pdataset_formatted_jm; extern jmethodID g_pdataclear_jm; /* Drop */ extern jclass g_drop_jc; extern jmethodID g_dropinit_jm; /* Error */ extern jclass g_error_jc; extern jmethodID g_errinit_jm; /* ProcessState */ extern jclass g_process_jc; extern jmethodID g_procinit_jm; extern jmethodID g_procexit_jm; /* Aggregate */ extern jclass g_agg_jc; extern jmethodID g_agginit_jm; extern jmethodID g_aggaddrec_jm; /* AggregateSpec */ extern jclass g_aggspec_jc; extern jmethodID g_aggspec_included_jm; extern jmethodID g_aggspec_cleared_jm; /* Tuple */ extern jclass g_tuple_jc; extern jmethodID g_tupleinit_jm; extern jmethodID g_tupleadd_jm; extern jmethodID g_tuplesize_jm; extern jfieldID g_tuple_EMPTY_jsf; /* AggregationRecord */ extern jclass g_aggrec_jc; extern jmethodID g_aggrecinit_jm; extern jmethodID g_aggrecget_tuple_jm; /* SumValue */ extern jclass g_aggsum_jc; extern jmethodID g_aggsuminit_jm; /* CountValue */ extern jclass g_aggcount_jc; extern jmethodID g_aggcountinit_jm; /* AvgValue */ extern jclass g_aggavg_jc; extern jmethodID g_aggavginit_jm; /* MinValue */ extern jclass g_aggmin_jc; extern jmethodID g_aggmininit_jm; /* MaxValue */ extern jclass g_aggmax_jc; extern jmethodID g_aggmaxinit_jm; /* KernelStackRecord */ extern jclass g_stack_jc; extern jmethodID g_parsestack_jsm; extern jmethodID g_stackinit_jm; extern jmethodID g_stackset_frames_jm; /* UserStackRecord */ extern jclass g_ustack_jc; extern jmethodID g_ustackinit_jm; extern jmethodID g_ustackset_frames_jm; /* Distribution */ extern jclass g_adist_jc; extern jmethodID g_dist_normal_jm; /* LogDistribution */ extern jclass g_dist_jc; extern jmethodID g_distinit_jm; /* LinearDistribution */ extern jclass g_ldist_jc; extern jmethodID g_ldistinit_jm; /* KernelSymbolRecord */ extern jclass g_symbol_jc; extern jmethodID g_symbolinit_jm; extern jmethodID g_symbolset_name_jm; /* UserSymbolRecord */ extern jclass g_usymbol_jc; extern jmethodID g_usymbolinit_jm; extern jmethodID g_usymbolset_name_jm; /* ScalarRecord */ extern jclass g_scalar_jc; extern jmethodID g_scalarinit_jm; /* * Populates the java class references and associated method and field IDs * declared in this file (above). * * Throws NoClassDefFoundError, NoSuchMethodError, or NoSuchFieldError if any * dtj_table_entry_t in dtj_jnitab.c is incorrect. */ extern dtj_status_t dtj_load(JNIEnv *); /* * Functions that create a structure return NULL if out of memory. A Java * OutOfMemoryError is pending in that case. */ extern dtj_request_t *dtj_request_create(JNIEnv *, dtj_request_type_t, ...); extern dtj_program_t *dtj_program_create(JNIEnv *, dtj_program_type_t, const char *); extern dtj_aggval_t *dtj_aggval_create(JNIEnv *, jobject, const char *, int64_t); /* * uu_list_t element destructors' signatures match uuwrap_value_destroy_f */ extern void dtj_request_destroy(void *, void *); /* expects NULL user arg */ extern void dtj_program_destroy(void *, void *); /* expects NULL user arg */ extern void dtj_aggval_destroy(void *, void *); /* expects JNIEnv * user arg */ /* Allocates and frees per-consumer state kept in the global consumer table */ extern dtj_consumer_t *dtj_consumer_create(JNIEnv *); extern void dtj_consumer_destroy(dtj_consumer_t *); /* Sets callback handlers before calling dtrace_go() */ extern dtj_status_t dtj_set_callback_handlers(dtj_java_consumer_t *); /* * Initializes Java Object references cached across multiple functions called * within the consumer loop. Deletes the references after exiting the consumer * loop. It is only necessary to initialize and finalize a dtj_java_consumer_t * if the native method call will enter the consumer loop. */ extern dtj_status_t dtj_java_consumer_init(JNIEnv *, dtj_java_consumer_t *); extern void dtj_java_consumer_fini(JNIEnv *, dtj_java_consumer_t *); /* * Throws a DTraceException with a message constructed from the given format * string and variable arg list. */ extern void dtj_throw_dtrace_exception(dtj_java_consumer_t *, const char *, ...); /* Returns NULL if pending Java Exception or OutOfMemoryError */ extern jobject dtj_new_probedesc(dtj_java_consumer_t *, const dtrace_probedesc_t *); extern jobject dtj_new_probeinfo(dtj_java_consumer_t *, const dtrace_probeinfo_t *); extern jobject dtj_new_attribute(dtj_java_consumer_t *, const dtrace_attribute_t *); /* * Returns NULL if the given fault is unrecognized, otherwise returns the name * of the fault, guaranteed not to change across multiple versions of this API * even if the integer value changes in libdtrace. */ extern const char *dtj_get_fault_name(int); /* Gets the libdtrace error number and message */ extern dtj_status_t dtj_get_dtrace_error(dtj_java_consumer_t *, dtj_error_t *); /* Stops the DTrace consumer */ extern void dtj_stop(dtj_java_consumer_t *); /* * The Consumer getAggregate() method runs in the caller's current thread * separate from the consumer loop. */ extern jobject dtj_get_aggregate(dtj_java_consumer_t *); /* * A blocking call that runs the consumer loop. If this function returns an * error status, it is necessary to call stop() in order to dtrace_stop() the * consumer in libdtrace (it is safe to call stop() in either case). */ extern dtj_status_t dtj_consume(dtj_java_consumer_t *); #ifdef __cplusplus } #endif #endif /* _DTRACE_JNI_H */