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