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