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 2006 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_printf_jm; 317 extern jmethodID g_pdataadd_printa_jm; 318 extern jmethodID g_pdatainvalidate_printa_jm; 319 extern jmethodID g_pdataadd_aggrec_jm; 320 extern jmethodID g_pdataadd_printa_str_jm; 321 extern jmethodID g_pdataadd_exit_jm; 322 extern jmethodID g_pdataattach_jm; 323 extern jmethodID g_pdataset_formatted_jm; 324 extern jmethodID g_pdataclear_jm; 325 326 /* Drop */ 327 extern jclass g_drop_jc; 328 extern jmethodID g_dropinit_jm; 329 330 /* Error */ 331 extern jclass g_error_jc; 332 extern jmethodID g_errinit_jm; 333 334 /* ProcessState */ 335 extern jclass g_process_jc; 336 extern jmethodID g_procinit_jm; 337 extern jmethodID g_procexit_jm; 338 339 /* Aggregate */ 340 extern jclass g_agg_jc; 341 extern jmethodID g_agginit_jm; 342 extern jmethodID g_aggaddrec_jm; 343 344 /* AggregateSpec */ 345 extern jclass g_aggspec_jc; 346 extern jmethodID g_aggspec_included_jm; 347 extern jmethodID g_aggspec_cleared_jm; 348 349 /* Tuple */ 350 extern jclass g_tuple_jc; 351 extern jmethodID g_tupleinit_jm; 352 extern jmethodID g_tupleadd_jm; 353 extern jmethodID g_tuplesize_jm; 354 extern jfieldID g_tuple_EMPTY_jsf; 355 356 /* AggregationRecord */ 357 extern jclass g_aggrec_jc; 358 extern jmethodID g_aggrecinit_jm; 359 extern jmethodID g_aggrecget_tuple_jm; 360 361 /* SumValue */ 362 extern jclass g_aggsum_jc; 363 extern jmethodID g_aggsuminit_jm; 364 365 /* CountValue */ 366 extern jclass g_aggcount_jc; 367 extern jmethodID g_aggcountinit_jm; 368 369 /* AvgValue */ 370 extern jclass g_aggavg_jc; 371 extern jmethodID g_aggavginit_jm; 372 373 /* MinValue */ 374 extern jclass g_aggmin_jc; 375 extern jmethodID g_aggmininit_jm; 376 377 /* MaxValue */ 378 extern jclass g_aggmax_jc; 379 extern jmethodID g_aggmaxinit_jm; 380 381 /* KernelStackRecord */ 382 extern jclass g_stack_jc; 383 extern jmethodID g_parsestack_jsm; 384 extern jmethodID g_stackinit_jm; 385 extern jmethodID g_stackset_frames_jm; 386 387 /* UserStackRecord */ 388 extern jclass g_ustack_jc; 389 extern jmethodID g_ustackinit_jm; 390 extern jmethodID g_ustackset_frames_jm; 391 392 /* Distribution */ 393 extern jclass g_adist_jc; 394 extern jmethodID g_dist_normal_jm; 395 396 /* LogDistribution */ 397 extern jclass g_dist_jc; 398 extern jmethodID g_distinit_jm; 399 400 /* LinearDistribution */ 401 extern jclass g_ldist_jc; 402 extern jmethodID g_ldistinit_jm; 403 404 /* 405 * Populates the java class references and associated method and field IDs 406 * declared in this file (above). 407 * 408 * Throws NoClassDefFoundError, NoSuchMethodError, or NoSuchFieldError if any 409 * dtj_table_entry_t in dtj_jnitab.c is incorrect. 410 */ 411 extern dtj_status_t dtj_load(JNIEnv *); 412 413 /* 414 * Functions that create a structure return NULL if out of memory. A Java 415 * OutOfMemoryError is pending in that case. 416 */ 417 extern dtj_request_t *dtj_request_create(JNIEnv *, dtj_request_type_t, ...); 418 extern dtj_program_t *dtj_program_create(JNIEnv *, dtj_program_type_t, 419 const char *); 420 extern dtj_aggval_t *dtj_aggval_create(JNIEnv *, jobject, const char *, 421 int64_t); 422 423 /* 424 * uu_list_t element destructors' signatures match uuwrap_value_destroy_f 425 */ 426 extern void dtj_request_destroy(void *, void *); /* expects NULL user arg */ 427 extern void dtj_program_destroy(void *, void *); /* expects NULL user arg */ 428 extern void dtj_aggval_destroy(void *, void *); /* expects JNIEnv * user arg */ 429 430 /* Allocates and frees per-consumer state kept in the global consumer table */ 431 extern dtj_consumer_t *dtj_consumer_create(JNIEnv *); 432 extern void dtj_consumer_destroy(dtj_consumer_t *); 433 434 /* Sets callback handlers before calling dtrace_go() */ 435 extern dtj_status_t dtj_set_callback_handlers(dtj_java_consumer_t *); 436 437 /* 438 * Initializes Java Object references cached across multiple functions called 439 * within the consumer loop. Deletes the references after exiting the consumer 440 * loop. It is only necessary to initialize and finalize a dtj_java_consumer_t 441 * if the native method call will enter the consumer loop. 442 */ 443 extern dtj_status_t dtj_java_consumer_init(JNIEnv *, dtj_java_consumer_t *); 444 extern void dtj_java_consumer_fini(JNIEnv *, dtj_java_consumer_t *); 445 446 /* 447 * Throws a DTraceException with a message constructed from the given format 448 * string and variable arg list. 449 */ 450 extern void dtj_throw_dtrace_exception(dtj_java_consumer_t *, 451 const char *, ...); 452 453 /* Returns NULL if pending Java Exception or OutOfMemoryError */ 454 extern jobject dtj_new_probedesc(dtj_java_consumer_t *, 455 const dtrace_probedesc_t *); 456 extern jobject dtj_new_probeinfo(dtj_java_consumer_t *, 457 const dtrace_probeinfo_t *); 458 extern jobject dtj_new_attribute(dtj_java_consumer_t *, 459 const dtrace_attribute_t *); 460 461 /* 462 * Returns NULL if the given fault is unrecognized, otherwise returns the name 463 * of the fault, guaranteed not to change across multiple versions of this API 464 * even if the integer value changes in libdtrace. 465 */ 466 extern const char *dtj_get_fault_name(int); 467 468 /* Gets the libdtrace error number and message */ 469 extern dtj_status_t dtj_get_dtrace_error(dtj_java_consumer_t *, dtj_error_t *); 470 471 /* Stops the DTrace consumer */ 472 extern void dtj_stop(dtj_java_consumer_t *); 473 474 /* 475 * The Consumer getAggregate() method runs in the caller's current thread 476 * separate from the consumer loop. 477 */ 478 extern jobject dtj_get_aggregate(dtj_java_consumer_t *); 479 480 /* 481 * A blocking call that runs the consumer loop. If this function returns an 482 * error status, it is necessary to call stop() in order to dtrace_stop() the 483 * consumer in libdtrace (it is safe to call stop() in either case). 484 */ 485 extern dtj_status_t dtj_consume(dtj_java_consumer_t *); 486 487 #ifdef __cplusplus 488 } 489 #endif 490 491 #endif /* _DTRACE_JNI_H */ 492