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