1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#ifndef _DTRACE_JNI_H 28#define _DTRACE_JNI_H 29 30#pragma ident "%Z%%M% %I% %E% SMI" 31 32#include <libuutil.h> 33#include <jni.h> 34#include <dtrace.h> 35#include <dtj_util.h> 36 37#ifdef __cplusplus 38extern "C" { 39#endif 40 41/* Java DTrace API native library */ 42 43 44/* 45 * Thread-specific data key used to obtain JNI state specific to either the 46 * consumer loop (calls dtrace_work()) or the getAggregate() method (calls 47 * dtrace_aggregate_print()). 48 */ 49extern pthread_key_t g_dtj_consumer_key; 50 51typedef enum dtj_consumer_state { 52 DTJ_CONSUMER_INIT, 53 DTJ_CONSUMER_GO, 54 DTJ_CONSUMER_START, 55 DTJ_CONSUMER_STOP 56} dtj_consumer_state_t; 57 58typedef struct dtj_error { 59 int dtje_number; /* dtrace_errno() */ 60 const char *dtje_message; /* dtrace_errmsg() */ 61} dtj_error_t; 62 63/* 64 * Identifies which function should handle a request dequeued after 65 * dtrace_sleep(). 66 */ 67typedef enum dtj_request_type { 68 DTJ_REQUEST_OPTION /* set DTrace runtime option */ 69} dtj_request_type_t; 70 71/* 72 * A request made from Java (by native method call) that is unsafe to process 73 * until just after the consumer loop wakes up from dtrace_sleep(). 74 */ 75typedef struct dtj_request { 76 dtj_request_type_t dtjr_type; /* request handler ID */ 77 uu_list_t *dtjr_args; /* string args to request handler */ 78 uu_list_node_t dtjr_node; /* points to next and prev requests */ 79} dtj_request_t; 80 81typedef enum dtj_program_type { 82 DTJ_PROGRAM_NONE, 83 DTJ_PROGRAM_STRING, /* dtrace_program_strcompile() */ 84 DTJ_PROGRAM_FILE /* dtrace_program_fcompile() */ 85} dtj_program_type_t; 86 87/* Identifier and description of a compiled DTrace program */ 88typedef struct dtj_program { 89 dtj_program_type_t dtjp_type; /* string or file */ 90 const char *dtjp_name; /* string or filename for err msg */ 91 dtrace_prog_t *dtjp_program; /* libdtrace program handle */ 92 dtrace_proginfo_t dtjp_info; /* program attributes */ 93 boolean_t dtjp_enabled; /* dtrace_program_exec() flag */ 94 uu_list_node_t dtjp_node; /* points to next and prev programs */ 95} dtj_program_t; 96 97/* 98 * An entry used to maintain the association between the value of an aggregating 99 * action (such as count()) and the aggregation to which the value belongs until 100 * all the data associated with a single tuple is available to the callback 101 * handler. 102 */ 103typedef struct dtj_aggval { 104 jobject dtja_value; /* value of aggregating action */ 105 const char *dtja_aggname; /* aggregation name */ 106 int64_t dtja_aggid; /* libdtrace aggregation ID */ 107 uu_list_node_t dtja_node; /* points to next and prev aggvals */ 108} dtj_aggval_t; 109 110/* 111 * Per-consumer state, including the libdtrace consumer handle, is valid across 112 * multiple threads. One consumer entry is added to a global table per 113 * dtrace_open(). 114 */ 115typedef struct dtj_consumer { 116 /* Consumer state */ 117 118 dtrace_hdl_t *dtjc_dtp; /* libdtrace consumer handle */ 119 uu_list_t *dtjc_program_list; /* program_t list */ 120 uu_list_t *dtjc_process_list; /* proc handle list */ 121 122 /* 123 * Count of processes that have ended. The consumer is stopped when 124 * this count equals the number of outstanding target processes and 125 * grabbed processes (see the Java Consumer createProcess() and 126 * grabProcess() methods). 127 */ 128 int dtjc_procs_ended; 129 130 /* 131 * Bit-field passed to dtrace_program_strcompile() and 132 * dtrace_program_fcompile() containing compile flags. The flags are 133 * set from Java by the setOption() Consumer method (just like the 134 * runtime options handled by dtrace_setopt(), except that they must be 135 * set before program compilation to have any effect). 136 */ 137 uint_t dtjc_cflags; 138 139 boolean_t dtjc_flow; /* current value of the flowindent option */ 140 dtj_consumer_state_t dtjc_state; /* execution state */ 141 boolean_t dtjc_interrupt; /* flag that stops consumer */ 142 143 /* Pending requests */ 144 uu_list_t *dtjc_request_list; /* request_t queue */ 145 pthread_mutex_t dtjc_request_list_lock; 146 147 148 /* Cached for optimization and for use across functions */ 149 150 /* 151 * Nanosecond timestamp cached in the consumer loop just before 152 * dtrace_work(). The timestamp is applied to each Java PrintaRecord 153 * generated in that iteration of the consumer loop. A value of zero 154 * indicates that we are not in the consumer loop, but that the 155 * callback was triggered instead by the Consumer getAggregate() method 156 * (from dtrace_aggregate_print()). 157 */ 158 hrtime_t dtjc_printa_snaptime; 159 160 /* 161 * The aggregation ID is used to optimize aggregation inclusion by 162 * testing for inclusion only when the aggregation has changed. 163 */ 164 int64_t dtjc_aggid; 165 boolean_t dtjc_included; 166 167 /* 168 * The expected tuple member count is used to determine whether or not 169 * the aggregation tuple values are completely specified in the printa() 170 * format string. 171 */ 172 int dtjc_expected; 173 174 int dtjc_probedata_rec_i; /* probe data record index */ 175 176 /* 177 * The current DTrace action may apply across multiple libdtrace probe 178 * data records. 179 */ 180 dtrace_actkind_t dtjc_probedata_act; 181 182 /* Placeholder used when listing probes */ 183 dtrace_ecbdesc_t *dtjc_last_probe; 184 185 /* Function used by statement iterator when listing probes */ 186 dtrace_probe_f *dtjc_plistfunc; 187} dtj_consumer_t; 188 189/* 190 * A view of a dtj_consumer_t that lasts only as long as a single native method 191 * call. This view attaches state needed for interaction with Java and specific 192 * to the JNI. 193 */ 194typedef struct dtj_java_consumer { 195 /* Per-consumer state in global consumer table */ 196 dtj_consumer_t *dtjj_consumer; 197 198 JNIEnv *dtjj_jenv; /* Java environment pointer */ 199 jobject dtjj_caller; /* Java Consumer to call back with probe data */ 200 201 /* 202 * Java Object references used across function boundaries, valid only 203 * within the current native method call. 204 */ 205 206 jobject dtjj_probedata; /* instance of class ProbeData */ 207 208 /* 209 * StringBuffer used to concatenate buffered printa() output associated 210 * with the current tuple. 211 */ 212 jobject dtjj_printa_buffer; 213 214 jobject dtjj_aggregate; /* instance of class Aggregate */ 215 jobject dtjj_tuple; /* instance of class Tuple */ 216 217 /* 218 * AggregationValue instances cached until we receive the 219 * DTRACE_BUFDATA_AGGLAST flag indicating the last callback associated 220 * with the current tuple. 221 */ 222 uu_list_t *dtjj_aggval_list; 223 224 /* AggregateSpec used by get_aggregate() */ 225 jobject dtjj_aggregate_spec; 226 227 jobject dtjj_probelist; /* java.util.List returned by listProbes() */ 228 229 /* 230 * Exception temporarily cleared by callback handlers who cannot return 231 * a signal to abort the consumer. At a safe point when the consumer 232 * loop gets control back from libdtrace, the exception is rethrown. 233 */ 234 jthrowable dtjj_exception; 235 236 jobject dtjj_consumer_lock; /* per-consumer lock */ 237 238} dtj_java_consumer_t; 239 240/* 241 * Cache of jclass, jmethodID, and jfieldID values, usable across multiple 242 * native method calls and multiple threads. Caching all of them up front 243 * rather than as-needed guarantees early detection of incorrect class, method, 244 * or field definitions, and eliminates the need for test cases to cover 245 * seldom-used definitions. 246 * 247 * Suffix conventions: 248 * jc java class 249 * jm java method 250 * jsm java static method 251 * jf java field 252 * jsf java static field 253 */ 254 255/* LocalConsumer */ 256extern jclass g_caller_jc; 257extern jmethodID g_gethandle_jm; 258extern jmethodID g_sethandle_jm; 259extern jmethodID g_pdatanext_jm; 260extern jmethodID g_drop_jm; 261extern jmethodID g_error_jm; 262extern jmethodID g_proc_jm; 263extern jmethodID g_interval_began_jm; 264extern jmethodID g_interval_ended_jm; 265extern jfieldID g_consumer_lock_jf; 266 267/* DTraceException */ 268extern jclass g_dtx_jc; 269extern jmethodID g_dtxinit_jm; 270 271/* InterfaceAttributes */ 272extern jclass g_attr_jc; 273extern jmethodID g_attrinit_jm; 274extern jmethodID g_attrset_name_jm; 275extern jmethodID g_attrset_data_jm; 276extern jmethodID g_attrset_class_jm; 277 278/* ProbeDescription */ 279extern jclass g_probedesc_jc; 280extern jmethodID g_probedescinit_jm; 281extern jfieldID g_probedesc_id_jf; 282 283/* ProbeInfo */ 284extern jclass g_probeinfo_jc; 285extern jmethodID g_probeinfoinit_jm; 286 287/* Probe */ 288extern jclass g_probe_jc; 289extern jmethodID g_probeinit_jm; 290 291/* Program */ 292extern jclass g_program_jc; 293extern jmethodID g_proginit_jm; 294extern jfieldID g_progid_jf; 295extern jfieldID g_proginfo_jf; 296 297/* Program.File */ 298extern jclass g_programfile_jc; 299extern jmethodID g_fproginit_jm; 300 301/* ProgramInfo */ 302extern jclass g_proginfo_jc; 303extern jmethodID g_proginfoinit_jm; 304 305/* Flow */ 306extern jclass g_flow_jc; 307extern jmethodID g_flowinit_jm; 308 309/* ProbeData */ 310extern jclass g_pdata_jc; 311extern jmethodID g_pdatainit_jm; 312extern jmethodID g_pdataadd_jm; 313extern jmethodID g_pdataadd_rec_jm; 314extern jmethodID g_pdataadd_trace_jm; 315extern jmethodID g_pdataadd_stack_jm; 316extern jmethodID g_pdataadd_symbol_jm; 317extern jmethodID g_pdataadd_printf_jm; 318extern jmethodID g_pdataadd_printa_jm; 319extern jmethodID g_pdatainvalidate_printa_jm; 320extern jmethodID g_pdataadd_aggrec_jm; 321extern jmethodID g_pdataadd_printa_str_jm; 322extern jmethodID g_pdataadd_exit_jm; 323extern jmethodID g_pdataattach_jm; 324extern jmethodID g_pdataset_formatted_jm; 325extern jmethodID g_pdataclear_jm; 326 327/* Drop */ 328extern jclass g_drop_jc; 329extern jmethodID g_dropinit_jm; 330 331/* Error */ 332extern jclass g_error_jc; 333extern jmethodID g_errinit_jm; 334 335/* ProcessState */ 336extern jclass g_process_jc; 337extern jmethodID g_procinit_jm; 338extern jmethodID g_procexit_jm; 339 340/* Aggregate */ 341extern jclass g_agg_jc; 342extern jmethodID g_agginit_jm; 343extern jmethodID g_aggaddrec_jm; 344 345/* AggregateSpec */ 346extern jclass g_aggspec_jc; 347extern jmethodID g_aggspec_included_jm; 348extern jmethodID g_aggspec_cleared_jm; 349 350/* Tuple */ 351extern jclass g_tuple_jc; 352extern jmethodID g_tupleinit_jm; 353extern jmethodID g_tupleadd_jm; 354extern jmethodID g_tuplesize_jm; 355extern jfieldID g_tuple_EMPTY_jsf; 356 357/* AggregationRecord */ 358extern jclass g_aggrec_jc; 359extern jmethodID g_aggrecinit_jm; 360extern jmethodID g_aggrecget_tuple_jm; 361 362/* SumValue */ 363extern jclass g_aggsum_jc; 364extern jmethodID g_aggsuminit_jm; 365 366/* CountValue */ 367extern jclass g_aggcount_jc; 368extern jmethodID g_aggcountinit_jm; 369 370/* AvgValue */ 371extern jclass g_aggavg_jc; 372extern jmethodID g_aggavginit_jm; 373 374/* MinValue */ 375extern jclass g_aggmin_jc; 376extern jmethodID g_aggmininit_jm; 377 378/* MaxValue */ 379extern jclass g_aggmax_jc; 380extern jmethodID g_aggmaxinit_jm; 381 382/* StddevValue */ 383extern jclass g_aggstddev_jc; 384extern jmethodID g_aggstddevinit_jm; 385 386/* KernelStackRecord */ 387extern jclass g_stack_jc; 388extern jmethodID g_parsestack_jsm; 389extern jmethodID g_stackinit_jm; 390extern jmethodID g_stackset_frames_jm; 391 392/* UserStackRecord */ 393extern jclass g_ustack_jc; 394extern jmethodID g_ustackinit_jm; 395extern jmethodID g_ustackset_frames_jm; 396 397/* Distribution */ 398extern jclass g_adist_jc; 399extern jmethodID g_dist_normal_jm; 400 401/* LogDistribution */ 402extern jclass g_dist_jc; 403extern jmethodID g_distinit_jm; 404 405/* LinearDistribution */ 406extern jclass g_ldist_jc; 407extern jmethodID g_ldistinit_jm; 408 409/* KernelSymbolRecord */ 410extern jclass g_symbol_jc; 411extern jmethodID g_symbolinit_jm; 412extern jmethodID g_symbolset_name_jm; 413 414/* UserSymbolRecord */ 415extern jclass g_usymbol_jc; 416extern jmethodID g_usymbolinit_jm; 417extern jmethodID g_usymbolset_name_jm; 418 419/* ScalarRecord */ 420extern jclass g_scalar_jc; 421extern jmethodID g_scalarinit_jm; 422 423/* 424 * Populates the java class references and associated method and field IDs 425 * declared in this file (above). 426 * 427 * Throws NoClassDefFoundError, NoSuchMethodError, or NoSuchFieldError if any 428 * dtj_table_entry_t in dtj_jnitab.c is incorrect. 429 */ 430extern dtj_status_t dtj_load(JNIEnv *); 431 432/* 433 * Functions that create a structure return NULL if out of memory. A Java 434 * OutOfMemoryError is pending in that case. 435 */ 436extern dtj_request_t *dtj_request_create(JNIEnv *, dtj_request_type_t, ...); 437extern dtj_program_t *dtj_program_create(JNIEnv *, dtj_program_type_t, 438 const char *); 439extern dtj_aggval_t *dtj_aggval_create(JNIEnv *, jobject, const char *, 440 int64_t); 441 442/* 443 * uu_list_t element destructors' signatures match uuwrap_value_destroy_f 444 */ 445extern void dtj_request_destroy(void *, void *); /* expects NULL user arg */ 446extern void dtj_program_destroy(void *, void *); /* expects NULL user arg */ 447extern void dtj_aggval_destroy(void *, void *); /* expects JNIEnv * user arg */ 448 449/* Allocates and frees per-consumer state kept in the global consumer table */ 450extern dtj_consumer_t *dtj_consumer_create(JNIEnv *); 451extern void dtj_consumer_destroy(dtj_consumer_t *); 452 453/* Sets callback handlers before calling dtrace_go() */ 454extern dtj_status_t dtj_set_callback_handlers(dtj_java_consumer_t *); 455 456/* 457 * Initializes Java Object references cached across multiple functions called 458 * within the consumer loop. Deletes the references after exiting the consumer 459 * loop. It is only necessary to initialize and finalize a dtj_java_consumer_t 460 * if the native method call will enter the consumer loop. 461 */ 462extern dtj_status_t dtj_java_consumer_init(JNIEnv *, dtj_java_consumer_t *); 463extern void dtj_java_consumer_fini(JNIEnv *, dtj_java_consumer_t *); 464 465/* 466 * Throws a DTraceException with a message constructed from the given format 467 * string and variable arg list. 468 */ 469extern void dtj_throw_dtrace_exception(dtj_java_consumer_t *, 470 const char *, ...); 471 472/* Returns NULL if pending Java Exception or OutOfMemoryError */ 473extern jobject dtj_new_probedesc(dtj_java_consumer_t *, 474 const dtrace_probedesc_t *); 475extern jobject dtj_new_probeinfo(dtj_java_consumer_t *, 476 const dtrace_probeinfo_t *); 477extern jobject dtj_new_attribute(dtj_java_consumer_t *, 478 const dtrace_attribute_t *); 479 480/* 481 * Returns NULL if the given fault is unrecognized, otherwise returns the name 482 * of the fault, guaranteed not to change across multiple versions of this API 483 * even if the integer value changes in libdtrace. 484 */ 485extern const char *dtj_get_fault_name(int); 486 487/* Gets the libdtrace error number and message */ 488extern dtj_status_t dtj_get_dtrace_error(dtj_java_consumer_t *, dtj_error_t *); 489 490/* Stops the DTrace consumer */ 491extern void dtj_stop(dtj_java_consumer_t *); 492 493/* 494 * The Consumer getAggregate() method runs in the caller's current thread 495 * separate from the consumer loop. 496 */ 497extern jobject dtj_get_aggregate(dtj_java_consumer_t *); 498 499/* 500 * A blocking call that runs the consumer loop. If this function returns an 501 * error status, it is necessary to call stop() in order to dtrace_stop() the 502 * consumer in libdtrace (it is safe to call stop() in either case). 503 */ 504extern dtj_status_t dtj_consume(dtj_java_consumer_t *); 505 506#ifdef __cplusplus 507} 508#endif 509 510#endif /* _DTRACE_JNI_H */ 511