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 38 extern "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 */ 49 extern pthread_key_t g_dtj_consumer_key; 50 51 typedef 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 58 typedef 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 */ 67 typedef 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 */ 75 typedef 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 81 typedef 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 */ 88 typedef 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 */ 103 typedef 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 */ 115 typedef 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 */ 194 typedef 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 */ 256 extern jclass g_caller_jc; 257 extern jmethodID g_gethandle_jm; 258 extern jmethodID g_sethandle_jm; 259 extern jmethodID g_pdatanext_jm; 260 extern jmethodID g_drop_jm; 261 extern jmethodID g_error_jm; 262 extern jmethodID g_proc_jm; 263 extern jmethodID g_interval_began_jm; 264 extern jmethodID g_interval_ended_jm; 265 extern jfieldID g_consumer_lock_jf; 266 267 /* DTraceException */ 268 extern jclass g_dtx_jc; 269 extern jmethodID g_dtxinit_jm; 270 271 /* InterfaceAttributes */ 272 extern jclass g_attr_jc; 273 extern jmethodID g_attrinit_jm; 274 extern jmethodID g_attrset_name_jm; 275 extern jmethodID g_attrset_data_jm; 276 extern jmethodID g_attrset_class_jm; 277 278 /* ProbeDescription */ 279 extern jclass g_probedesc_jc; 280 extern jmethodID g_probedescinit_jm; 281 extern jfieldID g_probedesc_id_jf; 282 283 /* ProbeInfo */ 284 extern jclass g_probeinfo_jc; 285 extern jmethodID g_probeinfoinit_jm; 286 287 /* Probe */ 288 extern jclass g_probe_jc; 289 extern jmethodID g_probeinit_jm; 290 291 /* Program */ 292 extern jclass g_program_jc; 293 extern jmethodID g_proginit_jm; 294 extern jfieldID g_progid_jf; 295 extern jfieldID g_proginfo_jf; 296 297 /* Program.File */ 298 extern jclass g_programfile_jc; 299 extern jmethodID g_fproginit_jm; 300 301 /* ProgramInfo */ 302 extern jclass g_proginfo_jc; 303 extern jmethodID g_proginfoinit_jm; 304 305 /* Flow */ 306 extern jclass g_flow_jc; 307 extern jmethodID g_flowinit_jm; 308 309 /* ProbeData */ 310 extern jclass g_pdata_jc; 311 extern jmethodID g_pdatainit_jm; 312 extern jmethodID g_pdataadd_jm; 313 extern jmethodID g_pdataadd_rec_jm; 314 extern jmethodID g_pdataadd_trace_jm; 315 extern jmethodID g_pdataadd_stack_jm; 316 extern jmethodID g_pdataadd_symbol_jm; 317 extern jmethodID g_pdataadd_printf_jm; 318 extern jmethodID g_pdataadd_printa_jm; 319 extern jmethodID g_pdatainvalidate_printa_jm; 320 extern jmethodID g_pdataadd_aggrec_jm; 321 extern jmethodID g_pdataadd_printa_str_jm; 322 extern jmethodID g_pdataadd_exit_jm; 323 extern jmethodID g_pdataattach_jm; 324 extern jmethodID g_pdataset_formatted_jm; 325 extern jmethodID g_pdataclear_jm; 326 327 /* Drop */ 328 extern jclass g_drop_jc; 329 extern jmethodID g_dropinit_jm; 330 331 /* Error */ 332 extern jclass g_error_jc; 333 extern jmethodID g_errinit_jm; 334 335 /* ProcessState */ 336 extern jclass g_process_jc; 337 extern jmethodID g_procinit_jm; 338 extern jmethodID g_procexit_jm; 339 340 /* Aggregate */ 341 extern jclass g_agg_jc; 342 extern jmethodID g_agginit_jm; 343 extern jmethodID g_aggaddrec_jm; 344 345 /* AggregateSpec */ 346 extern jclass g_aggspec_jc; 347 extern jmethodID g_aggspec_included_jm; 348 extern jmethodID g_aggspec_cleared_jm; 349 350 /* Tuple */ 351 extern jclass g_tuple_jc; 352 extern jmethodID g_tupleinit_jm; 353 extern jmethodID g_tupleadd_jm; 354 extern jmethodID g_tuplesize_jm; 355 extern jfieldID g_tuple_EMPTY_jsf; 356 357 /* AggregationRecord */ 358 extern jclass g_aggrec_jc; 359 extern jmethodID g_aggrecinit_jm; 360 extern jmethodID g_aggrecget_tuple_jm; 361 362 /* SumValue */ 363 extern jclass g_aggsum_jc; 364 extern jmethodID g_aggsuminit_jm; 365 366 /* CountValue */ 367 extern jclass g_aggcount_jc; 368 extern jmethodID g_aggcountinit_jm; 369 370 /* AvgValue */ 371 extern jclass g_aggavg_jc; 372 extern jmethodID g_aggavginit_jm; 373 374 /* MinValue */ 375 extern jclass g_aggmin_jc; 376 extern jmethodID g_aggmininit_jm; 377 378 /* MaxValue */ 379 extern jclass g_aggmax_jc; 380 extern jmethodID g_aggmaxinit_jm; 381 382 /* StddevValue */ 383 extern jclass g_aggstddev_jc; 384 extern jmethodID g_aggstddevinit_jm; 385 386 /* KernelStackRecord */ 387 extern jclass g_stack_jc; 388 extern jmethodID g_parsestack_jsm; 389 extern jmethodID g_stackinit_jm; 390 extern jmethodID g_stackset_frames_jm; 391 392 /* UserStackRecord */ 393 extern jclass g_ustack_jc; 394 extern jmethodID g_ustackinit_jm; 395 extern jmethodID g_ustackset_frames_jm; 396 397 /* Distribution */ 398 extern jclass g_adist_jc; 399 extern jmethodID g_dist_normal_jm; 400 401 /* LogDistribution */ 402 extern jclass g_dist_jc; 403 extern jmethodID g_distinit_jm; 404 405 /* LinearDistribution */ 406 extern jclass g_ldist_jc; 407 extern jmethodID g_ldistinit_jm; 408 409 /* KernelSymbolRecord */ 410 extern jclass g_symbol_jc; 411 extern jmethodID g_symbolinit_jm; 412 extern jmethodID g_symbolset_name_jm; 413 414 /* UserSymbolRecord */ 415 extern jclass g_usymbol_jc; 416 extern jmethodID g_usymbolinit_jm; 417 extern jmethodID g_usymbolset_name_jm; 418 419 /* ScalarRecord */ 420 extern jclass g_scalar_jc; 421 extern 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 */ 430 extern 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 */ 436 extern dtj_request_t *dtj_request_create(JNIEnv *, dtj_request_type_t, ...); 437 extern dtj_program_t *dtj_program_create(JNIEnv *, dtj_program_type_t, 438 const char *); 439 extern 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 */ 445 extern void dtj_request_destroy(void *, void *); /* expects NULL user arg */ 446 extern void dtj_program_destroy(void *, void *); /* expects NULL user arg */ 447 extern void dtj_aggval_destroy(void *, void *); /* expects JNIEnv * user arg */ 448 449 /* Allocates and frees per-consumer state kept in the global consumer table */ 450 extern dtj_consumer_t *dtj_consumer_create(JNIEnv *); 451 extern void dtj_consumer_destroy(dtj_consumer_t *); 452 453 /* Sets callback handlers before calling dtrace_go() */ 454 extern 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 */ 462 extern dtj_status_t dtj_java_consumer_init(JNIEnv *, dtj_java_consumer_t *); 463 extern 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 */ 469 extern void dtj_throw_dtrace_exception(dtj_java_consumer_t *, 470 const char *, ...); 471 472 /* Returns NULL if pending Java Exception or OutOfMemoryError */ 473 extern jobject dtj_new_probedesc(dtj_java_consumer_t *, 474 const dtrace_probedesc_t *); 475 extern jobject dtj_new_probeinfo(dtj_java_consumer_t *, 476 const dtrace_probeinfo_t *); 477 extern 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 */ 485 extern const char *dtj_get_fault_name(int); 486 487 /* Gets the libdtrace error number and message */ 488 extern dtj_status_t dtj_get_dtrace_error(dtj_java_consumer_t *, dtj_error_t *); 489 490 /* Stops the DTrace consumer */ 491 extern 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 */ 497 extern 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 */ 504 extern dtj_status_t dtj_consume(dtj_java_consumer_t *); 505 506 #ifdef __cplusplus 507 } 508 #endif 509 510 #endif /* _DTRACE_JNI_H */ 511