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