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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdlib.h> 30 #include <stddef.h> 31 #include <limits.h> 32 #include <strings.h> 33 #include <pthread.h> 34 #include <dtrace_jni.h> 35 36 /* 37 * dtj_jnitab.c defines the JNI table of classes, methods, and fields belonging 38 * to the Java DTrace API. Another JNI table defining classes from the JDK is 39 * defined in dtj_util.c. Utility functions specific to the Java DTrace API are 40 * also defined here, while general utilities are defined in dtj_util.c. 41 */ 42 43 static uu_list_pool_t *g_request_pool = NULL; 44 static uu_list_pool_t *g_program_pool = NULL; 45 static uu_list_pool_t *g_aggval_pool = NULL; 46 47 static boolean_t dtj_check_request_pool(void); 48 static boolean_t dtj_check_program_pool(void); 49 static boolean_t dtj_check_aggval_pool(void); 50 51 /* LocalConsumer */ 52 jclass g_caller_jc = 0; 53 jmethodID g_gethandle_jm = 0; 54 jmethodID g_sethandle_jm = 0; 55 jmethodID g_pdatanext_jm = 0; 56 jmethodID g_drop_jm = 0; 57 jmethodID g_error_jm = 0; 58 jmethodID g_proc_jm = 0; 59 jmethodID g_interval_began_jm = 0; 60 jmethodID g_interval_ended_jm = 0; 61 jfieldID g_consumer_lock_jf = 0; 62 63 /* DTraceException */ 64 jclass g_dtx_jc = 0; 65 jmethodID g_dtxinit_jm = 0; 66 67 /* InterfaceAttributes */ 68 jclass g_attr_jc = 0; 69 jmethodID g_attrinit_jm = 0; 70 jmethodID g_attrset_name_jm = 0; 71 jmethodID g_attrset_data_jm = 0; 72 jmethodID g_attrset_class_jm = 0; 73 74 /* ProbeDescription */ 75 jclass g_probedesc_jc = 0; 76 jmethodID g_probedescinit_jm = 0; 77 jfieldID g_probedesc_id_jf = 0; 78 79 /* ProbeInfo */ 80 jclass g_probeinfo_jc = 0; 81 jmethodID g_probeinfoinit_jm = 0; 82 83 /* Probe */ 84 jclass g_probe_jc = 0; 85 jmethodID g_probeinit_jm = 0; 86 87 /* Program */ 88 jclass g_program_jc = 0; 89 jmethodID g_proginit_jm = 0; 90 jfieldID g_progid_jf = 0; 91 jfieldID g_proginfo_jf = 0; 92 93 /* Program.File */ 94 jclass g_programfile_jc = 0; 95 jmethodID g_fproginit_jm = 0; 96 97 /* ProgramInfo */ 98 jclass g_proginfo_jc = 0; 99 jmethodID g_proginfoinit_jm = 0; 100 101 /* Flow */ 102 jclass g_flow_jc = 0; 103 jmethodID g_flowinit_jm = 0; 104 105 /* ProbeData */ 106 jclass g_pdata_jc = 0; 107 jmethodID g_pdatainit_jm = 0; 108 jmethodID g_pdataadd_jm = 0; 109 jmethodID g_pdataadd_rec_jm = 0; 110 jmethodID g_pdataadd_trace_jm = 0; 111 jmethodID g_pdataadd_stack_jm = 0; 112 jmethodID g_pdataadd_symbol_jm = 0; 113 jmethodID g_pdataadd_printf_jm = 0; 114 jmethodID g_pdataadd_printa_jm = 0; 115 jmethodID g_pdatainvalidate_printa_jm = 0; 116 jmethodID g_pdataadd_aggrec_jm = 0; 117 jmethodID g_pdataadd_printa_str_jm = 0; 118 jmethodID g_pdataadd_exit_jm = 0; 119 jmethodID g_pdataattach_jm = 0; 120 jmethodID g_pdataset_formatted_jm = 0; 121 jmethodID g_pdataclear_jm = 0; 122 123 /* Drop */ 124 jclass g_drop_jc = 0; 125 jmethodID g_dropinit_jm = 0; 126 127 /* Error */ 128 jclass g_error_jc = 0; 129 jmethodID g_errinit_jm = 0; 130 131 /* ProcessState */ 132 jclass g_process_jc = 0; 133 jmethodID g_procinit_jm = 0; 134 jmethodID g_procexit_jm = 0; 135 136 /* Aggregate */ 137 jclass g_agg_jc = 0; 138 jmethodID g_agginit_jm = 0; 139 jmethodID g_aggaddrec_jm = 0; 140 141 /* AggregateSpec */ 142 jclass g_aggspec_jc = 0; 143 jmethodID g_aggspec_included_jm = 0; 144 jmethodID g_aggspec_cleared_jm = 0; 145 146 /* Tuple */ 147 jclass g_tuple_jc = 0; 148 jmethodID g_tupleinit_jm = 0; 149 jmethodID g_tupleadd_jm = 0; 150 jmethodID g_tuplesize_jm = 0; 151 jfieldID g_tuple_EMPTY_jsf = 0; 152 153 /* AggregationRecord */ 154 jclass g_aggrec_jc = 0; 155 jmethodID g_aggrecinit_jm = 0; 156 jmethodID g_aggrecget_tuple_jm = 0; 157 158 /* SumValue */ 159 jclass g_aggsum_jc = 0; 160 jmethodID g_aggsuminit_jm = 0; 161 162 /* CountValue */ 163 jclass g_aggcount_jc = 0; 164 jmethodID g_aggcountinit_jm = 0; 165 166 /* AvgValue */ 167 jclass g_aggavg_jc = 0; 168 jmethodID g_aggavginit_jm = 0; 169 170 /* MinValue */ 171 jclass g_aggmin_jc = 0; 172 jmethodID g_aggmininit_jm = 0; 173 174 /* MaxValue */ 175 jclass g_aggmax_jc = 0; 176 jmethodID g_aggmaxinit_jm = 0; 177 178 /* KernelStackRecord */ 179 jclass g_stack_jc = 0; 180 jmethodID g_parsestack_jsm = 0; 181 jmethodID g_stackinit_jm = 0; 182 jmethodID g_stackset_frames_jm = 0; 183 184 /* UserStackRecord */ 185 jclass g_ustack_jc = 0; 186 jmethodID g_ustackinit_jm = 0; 187 jmethodID g_ustackset_frames_jm = 0; 188 189 /* Distribution */ 190 jclass g_adist_jc = 0; 191 jmethodID g_dist_normal_jm = 0; 192 193 /* LogDistribution */ 194 jclass g_dist_jc = 0; 195 jmethodID g_distinit_jm = 0; 196 197 /* LinearDistribution */ 198 jclass g_ldist_jc = 0; 199 jmethodID g_ldistinit_jm = 0; 200 201 /* KernelSymbolRecord */ 202 jclass g_symbol_jc = 0; 203 jmethodID g_symbolinit_jm = 0; 204 jmethodID g_symbolset_name_jm = 0; 205 206 /* UserSymbolRecord */ 207 jclass g_usymbol_jc = 0; 208 jmethodID g_usymbolinit_jm = 0; 209 jmethodID g_usymbolset_name_jm = 0; 210 211 /* ScalarRecord */ 212 jclass g_scalar_jc = 0; 213 jmethodID g_scalarinit_jm = 0; 214 215 216 static dtj_status_t 217 dtj_table_load(JNIEnv *jenv) 218 { 219 /* 220 * If you change this table, increment DTRACE_JNI_VERSION in 221 * dtrace_jni.c. 222 */ 223 static const dtj_table_entry_t table[] = { 224 /* LocalConsumer */ 225 { JCLASS, &g_caller_jc, 226 "org/opensolaris/os/dtrace/LocalConsumer" }, 227 { JMETHOD, &g_gethandle_jm, "getHandle", "()I" }, 228 { JMETHOD, &g_sethandle_jm, "setHandle", "(I)V" }, 229 { JMETHOD, &g_pdatanext_jm, "nextProbeData", 230 "(Lorg/opensolaris/os/dtrace/ProbeData;)V" }, 231 { JMETHOD, &g_drop_jm, "dataDropped", 232 "(Lorg/opensolaris/os/dtrace/Drop;)V" }, 233 { JMETHOD, &g_error_jm, "errorEncountered", 234 "(Lorg/opensolaris/os/dtrace/Error;)V" }, 235 { JMETHOD, &g_proc_jm, "processStateChanged", 236 "(Lorg/opensolaris/os/dtrace/ProcessState;)V" }, 237 { JMETHOD, &g_interval_began_jm, "intervalBegan", "()V" }, 238 { JMETHOD, &g_interval_ended_jm, "intervalEnded", "()V" }, 239 { JFIELD, &g_consumer_lock_jf, "consumerLock", 240 "Ljava/lang/Object;" }, 241 242 /* DTraceException */ 243 { JCLASS, &g_dtx_jc, 244 "org/opensolaris/os/dtrace/DTraceException" }, 245 { JMETHOD, &g_dtxinit_jm, CONSTRUCTOR, 246 "(Ljava/lang/String;)V" }, 247 248 /* InterfaceAttributes */ 249 { JCLASS, &g_attr_jc, 250 "org/opensolaris/os/dtrace/InterfaceAttributes" }, 251 { JMETHOD, &g_attrinit_jm, CONSTRUCTOR, "()V" }, 252 { JMETHOD, &g_attrset_name_jm, "setNameStability", 253 "(Ljava/lang/String;)V" }, 254 { JMETHOD, &g_attrset_data_jm, "setDataStability", 255 "(Ljava/lang/String;)V" }, 256 { JMETHOD, &g_attrset_class_jm, "setDependencyClass", 257 "(Ljava/lang/String;)V" }, 258 259 /* ProbeDescription */ 260 { JCLASS, &g_probedesc_jc, 261 "org/opensolaris/os/dtrace/ProbeDescription" }, 262 { JMETHOD, &g_probedescinit_jm, CONSTRUCTOR, 263 "(Ljava/lang/String;Ljava/lang/String;" 264 "Ljava/lang/String;Ljava/lang/String;)V" }, 265 { JFIELD, &g_probedesc_id_jf, "id", "I" }, 266 267 /* ProbeInfo */ 268 { JCLASS, &g_probeinfo_jc, 269 "org/opensolaris/os/dtrace/ProbeInfo" }, 270 { JMETHOD, &g_probeinfoinit_jm, CONSTRUCTOR, 271 "(Lorg/opensolaris/os/dtrace/InterfaceAttributes;" 272 "Lorg/opensolaris/os/dtrace/InterfaceAttributes;" 273 ")V" }, 274 275 /* Probe */ 276 { JCLASS, &g_probe_jc, "org/opensolaris/os/dtrace/Probe" }, 277 { JMETHOD, &g_probeinit_jm, CONSTRUCTOR, 278 "(Lorg/opensolaris/os/dtrace/ProbeDescription;" 279 "Lorg/opensolaris/os/dtrace/ProbeInfo;)V" }, 280 281 /* Program */ 282 { JCLASS, &g_program_jc, 283 "org/opensolaris/os/dtrace/Program" }, 284 { JMETHOD, &g_proginit_jm, CONSTRUCTOR, "()V" }, 285 { JFIELD, &g_progid_jf, "id", "I" }, 286 { JFIELD, &g_proginfo_jf, "info", 287 "Lorg/opensolaris/os/dtrace/ProgramInfo;" }, 288 289 /* Program.File */ 290 { JCLASS, &g_programfile_jc, 291 "org/opensolaris/os/dtrace/Program$File" }, 292 { JMETHOD, &g_fproginit_jm, CONSTRUCTOR, "()V" }, 293 294 /* ProgramInfo */ 295 { JCLASS, &g_proginfo_jc, 296 "org/opensolaris/os/dtrace/ProgramInfo" }, 297 { JMETHOD, &g_proginfoinit_jm, CONSTRUCTOR, 298 "(Lorg/opensolaris/os/dtrace/InterfaceAttributes;" 299 "Lorg/opensolaris/os/dtrace/InterfaceAttributes;" 300 "I)V" }, 301 302 /* Flow */ 303 { JCLASS, &g_flow_jc, "org/opensolaris/os/dtrace/Flow" }, 304 { JMETHOD, &g_flowinit_jm, CONSTRUCTOR, 305 "(Ljava/lang/String;I)V" }, 306 307 /* ProbeData */ 308 { JCLASS, &g_pdata_jc, 309 "org/opensolaris/os/dtrace/ProbeData" }, 310 { JMETHOD, &g_pdatainit_jm, CONSTRUCTOR, 311 "(IILorg/opensolaris/os/dtrace/ProbeDescription;" 312 "Lorg/opensolaris/os/dtrace/Flow;I)V" }, 313 { JMETHOD, &g_pdataadd_jm, "addDataElement", 314 "(Lorg/opensolaris/os/dtrace/Record;)V" }, 315 { JMETHOD, &g_pdataadd_rec_jm, "addRecord", 316 "(Lorg/opensolaris/os/dtrace/Record;)V" }, 317 { JMETHOD, &g_pdataadd_trace_jm, "addTraceRecord", "(I)V" }, 318 { JMETHOD, &g_pdataadd_stack_jm, "addStackRecord", 319 "(ILjava/lang/String;)V" }, 320 { JMETHOD, &g_pdataadd_symbol_jm, "addSymbolRecord", 321 "(ILjava/lang/String;)V" }, 322 { JMETHOD, &g_pdataadd_printf_jm, "addPrintfRecord", "()V" }, 323 { JMETHOD, &g_pdataadd_printa_jm, "addPrintaRecord", "(JZ)V" }, 324 { JMETHOD, &g_pdatainvalidate_printa_jm, 325 "invalidatePrintaRecord", "()V" }, 326 { JMETHOD, &g_pdataadd_aggrec_jm, "addAggregationRecord", 327 "(Ljava/lang/String;J" 328 "Lorg/opensolaris/os/dtrace/AggregationRecord;)V" }, 329 { JMETHOD, &g_pdataadd_printa_str_jm, 330 "addPrintaFormattedString", 331 "(Lorg/opensolaris/os/dtrace/Tuple;" 332 "Ljava/lang/String;)V" }, 333 { JMETHOD, &g_pdataadd_exit_jm, "addExitRecord", "(I)V" }, 334 { JMETHOD, &g_pdataattach_jm, "attachRecordElements", 335 "(II)V" }, 336 { JMETHOD, &g_pdataset_formatted_jm, "setFormattedString", 337 "(Ljava/lang/String;)V" }, 338 { JMETHOD, &g_pdataclear_jm, "clearNativeElements", "()V" }, 339 340 /* Drop */ 341 { JCLASS, &g_drop_jc, "org/opensolaris/os/dtrace/Drop" }, 342 { JMETHOD, &g_dropinit_jm, CONSTRUCTOR, 343 "(ILjava/lang/String;JJLjava/lang/String;)V" }, 344 345 /* Error */ 346 { JCLASS, &g_error_jc, "org/opensolaris/os/dtrace/Error" }, 347 { JMETHOD, &g_errinit_jm, CONSTRUCTOR, 348 "(Lorg/opensolaris/os/dtrace/ProbeDescription;IIII" 349 "Ljava/lang/String;JLjava/lang/String;)V" }, 350 351 /* ProcessState */ 352 { JCLASS, &g_process_jc, 353 "org/opensolaris/os/dtrace/ProcessState" }, 354 { JMETHOD, &g_procinit_jm, CONSTRUCTOR, 355 "(ILjava/lang/String;ILjava/lang/String;" 356 "Ljava/lang/Integer;Ljava/lang/String;)V" }, 357 { JMETHOD, &g_procexit_jm, "setExitStatus", "(I)V" }, 358 359 /* Aggregate */ 360 { JCLASS, &g_agg_jc, "org/opensolaris/os/dtrace/Aggregate" }, 361 { JMETHOD, &g_agginit_jm, CONSTRUCTOR, "(J)V" }, 362 { JMETHOD, &g_aggaddrec_jm, "addRecord", 363 "(Ljava/lang/String;J" 364 "Lorg/opensolaris/os/dtrace/AggregationRecord;)V" }, 365 366 /* AggregateSpec */ 367 { JCLASS, &g_aggspec_jc, 368 "org/opensolaris/os/dtrace/AggregateSpec" }, 369 { JMETHOD, &g_aggspec_included_jm, "isIncluded", 370 "(Ljava/lang/String;)Z" }, 371 { JMETHOD, &g_aggspec_cleared_jm, "isCleared", 372 "(Ljava/lang/String;)Z" }, 373 374 /* Tuple */ 375 { JCLASS, &g_tuple_jc, "org/opensolaris/os/dtrace/Tuple" }, 376 { JMETHOD, &g_tupleinit_jm, CONSTRUCTOR, "()V" }, 377 { JMETHOD, &g_tupleadd_jm, "addElement", 378 "(Lorg/opensolaris/os/dtrace/ValueRecord;)V" }, 379 { JMETHOD, &g_tuplesize_jm, "size", "()I" }, 380 { JFIELD_STATIC, &g_tuple_EMPTY_jsf, "EMPTY", 381 "Lorg/opensolaris/os/dtrace/Tuple;" }, 382 383 /* AggregationRecord */ 384 { JCLASS, &g_aggrec_jc, 385 "org/opensolaris/os/dtrace/AggregationRecord" }, 386 { JMETHOD, &g_aggrecinit_jm, CONSTRUCTOR, 387 "(Lorg/opensolaris/os/dtrace/Tuple;" 388 "Lorg/opensolaris/os/dtrace/AggregationValue;)V" }, 389 { JMETHOD, &g_aggrecget_tuple_jm, "getTuple", 390 "()Lorg/opensolaris/os/dtrace/Tuple;" }, 391 392 /* SumValue */ 393 { JCLASS, &g_aggsum_jc, 394 "org/opensolaris/os/dtrace/SumValue" }, 395 { JMETHOD, &g_aggsuminit_jm, CONSTRUCTOR, "(J)V" }, 396 397 /* CountValue */ 398 { JCLASS, &g_aggcount_jc, 399 "org/opensolaris/os/dtrace/CountValue" }, 400 { JMETHOD, &g_aggcountinit_jm, CONSTRUCTOR, "(J)V" }, 401 402 /* AvgValue */ 403 { JCLASS, &g_aggavg_jc, 404 "org/opensolaris/os/dtrace/AvgValue" }, 405 { JMETHOD, &g_aggavginit_jm, CONSTRUCTOR, "(JJJ)V" }, 406 407 /* MinValue */ 408 { JCLASS, &g_aggmin_jc, 409 "org/opensolaris/os/dtrace/MinValue" }, 410 { JMETHOD, &g_aggmininit_jm, CONSTRUCTOR, "(J)V" }, 411 412 /* MaxValue */ 413 { JCLASS, &g_aggmax_jc, 414 "org/opensolaris/os/dtrace/MaxValue" }, 415 { JMETHOD, &g_aggmaxinit_jm, CONSTRUCTOR, "(J)V" }, 416 417 /* KernelStackRecord */ 418 { JCLASS, &g_stack_jc, 419 "org/opensolaris/os/dtrace/KernelStackRecord" }, 420 { JMETHOD_STATIC, &g_parsestack_jsm, "parse", 421 "(Ljava/lang/String;)" 422 "[Lorg/opensolaris/os/dtrace/StackFrame;" }, 423 { JMETHOD, &g_stackinit_jm, CONSTRUCTOR, "([B)V" }, 424 { JMETHOD, &g_stackset_frames_jm, "setStackFrames", 425 "([Lorg/opensolaris/os/dtrace/StackFrame;)V" }, 426 427 /* UserStackRecord */ 428 { JCLASS, &g_ustack_jc, 429 "org/opensolaris/os/dtrace/UserStackRecord" }, 430 { JMETHOD, &g_ustackinit_jm, CONSTRUCTOR, "(I[B)V" }, 431 { JMETHOD, &g_ustackset_frames_jm, "setStackFrames", 432 "([Lorg/opensolaris/os/dtrace/StackFrame;)V" }, 433 434 /* Distribution */ 435 { JCLASS, &g_adist_jc, 436 "org/opensolaris/os/dtrace/Distribution" }, 437 { JMETHOD, &g_dist_normal_jm, "normalizeBuckets", "(J)V" }, 438 439 /* LogDistribution */ 440 { JCLASS, &g_dist_jc, 441 "org/opensolaris/os/dtrace/LogDistribution" }, 442 { JMETHOD, &g_distinit_jm, CONSTRUCTOR, "([J)V" }, 443 444 /* LinearDistribution */ 445 { JCLASS, &g_ldist_jc, 446 "org/opensolaris/os/dtrace/LinearDistribution" }, 447 { JMETHOD, &g_ldistinit_jm, CONSTRUCTOR, "(JJ[J)V" }, 448 449 /* KernelSymbolRecord */ 450 { JCLASS, &g_symbol_jc, 451 "org/opensolaris/os/dtrace/KernelSymbolRecord" }, 452 { JMETHOD, &g_symbolinit_jm, CONSTRUCTOR, "(J)V" }, 453 { JMETHOD, &g_symbolset_name_jm, "setSymbol", 454 "(Ljava/lang/String;)V" }, 455 456 /* UserSymbolRecord */ 457 { JCLASS, &g_usymbol_jc, 458 "org/opensolaris/os/dtrace/UserSymbolRecord" }, 459 { JMETHOD, &g_usymbolinit_jm, CONSTRUCTOR, "(IJ)V" }, 460 { JMETHOD, &g_usymbolset_name_jm, "setSymbol", 461 "(Ljava/lang/String;)V" }, 462 463 /* ScalarRecord */ 464 { JCLASS, &g_scalar_jc, 465 "org/opensolaris/os/dtrace/ScalarRecord" }, 466 { JMETHOD, &g_scalarinit_jm, CONSTRUCTOR, 467 "(Ljava/lang/Object;I)V" }, 468 469 { DTJ_TYPE_END } 470 }; 471 472 return (dtj_cache_jni_classes(jenv, table)); 473 } 474 475 dtj_status_t 476 dtj_load(JNIEnv *jenv) 477 { 478 if (dtj_load_common(jenv) != DTJ_OK) { 479 /* Java Error pending */ 480 return (DTJ_ERR); 481 } 482 483 return (dtj_table_load(jenv)); 484 } 485 486 static boolean_t 487 dtj_check_request_pool(void) 488 { 489 if (!g_request_pool) { 490 g_request_pool = uu_list_pool_create("g_request_pool", 491 sizeof (dtj_request_t), 492 offsetof(dtj_request_t, dtjr_node), 493 dtj_pointer_list_entry_cmp, 494 (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0)); 495 if (!g_request_pool) { 496 return (B_FALSE); 497 } 498 } 499 return (B_TRUE); 500 } 501 502 dtj_request_t * 503 dtj_request_create(JNIEnv *jenv, dtj_request_type_t type, ...) 504 { 505 dtj_request_t *r; 506 507 if (!dtj_check_request_pool()) { 508 dtj_throw_out_of_memory(jenv, 509 "Failed to allocate request pool"); 510 return (NULL); 511 } 512 513 r = uu_zalloc(sizeof (dtj_request_t)); 514 if (r) { 515 uu_list_node_init(r, &r->dtjr_node, g_request_pool); 516 r->dtjr_type = type; 517 r->dtjr_args = dtj_string_list_create(); 518 if (r->dtjr_args) { 519 va_list ap; 520 const char *arg; 521 int i, len; 522 523 va_start(ap, type); 524 switch (type) { 525 case DTJ_REQUEST_OPTION: 526 len = 2; 527 break; 528 default: 529 len = 0; 530 } 531 532 for (i = 0; i < len; ++i) { 533 arg = va_arg(ap, char *); 534 if (!dtj_string_list_add(r->dtjr_args, arg)) { 535 dtj_throw_out_of_memory(jenv, 536 "Failed to add request arg"); 537 uu_list_node_fini(r, &r->dtjr_node, 538 g_request_pool); 539 dtj_request_destroy(r, NULL); 540 r = NULL; 541 } 542 } 543 va_end(ap); 544 } else { 545 dtj_throw_out_of_memory(jenv, 546 "Failed to allocate request arglist"); 547 uu_list_node_fini(r, &r->dtjr_node, g_request_pool); 548 dtj_request_destroy(r, NULL); 549 r = NULL; 550 } 551 } else { 552 dtj_throw_out_of_memory(jenv, 553 "Failed to allocate request"); 554 } 555 556 return (r); 557 } 558 559 static boolean_t 560 dtj_check_program_pool(void) 561 { 562 if (!g_program_pool) { 563 g_program_pool = uu_list_pool_create("g_program_pool", 564 sizeof (dtj_program_t), 565 offsetof(dtj_program_t, dtjp_node), 566 dtj_pointer_list_entry_cmp, 567 (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0)); 568 if (!g_program_pool) { 569 return (B_FALSE); 570 } 571 } 572 return (B_TRUE); 573 } 574 575 dtj_program_t * 576 dtj_program_create(JNIEnv *jenv, dtj_program_type_t type, const char *name) 577 { 578 dtj_program_t *p; 579 580 if (!dtj_check_program_pool()) { 581 dtj_throw_out_of_memory(jenv, 582 "Failed to allocate program pool"); 583 return (NULL); 584 } 585 586 p = uu_zalloc(sizeof (dtj_program_t)); 587 if (p) { 588 char *program_name; 589 590 uu_list_node_init(p, &p->dtjp_node, g_program_pool); 591 p->dtjp_type = type; 592 program_name = malloc((size_t) 593 (sizeof (char)) * (strlen(name) + 1)); 594 if (program_name) { 595 (void) strcpy(program_name, name); 596 p->dtjp_name = program_name; 597 p->dtjp_enabled = B_FALSE; 598 } else { 599 dtj_throw_out_of_memory(jenv, 600 "Failed to allocate program name"); 601 uu_list_node_fini(p, &p->dtjp_node, g_program_pool); 602 dtj_program_destroy(p, NULL); 603 p = NULL; 604 } 605 } else { 606 dtj_throw_out_of_memory(jenv, 607 "Failed to allocate program"); 608 } 609 610 return (p); 611 } 612 613 static boolean_t 614 dtj_check_aggval_pool(void) 615 { 616 if (!g_aggval_pool) { 617 g_aggval_pool = uu_list_pool_create("g_aggval_pool", 618 sizeof (dtj_aggval_t), 619 offsetof(dtj_aggval_t, dtja_node), 620 dtj_pointer_list_entry_cmp, 621 (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0)); 622 if (!g_aggval_pool) { 623 return (B_FALSE); 624 } 625 } 626 return (B_TRUE); 627 } 628 629 dtj_aggval_t * 630 dtj_aggval_create(JNIEnv *jenv, jobject aggval, const char *aggname, 631 int64_t aggid) 632 { 633 dtj_aggval_t *e; 634 635 if (!dtj_check_aggval_pool()) { 636 dtj_throw_out_of_memory(jenv, 637 "Failed to allocate aggval entry pool"); 638 return (NULL); 639 } 640 641 e = uu_zalloc(sizeof (dtj_aggval_t)); 642 if (e) { 643 char *a_name; 644 645 uu_list_node_init(e, &e->dtja_node, g_aggval_pool); 646 e->dtja_value = aggval; 647 a_name = malloc((size_t) 648 (sizeof (char)) * (strlen(aggname) + 1)); 649 if (a_name) { 650 (void) strcpy(a_name, aggname); 651 e->dtja_aggname = a_name; 652 } else { 653 dtj_throw_out_of_memory(jenv, 654 "Failed to allocate aggregation name"); 655 uu_list_node_fini(e, &e->dtja_node, g_aggval_pool); 656 /* caller responsible for input java reference */ 657 e->dtja_value = NULL; 658 dtj_aggval_destroy(e, jenv); 659 e = NULL; 660 } 661 e->dtja_aggid = aggid; 662 } else { 663 dtj_throw_out_of_memory(jenv, 664 "Failed to allocate aggval entry"); 665 } 666 667 return (e); 668 } 669 670 dtj_status_t 671 dtj_java_consumer_init(JNIEnv *jenv, dtj_java_consumer_t *jc) 672 { 673 if (!dtj_check_aggval_pool()) { 674 dtj_throw_out_of_memory(jenv, 675 "Failed to allocate aggval pool"); 676 return (DTJ_ERR); 677 } 678 679 jc->dtjj_aggval_list = uu_list_create(g_aggval_pool, NULL, 680 (g_dtj_util_debug ? UU_LIST_DEBUG : 0)); 681 if (!jc->dtjj_aggval_list) { 682 dtj_throw_out_of_memory(jenv, 683 "Failed to allocate aggval list"); 684 return (DTJ_ERR); 685 } 686 687 /* Does not throw exceptions */ 688 jc->dtjj_consumer_lock = (*jenv)->GetObjectField(jenv, jc->dtjj_caller, 689 g_consumer_lock_jf); 690 691 return (DTJ_OK); 692 } 693 694 void 695 dtj_java_consumer_fini(JNIEnv *jenv, dtj_java_consumer_t *jc) 696 { 697 if (jc) { 698 if (jc->dtjj_probedata) { 699 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_probedata); 700 jc->dtjj_probedata = NULL; 701 } 702 if (jc->dtjj_printa_buffer) { 703 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_printa_buffer); 704 jc->dtjj_printa_buffer = NULL; 705 } 706 if (jc->dtjj_aggregate) { 707 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_aggregate); 708 jc->dtjj_aggregate = NULL; 709 } 710 if (jc->dtjj_tuple) { 711 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 712 jc->dtjj_tuple = NULL; 713 } 714 if (jc->dtjj_aggval_list) { 715 dtj_list_destroy(jc->dtjj_aggval_list, 716 dtj_aggval_destroy, jenv); 717 jc->dtjj_aggval_list = NULL; 718 } 719 720 /* 721 * aggregate_spec records an input argument to a native JNI 722 * function (a reference we did not create), so we are not 723 * responsible for it. 724 */ 725 jc->dtjj_aggregate_spec = NULL; 726 727 /* 728 * probelist records an in-out argument to a native JNI function 729 * (a reference we did not create), so we are not responsible 730 * for it. 731 */ 732 jc->dtjj_probelist = NULL; 733 734 if (jc->dtjj_exception) { 735 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_exception); 736 jc->dtjj_exception = NULL; 737 } 738 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_consumer_lock); 739 jc->dtjj_consumer_lock = NULL; 740 } 741 } 742 743 dtj_consumer_t * 744 dtj_consumer_create(JNIEnv *jenv) 745 { 746 dtj_consumer_t *c; 747 748 if (!dtj_check_request_pool()) { 749 dtj_throw_out_of_memory(jenv, 750 "Failed to allocate request pool"); 751 return (NULL); 752 } 753 754 if (!dtj_check_program_pool()) { 755 dtj_throw_out_of_memory(jenv, 756 "Failed to allocate program pool"); 757 return (NULL); 758 } 759 760 c = uu_zalloc(sizeof (dtj_consumer_t)); 761 if (c) { 762 c->dtjc_request_list = uu_list_create(g_request_pool, NULL, 763 (g_dtj_util_debug ? UU_LIST_DEBUG : 0)); 764 if (!c->dtjc_request_list) { 765 dtj_throw_out_of_memory(jenv, 766 "Failed to allocate consumer request list"); 767 dtj_consumer_destroy(c); 768 return (NULL); 769 } 770 (void) pthread_mutex_init(&c->dtjc_request_list_lock, NULL); 771 772 c->dtjc_program_list = uu_list_create(g_program_pool, NULL, 773 (g_dtj_util_debug ? UU_LIST_DEBUG : 0)); 774 if (!c->dtjc_program_list) { 775 dtj_throw_out_of_memory(jenv, 776 "Failed to allocate consumer program list"); 777 dtj_consumer_destroy(c); 778 return (NULL); 779 } 780 781 c->dtjc_probedata_rec_i = 0; 782 c->dtjc_probedata_act = DTRACEACT_NONE; 783 c->dtjc_aggid = -1; 784 c->dtjc_expected = -1; 785 c->dtjc_state = DTJ_CONSUMER_INIT; 786 } else { 787 dtj_throw_out_of_memory(jenv, 788 "Failed to allocate consumer"); 789 } 790 791 return (c); 792 } 793 794 void 795 /* ARGSUSED */ 796 dtj_request_destroy(void *v, void *arg) 797 { 798 if (v) { 799 dtj_request_t *r = v; 800 dtj_string_list_destroy(r->dtjr_args); 801 uu_list_node_fini(r, &r->dtjr_node, g_request_pool); 802 bzero(v, sizeof (dtj_request_t)); 803 uu_free(v); 804 } 805 } 806 807 void 808 /* ARGSUSED */ 809 dtj_program_destroy(void *v, void *arg) 810 { 811 if (v) { 812 dtj_program_t *p = v; 813 if (p->dtjp_name) { 814 free((void *)p->dtjp_name); 815 } 816 uu_list_node_fini(p, &p->dtjp_node, g_program_pool); 817 bzero(v, sizeof (dtj_program_t)); 818 uu_free(v); 819 } 820 } 821 822 void 823 dtj_aggval_destroy(void *v, void *arg) 824 { 825 if (v) { 826 dtj_aggval_t *a = v; 827 if (a->dtja_value && arg) { 828 JNIEnv *jenv = arg; 829 (*jenv)->DeleteLocalRef(jenv, a->dtja_value); 830 } 831 if (a->dtja_aggname) { 832 free((void *)a->dtja_aggname); 833 } 834 uu_list_node_fini(a, &a->dtja_node, g_aggval_pool); 835 bzero(v, sizeof (dtj_aggval_t)); 836 uu_free(v); 837 } 838 } 839 840 /* 841 * Frees per-consumer state. Assumes that the DTrace handle has been closed 842 * already. 843 */ 844 void 845 dtj_consumer_destroy(dtj_consumer_t *c) 846 { 847 if (c) { 848 dtj_list_destroy(c->dtjc_request_list, dtj_request_destroy, 849 NULL); 850 (void) pthread_mutex_destroy(&c->dtjc_request_list_lock); 851 dtj_list_destroy(c->dtjc_program_list, dtj_program_destroy, 852 NULL); 853 /* 854 * Cannot dtrace_proc_release the c->process_list proc 855 * elements here, because we need the dtrace handle for that. 856 * By the time this destructor is called, the dtrace handle is 857 * already closed. The proc elements are released in 858 * dtrace_jni.c _close(). 859 */ 860 if (c->dtjc_process_list) { 861 dtj_list_destroy(c->dtjc_process_list, NULL, NULL); 862 } 863 bzero(c, sizeof (dtj_consumer_t)); 864 uu_free(c); 865 } 866 } 867 868 void 869 dtj_throw_dtrace_exception(dtj_java_consumer_t *jc, const char *fmt, ...) 870 { 871 JNIEnv *jenv = jc->dtjj_jenv; 872 873 va_list ap; 874 char msg[DTJ_MSG_SIZE]; 875 876 jobject message = NULL; 877 jobject exception = NULL; 878 879 va_start(ap, fmt); 880 (void) vsnprintf(msg, sizeof (msg), fmt, ap); 881 va_end(ap); 882 883 message = dtj_NewStringNative(jenv, msg); 884 if (!message) { 885 return; /* java exception pending */ 886 } 887 888 exception = (*jenv)->NewObject(jenv, g_dtx_jc, g_dtxinit_jm, message); 889 (*jenv)->DeleteLocalRef(jenv, message); 890 if (exception) { 891 (*jenv)->Throw(jenv, exception); 892 (*jenv)->DeleteLocalRef(jenv, exception); 893 } 894 } 895