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