1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <ctype.h> 31 #include <limits.h> 32 #include <errno.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <strings.h> 36 #include <sys/wait.h> 37 #include <limits.h> 38 #include <signal.h> 39 #include <libproc.h> 40 #include <pthread.h> 41 #include <dtrace_jni.h> 42 43 /* 44 * Implements the work done in the running consumer loop. The native Java 45 * methods (JNI layer) are implemented in dtrace_jni.c. 46 */ 47 48 /* Record handler passed to dtrace_work() */ 49 static int dtj_chewrec(const dtrace_probedata_t *, const dtrace_recdesc_t *, 50 void *); 51 /* Probe data handler passed to dtrace_work() */ 52 static int dtj_chew(const dtrace_probedata_t *, void *); 53 54 /* Processes requests from LocalConsumer enqueued during dtrace_sleep() */ 55 static dtj_status_t dtj_process_requests(dtj_java_consumer_t *); 56 57 /* 58 * Callback handlers set in dtj_set_callback_handlers(), called from libdtrace 59 * in the consumer loop (from dtrace_work()) 60 */ 61 static int dtj_drophandler(const dtrace_dropdata_t *, void *); 62 static int dtj_errhandler(const dtrace_errdata_t *, void *); 63 static void dtj_prochandler(struct ps_prochandle *, const char *, void *); 64 static int dtj_setopthandler(const dtrace_setoptdata_t *, void *); 65 /* 66 * Buffered output handler called from libdtrace in both the consumer loop (from 67 * dtrace_work()) and the get_aggregate() function (from 68 * dtrace_aggregate_print()). 69 */ 70 static int dtj_bufhandler(const dtrace_bufdata_t *, void *); 71 72 /* Conversion of libdtrace data into Java Objects */ 73 static jobject dtj_recdata(dtj_java_consumer_t *, uint32_t, caddr_t); 74 static jobject dtj_bytedata(JNIEnv *, uint32_t, caddr_t); 75 static jobject dtj_new_stack_record(const caddr_t, const dtrace_recdesc_t *, 76 dtj_java_consumer_t *); 77 static jobject dtj_new_probedata_stack_record(const dtrace_probedata_t *, 78 const dtrace_recdesc_t *, dtj_java_consumer_t *); 79 static jobject dtj_new_symbol_record(const caddr_t, const dtrace_recdesc_t *, 80 dtj_java_consumer_t *); 81 static jobject dtj_new_probedata_symbol_record(const dtrace_probedata_t *, 82 const dtrace_recdesc_t *, dtj_java_consumer_t *); 83 /* Aggregation data */ 84 static jobject dtj_new_tuple_stack_record(const dtrace_aggdata_t *, 85 const dtrace_recdesc_t *, const char *, dtj_java_consumer_t *); 86 static jobject dtj_new_tuple_symbol_record(const dtrace_aggdata_t *, 87 const dtrace_recdesc_t *, const char *, dtj_java_consumer_t *); 88 static jobject dtj_new_distribution(const dtrace_aggdata_t *, 89 const dtrace_recdesc_t *, dtj_java_consumer_t *); 90 static jobject dtj_new_aggval(dtj_java_consumer_t *, const dtrace_aggdata_t *, 91 const dtrace_recdesc_t *); 92 static int64_t dtj_average(caddr_t, uint64_t); 93 static int64_t dtj_avg_total(caddr_t, uint64_t); 94 static int64_t dtj_avg_count(caddr_t); 95 96 /* Aggregation functions */ 97 static void dtj_aggwalk_init(dtj_java_consumer_t *); 98 static int dtj_agghandler(const dtrace_bufdata_t *, dtj_java_consumer_t *); 99 static boolean_t dtj_is_included(const dtrace_aggdata_t *, 100 dtj_java_consumer_t *); 101 static void dtj_attach_frames(dtj_java_consumer_t *, jobject, jobjectArray); 102 static void dtj_attach_name(dtj_java_consumer_t *, jobject, jstring); 103 static boolean_t dtj_is_stack_action(dtrace_actkind_t); 104 static boolean_t dtj_is_symbol_action(dtrace_actkind_t); 105 static int dtj_clear(const dtrace_aggdata_t *, void *); 106 107 /* 108 * The consumer loop needs to protect calls to libdtrace functions with a global 109 * lock. JNI native method calls in dtrace_jni.c are already protected and do 110 * not need this function. 111 */ 112 dtj_status_t 113 dtj_get_dtrace_error(dtj_java_consumer_t *jc, dtj_error_t *e) 114 { 115 JNIEnv *jenv = jc->dtjj_jenv; 116 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 117 118 /* Must not call MonitorEnter with a pending exception */ 119 if ((*jenv)->ExceptionCheck(jenv)) { 120 WRAP_EXCEPTION(jenv); 121 return (DTJ_ERR); 122 } 123 /* Grab global lock */ 124 (*jenv)->MonitorEnter(jenv, g_caller_jc); 125 if ((*jenv)->ExceptionCheck(jenv)) { 126 WRAP_EXCEPTION(jenv); 127 return (DTJ_ERR); 128 } 129 e->dtje_number = dtrace_errno(dtp); 130 e->dtje_message = dtrace_errmsg(dtp, e->dtje_number); 131 (*jenv)->MonitorExit(jenv, g_caller_jc); 132 if ((*jenv)->ExceptionCheck(jenv)) { 133 WRAP_EXCEPTION(jenv); 134 return (DTJ_ERR); 135 } 136 return (DTJ_OK); 137 } 138 139 /* 140 * Protected by global lock (LocalConsumer.class) that protects call to 141 * Java_org_opensolaris_os_dtrace_LocalConsumer__1go() 142 */ 143 dtj_status_t 144 dtj_set_callback_handlers(dtj_java_consumer_t *jc) 145 { 146 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 147 dtrace_optval_t optval; 148 149 if (dtrace_handle_buffered(dtp, &dtj_bufhandler, NULL) == -1) { 150 dtj_throw_dtrace_exception(jc, 151 "failed to establish buffered handler: %s", 152 dtrace_errmsg(dtp, dtrace_errno(dtp))); 153 return (DTJ_ERR); 154 } 155 156 if (dtrace_handle_drop(dtp, &dtj_drophandler, NULL) == -1) { 157 dtj_throw_dtrace_exception(jc, 158 "failed to establish drop handler: %s", 159 dtrace_errmsg(dtp, dtrace_errno(dtp))); 160 return (DTJ_ERR); 161 } 162 163 if (dtrace_handle_err(dtp, &dtj_errhandler, NULL) == -1) { 164 dtj_throw_dtrace_exception(jc, 165 "failed to establish error handler: %s", 166 dtrace_errmsg(dtp, dtrace_errno(dtp))); 167 return (DTJ_ERR); 168 } 169 170 if (dtrace_handle_proc(dtp, &dtj_prochandler, NULL) == -1) { 171 dtj_throw_dtrace_exception(jc, 172 "failed to establish proc handler: %s", 173 dtrace_errmsg(dtp, dtrace_errno(dtp))); 174 return (DTJ_ERR); 175 } 176 177 if (dtrace_getopt(dtp, "flowindent", &optval) == -1) { 178 dtj_throw_dtrace_exception(jc, 179 "couldn't get option %s: %s", "flowindent", 180 dtrace_errmsg(dtp, dtrace_errno(dtp))); 181 return (DTJ_ERR); 182 } 183 184 jc->dtjj_consumer->dtjc_flow = (optval != DTRACEOPT_UNSET); 185 186 if (dtrace_handle_setopt(dtp, &dtj_setopthandler, NULL) == -1) { 187 dtj_throw_dtrace_exception(jc, 188 "failed to establish setopt handler: %s", 189 dtrace_errmsg(dtp, dtrace_errno(dtp))); 190 return (DTJ_ERR); 191 } 192 193 return (DTJ_OK); 194 } 195 196 static int 197 /* ARGSUSED */ 198 dtj_drophandler(const dtrace_dropdata_t *data, void *arg) 199 { 200 dtj_java_consumer_t *jc; 201 JNIEnv *jenv; 202 203 const char *dropkind; 204 205 jstring msg = NULL; 206 jstring kind = NULL; 207 jobject drop = NULL; 208 209 jc = pthread_getspecific(g_dtj_consumer_key); 210 jenv = jc->dtjj_jenv; 211 212 msg = dtj_NewStringNative(jenv, data->dtdda_msg); 213 if ((*jenv)->ExceptionCheck(jenv)) { 214 return (DTRACE_HANDLE_ABORT); 215 } 216 switch (data->dtdda_kind) { 217 case DTRACEDROP_PRINCIPAL: 218 dropkind = "PRINCIPAL"; 219 break; 220 case DTRACEDROP_AGGREGATION: 221 dropkind = "AGGREGATION"; 222 break; 223 case DTRACEDROP_DYNAMIC: 224 dropkind = "DYNAMIC"; 225 break; 226 case DTRACEDROP_DYNRINSE: 227 dropkind = "DYNRINSE"; 228 break; 229 case DTRACEDROP_DYNDIRTY: 230 dropkind = "DYNDIRTY"; 231 break; 232 case DTRACEDROP_SPEC: 233 dropkind = "SPEC"; 234 break; 235 case DTRACEDROP_SPECBUSY: 236 dropkind = "SPECBUSY"; 237 break; 238 case DTRACEDROP_SPECUNAVAIL: 239 dropkind = "SPECUNAVAIL"; 240 break; 241 case DTRACEDROP_STKSTROVERFLOW: 242 dropkind = "STKSTROVERFLOW"; 243 break; 244 case DTRACEDROP_DBLERROR: 245 dropkind = "DBLERROR"; 246 break; 247 default: 248 dropkind = "UNKNOWN"; 249 } 250 kind = (*jenv)->NewStringUTF(jenv, dropkind); 251 if ((*jenv)->ExceptionCheck(jenv)) { 252 (*jenv)->DeleteLocalRef(jenv, msg); 253 return (DTRACE_HANDLE_ABORT); 254 } 255 drop = (*jenv)->NewObject(jenv, g_drop_jc, g_dropinit_jm, 256 data->dtdda_cpu, kind, data->dtdda_drops, data->dtdda_total, msg); 257 (*jenv)->DeleteLocalRef(jenv, kind); 258 (*jenv)->DeleteLocalRef(jenv, msg); 259 if ((*jenv)->ExceptionCheck(jenv)) { 260 return (DTRACE_HANDLE_ABORT); 261 } 262 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_drop_jm, drop); 263 (*jenv)->DeleteLocalRef(jenv, drop); 264 if ((*jenv)->ExceptionCheck(jenv)) { 265 return (DTRACE_HANDLE_ABORT); 266 } 267 268 return (DTRACE_HANDLE_OK); 269 } 270 271 static int 272 /* ARGSUSED */ 273 dtj_errhandler(const dtrace_errdata_t *data, void *arg) 274 { 275 dtj_java_consumer_t *jc; 276 JNIEnv *jenv; 277 278 const char *f; 279 int64_t addr; 280 281 jobject probe = NULL; 282 jstring fault = NULL; 283 jstring msg = NULL; 284 jobject error = NULL; 285 286 jc = pthread_getspecific(g_dtj_consumer_key); 287 jenv = jc->dtjj_jenv; 288 289 probe = dtj_new_probedesc(jc, data->dteda_pdesc); 290 if (!probe) { 291 return (DTRACE_HANDLE_ABORT); 292 } 293 f = dtj_get_fault_name(data->dteda_fault); 294 if (f) { 295 fault = (*jenv)->NewStringUTF(jenv, f); 296 if ((*jenv)->ExceptionCheck(jenv)) { 297 (*jenv)->DeleteLocalRef(jenv, probe); 298 return (DTRACE_HANDLE_ABORT); 299 } 300 } 301 switch (data->dteda_fault) { 302 case DTRACEFLT_BADADDR: 303 case DTRACEFLT_BADALIGN: 304 addr = data->dteda_addr; 305 break; 306 default: 307 addr = -1; 308 } 309 msg = dtj_NewStringNative(jenv, data->dteda_msg); 310 if ((*jenv)->ExceptionCheck(jenv)) { 311 (*jenv)->DeleteLocalRef(jenv, probe); 312 (*jenv)->DeleteLocalRef(jenv, fault); 313 return (DTRACE_HANDLE_ABORT); 314 } 315 error = (*jenv)->NewObject(jenv, g_error_jc, g_errinit_jm, 316 probe, 317 data->dteda_edesc->dtepd_epid, 318 data->dteda_cpu, 319 data->dteda_action, 320 data->dteda_offset, 321 fault, addr, msg); 322 (*jenv)->DeleteLocalRef(jenv, msg); 323 (*jenv)->DeleteLocalRef(jenv, fault); 324 (*jenv)->DeleteLocalRef(jenv, probe); 325 if ((*jenv)->ExceptionCheck(jenv)) { 326 return (DTRACE_HANDLE_ABORT); 327 } 328 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_error_jm, error); 329 (*jenv)->DeleteLocalRef(jenv, error); 330 if ((*jenv)->ExceptionCheck(jenv)) { 331 return (DTRACE_HANDLE_ABORT); 332 } 333 334 return (DTRACE_HANDLE_OK); 335 } 336 337 /* 338 * Since the function signature does not allow us to return an abort signal, we 339 * need to temporarily clear any pending exception before returning, since 340 * without the abort we can't guarantee that the exception will be checked in 341 * time to prevent invalid JNI function calls. 342 */ 343 static void 344 /* ARGSUSED */ 345 dtj_prochandler(struct ps_prochandle *P, const char *msg, void *arg) 346 { 347 dtj_java_consumer_t *jc; 348 JNIEnv *jenv; 349 350 const psinfo_t *prp = Ppsinfo(P); 351 int pid = Pstatus(P)->pr_pid; 352 int signal = -1; 353 char signame[SIG2STR_MAX]; 354 const char *statusname; 355 int exit = INT_MAX; /* invalid initial status */ 356 357 jstring status = NULL; 358 jstring signalName = NULL; 359 jstring message = NULL; 360 jobject process = NULL; 361 362 jc = pthread_getspecific(g_dtj_consumer_key); 363 jenv = jc->dtjj_jenv; 364 365 switch (Pstate(P)) { 366 case PS_RUN: 367 statusname = "RUN"; 368 break; 369 case PS_STOP: 370 statusname = "STOP"; 371 break; 372 case PS_UNDEAD: 373 statusname = "UNDEAD"; 374 if (prp != NULL) { 375 exit = WEXITSTATUS(prp->pr_wstat); 376 } 377 if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { 378 signal = WTERMSIG(prp->pr_wstat); 379 (void) proc_signame(signal, signame, sizeof (signame)); 380 signalName = (*jenv)->NewStringUTF(jenv, signame); 381 if ((*jenv)->ExceptionCheck(jenv)) { 382 goto proc_end; 383 } 384 } 385 ++jc->dtjj_consumer->dtjc_procs_ended; 386 break; 387 case PS_LOST: 388 statusname = "LOST"; 389 ++jc->dtjj_consumer->dtjc_procs_ended; 390 break; 391 case PS_DEAD: 392 /* 393 * PS_DEAD not handled by dtrace.c prochandler, still this is a 394 * case of process termination and it can't hurt to handle it. 395 */ 396 statusname = "DEAD"; 397 ++jc->dtjj_consumer->dtjc_procs_ended; 398 break; 399 default: 400 /* 401 * Unexpected, but erring on the side of tolerance by not 402 * crashing the consumer. Failure to notify listeners of 403 * process state not handled by the dtrace.c prochandler does 404 * not seem serious. 405 */ 406 return; 407 } 408 409 status = (*jenv)->NewStringUTF(jenv, statusname); 410 if ((*jenv)->ExceptionCheck(jenv)) { 411 (*jenv)->DeleteLocalRef(jenv, signalName); 412 goto proc_end; 413 } 414 if (msg) { 415 message = dtj_NewStringNative(jenv, msg); 416 if (!message) { 417 (*jenv)->DeleteLocalRef(jenv, status); 418 (*jenv)->DeleteLocalRef(jenv, signalName); 419 goto proc_end; 420 } 421 } 422 process = (*jenv)->NewObject(jenv, g_process_jc, g_procinit_jm, 423 pid, status, signal, signalName, NULL, message); 424 (*jenv)->DeleteLocalRef(jenv, status); 425 (*jenv)->DeleteLocalRef(jenv, signalName); 426 (*jenv)->DeleteLocalRef(jenv, message); 427 if ((*jenv)->ExceptionCheck(jenv)) { 428 goto proc_end; 429 } 430 if (exit != INT_MAX) { 431 /* valid exit status */ 432 (*jenv)->CallVoidMethod(jenv, process, g_procexit_jm, exit); 433 if ((*jenv)->ExceptionCheck(jenv)) { 434 (*jenv)->DeleteLocalRef(jenv, process); 435 goto proc_end; 436 } 437 } 438 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_proc_jm, process); 439 (*jenv)->DeleteLocalRef(jenv, process); 440 441 proc_end: 442 443 if ((*jenv)->ExceptionCheck(jenv)) { 444 /* 445 * Save the exception so we can rethrow it later when it's safe. 446 */ 447 if (!jc->dtjj_exception) { 448 jthrowable e = (*jenv)->ExceptionOccurred(jenv); 449 jc->dtjj_exception = e; 450 } 451 (*jenv)->ExceptionClear(jenv); 452 } 453 } 454 455 static int 456 /* ARGSUSED */ 457 dtj_setopthandler(const dtrace_setoptdata_t *data, void *arg) 458 { 459 dtj_java_consumer_t *jc; 460 461 jc = pthread_getspecific(g_dtj_consumer_key); 462 if (strcmp(data->dtsda_option, "flowindent") == 0) { 463 jc->dtjj_consumer->dtjc_flow = 464 (data->dtsda_newval != DTRACEOPT_UNSET); 465 } 466 return (DTRACE_HANDLE_OK); 467 } 468 469 /* 470 * Most of this function lifted from libdtrace/common/dt_consume.c 471 * dt_print_bytes(). 472 */ 473 static jobject 474 dtj_bytedata(JNIEnv *jenv, uint32_t nbytes, caddr_t addr) 475 { 476 /* 477 * If the byte stream is a series of printable characters, followed by 478 * a terminating byte, we print it out as a string. Otherwise, we 479 * assume that it's something else and just print the bytes. 480 */ 481 int i, j; 482 char *c = addr; 483 484 jobject jobj = NULL; /* return value */ 485 486 if (nbytes == 0) { 487 return ((*jenv)->NewStringUTF(jenv, "")); 488 } 489 490 for (i = 0; i < nbytes; i++) { 491 /* 492 * We define a "printable character" to be one for which 493 * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 494 * or a character which is either backspace or the bell. 495 * Backspace and the bell are regrettably special because 496 * they fail the first two tests -- and yet they are entirely 497 * printable. These are the only two control characters that 498 * have meaning for the terminal and for which isprint(3C) and 499 * isspace(3C) return 0. 500 */ 501 if (isprint(c[i]) || isspace(c[i]) || 502 c[i] == '\b' || c[i] == '\a') 503 continue; 504 505 if (c[i] == '\0' && i > 0) { 506 /* 507 * This looks like it might be a string. Before we 508 * assume that it is indeed a string, check the 509 * remainder of the byte range; if it contains 510 * additional non-nul characters, we'll assume that 511 * it's a binary stream that just happens to look like 512 * a string. 513 */ 514 for (j = i + 1; j < nbytes; j++) { 515 if (c[j] != '\0') 516 break; 517 } 518 519 if (j != nbytes) 520 break; 521 522 /* It's a string */ 523 return (dtj_NewStringNative(jenv, (char *)addr)); 524 } 525 526 break; 527 } 528 529 if (i == nbytes) { 530 /* 531 * The byte range is all printable characters, but there is 532 * no trailing nul byte. We'll assume that it's a string. 533 */ 534 char *s = malloc(nbytes + 1); 535 if (!s) { 536 dtj_throw_out_of_memory(jenv, 537 "failed to allocate string value"); 538 return (NULL); 539 } 540 (void) strncpy(s, c, nbytes); 541 s[nbytes] = '\0'; 542 jobj = dtj_NewStringNative(jenv, s); 543 free(s); 544 return (jobj); 545 } 546 547 /* return byte array */ 548 jobj = (*jenv)->NewByteArray(jenv, nbytes); 549 if ((*jenv)->ExceptionCheck(jenv)) { 550 return (NULL); 551 } 552 (*jenv)->SetByteArrayRegion(jenv, (jbyteArray)jobj, 0, nbytes, 553 (const jbyte *)c); 554 if ((*jenv)->ExceptionCheck(jenv)) { 555 WRAP_EXCEPTION(jenv); 556 (*jenv)->DeleteLocalRef(jenv, jobj); 557 return (NULL); 558 } 559 return (jobj); 560 } 561 562 /* 563 * Return NULL if memory could not be allocated (OutOfMemoryError is thrown in 564 * that case). 565 */ 566 static jobject 567 dtj_recdata(dtj_java_consumer_t *jc, uint32_t size, caddr_t addr) 568 { 569 JNIEnv *jenv = jc->dtjj_jenv; 570 jobject jobj; 571 jobject jrec; 572 573 switch (size) { 574 case 1: 575 jobj = (*jenv)->NewObject(jenv, g_int_jc, 576 g_intinit_jm, (int)(*((uint8_t *)addr))); 577 break; 578 case 2: 579 jobj = (*jenv)->NewObject(jenv, g_int_jc, 580 /* LINTED - alignment */ 581 g_intinit_jm, (int)(*((uint16_t *)addr))); 582 break; 583 case 4: 584 jobj = (*jenv)->NewObject(jenv, g_int_jc, 585 /* LINTED - alignment */ 586 g_intinit_jm, *((int32_t *)addr)); 587 break; 588 case 8: 589 jobj = (*jenv)->NewObject(jenv, g_long_jc, 590 /* LINTED - alignment */ 591 g_longinit_jm, *((int64_t *)addr)); 592 break; 593 default: 594 jobj = dtj_bytedata(jenv, size, addr); 595 break; 596 } 597 598 if (!jobj) { 599 return (NULL); /* OutOfMemoryError pending */ 600 } 601 602 jrec = (*jenv)->NewObject(jenv, g_scalar_jc, 603 g_scalarinit_jm, jobj, size); 604 (*jenv)->DeleteLocalRef(jenv, jobj); 605 606 return (jrec); 607 } 608 609 /* 610 * This is the record handling function passed to dtrace_work(). It differs 611 * from the bufhandler registered with dtrace_handle_buffered() as follows: 612 * 613 * 1. It does not have access to libdtrace formatted output. 614 * 2. It is called once for every D program statement, not for every 615 * output-producing D action or aggregation record. A statement may be a 616 * variable assignment, having no size and producing no output. 617 * 3. It is called for the D exit() action; the bufhandler is not. 618 * 4. In response to the printa() action, it is called with a record having an 619 * action of type DTRACEACT_PRINTA. The bufhandler never sees that action 620 * value. It only sees the output-producing aggregation records. 621 * 5. It is called with a NULL record at the end of each probedata. 622 */ 623 static int 624 dtj_chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, 625 void *arg) 626 { 627 dtj_java_consumer_t *jc = arg; 628 JNIEnv *jenv = jc->dtjj_jenv; 629 630 const dtrace_eprobedesc_t *edesc = data->dtpda_edesc; 631 dtrace_actkind_t act; 632 int r; 633 634 /* 635 * Update the record index to that of the current record, or to that of 636 * the last record if rec is NULL (signalling end of probe data). 637 */ 638 if (rec == NULL) { 639 r = edesc->dtepd_nrecs; /* end of probe data */ 640 } else { 641 /* 642 * This record handler is called once for the printf() action, 643 * but there may be multiple records in the probedata 644 * corresponding to the unformatted elements of that printf(). 645 * We don't know ahead of time how many probedata records 646 * libdtrace will consume to produce output for one printf() 647 * action, so we look back at the previous call to dtj_chewrec() 648 * to see how many probedata records were consumed. All 649 * non-null elements in the range from the previous record index 650 * up to and not including the current record index are assumed 651 * to be unformatted printf() elements, and will be attached to 652 * the PrintfRecord from the previous call. A null element in 653 * that range is the result of a D program statement preceding 654 * the printf() that is not a D action. These generate 655 * probedata records accounted for by the null placeholder, but 656 * do not advance the probedata offset and are not part of the 657 * subsequent printf(). 658 * 659 * If rec->dtrd_size == 0, the record represents a D program 660 * statement that is not a D action. It has no size and does 661 * not advance the offset in the probedata. Handle it normally 662 * without special-casing or premature return, since in all 663 * cases we look at the previous record later in this function. 664 */ 665 for (r = jc->dtjj_consumer->dtjc_probedata_rec_i; 666 ((r < edesc->dtepd_nrecs) && 667 (edesc->dtepd_rec[r].dtrd_offset < rec->dtrd_offset)); 668 ++r) { 669 } 670 } 671 672 /* 673 * Attach the Java representations of the libdtrace data elements 674 * pertaining to the previous call to this record handler to the 675 * previous Java Record. (All data elements belonging to the current 676 * probedata are added to a single list by the probedata consumer 677 * function dtj_chew() before this record consumer function is ever 678 * called.) For example, if the previous Record was generated by the 679 * printf() action, and dtj_chew() listed 3 records for its 3 680 * unformatted elements, those 3 libdtrace records comprise 1 681 * PrintfRecord. Note that we cannot know how many data elements apply 682 * to the current rec until we find out the data index where the next 683 * rec starts. (The knowledge of how many probedata records to consume 684 * is private to libdtrace.) 685 */ 686 if (jc->dtjj_consumer->dtjc_probedata_act == DTRACEACT_PRINTF) { 687 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 688 g_pdataattach_jm, 689 jc->dtjj_consumer->dtjc_probedata_rec_i, r - 1); 690 if ((*jenv)->ExceptionCheck(jenv)) { 691 WRAP_EXCEPTION(jenv); 692 return (DTRACE_CONSUME_ABORT); 693 } 694 } 695 696 if (rec == NULL) { 697 /* 698 * End of probe data. Notify listeners of the new ProbeData 699 * instance. 700 */ 701 if (jc->dtjj_probedata) { 702 /* previous probedata */ 703 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 704 g_pdataclear_jm); 705 if ((*jenv)->ExceptionCheck(jenv)) { 706 WRAP_EXCEPTION(jenv); 707 return (DTRACE_CONSUME_ABORT); 708 } 709 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 710 g_pdatanext_jm, jc->dtjj_probedata); 711 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_probedata); 712 jc->dtjj_probedata = NULL; 713 if ((*jenv)->ExceptionCheck(jenv)) { 714 /* 715 * Do not wrap exception thrown from 716 * ConsumerListener. 717 */ 718 return (DTRACE_CONSUME_ABORT); 719 } 720 } 721 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_printa_buffer); 722 jc->dtjj_printa_buffer = NULL; 723 return (DTRACE_CONSUME_NEXT); 724 } 725 726 act = rec->dtrd_action; 727 728 /* Set previous record action and data index to current */ 729 jc->dtjj_consumer->dtjc_probedata_act = act; 730 jc->dtjj_consumer->dtjc_probedata_rec_i = r; 731 732 switch (act) { 733 case DTRACEACT_DIFEXPR: 734 if (rec->dtrd_size == 0) { 735 /* 736 * The current record is not a D action, but a program 737 * statement such as a variable assignment, not to be 738 * confused with the trace() action. 739 */ 740 break; 741 } 742 /* 743 * Add a Record for the trace() action that references the 744 * native probedata element listed at the current index. 745 */ 746 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 747 g_pdataadd_trace_jm, 748 jc->dtjj_consumer->dtjc_probedata_rec_i); 749 if ((*jenv)->ExceptionCheck(jenv)) { 750 WRAP_EXCEPTION(jenv); 751 return (DTRACE_CONSUME_ABORT); 752 } 753 break; 754 case DTRACEACT_PRINTF: 755 /* 756 * Just add an empty PrintfRecord for now. We'll attach the 757 * unformatted elements in a subsequent call to this function. 758 * (We don't know how many there will be.) 759 */ 760 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 761 g_pdataadd_printf_jm); 762 if ((*jenv)->ExceptionCheck(jenv)) { 763 WRAP_EXCEPTION(jenv); 764 return (DTRACE_CONSUME_ABORT); 765 } 766 /* defer formatted string to dtj_bufhandler() */ 767 break; 768 case DTRACEACT_PRINTA: { 769 jobject jbuf = NULL; 770 771 dtj_aggwalk_init(jc); 772 if ((*jenv)->ExceptionCheck(jenv)) { 773 WRAP_EXCEPTION(jenv); 774 return (DTRACE_CONSUME_ABORT); 775 } 776 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 777 g_pdataadd_printa_jm, 778 jc->dtjj_consumer->dtjc_printa_snaptime, 779 (rec->dtrd_format != 0)); 780 if ((*jenv)->ExceptionCheck(jenv)) { 781 WRAP_EXCEPTION(jenv); 782 return (DTRACE_CONSUME_ABORT); 783 } 784 if (jc->dtjj_printa_buffer == NULL) { 785 /* 786 * Create a StringBuilder to collect the pieces of 787 * formatted output into a single String. 788 */ 789 jbuf = (*jenv)->NewObject(jenv, g_buf_jc, 790 g_bufinit_jm); 791 if (!jbuf) { 792 /* OutOfMemoryError pending */ 793 return (DTRACE_CONSUME_ABORT); 794 } 795 jc->dtjj_printa_buffer = jbuf; 796 } 797 /* defer aggregation records to dtj_bufhandler() */ 798 break; 799 } 800 case DTRACEACT_EXIT: 801 /* 802 * Add a Record for the exit() action that references the native 803 * probedata element listed at the current index. 804 */ 805 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 806 g_pdataadd_exit_jm, 807 jc->dtjj_consumer->dtjc_probedata_rec_i); 808 if ((*jenv)->ExceptionCheck(jenv)) { 809 WRAP_EXCEPTION(jenv); 810 return (DTRACE_CONSUME_ABORT); 811 } 812 return (DTRACE_CONSUME_NEXT); 813 } 814 815 return (DTRACE_CONSUME_THIS); 816 } 817 818 /* 819 * This is the probe handling function passed to dtrace_work(). It is is called 820 * once every time a probe fires. It is the first of all the callbacks for the 821 * current probe. It is followed by multiple callbacks to dtj_chewrec(), one 822 * for each probedata record. Each call to dtj_chewrec() is followed by zero or 823 * more callbacks to the bufhandler, one for each output-producing action or 824 * aggregation record. 825 */ 826 static int 827 dtj_chew(const dtrace_probedata_t *data, void *arg) 828 { 829 dtj_java_consumer_t *jc = arg; 830 JNIEnv *jenv = jc->dtjj_jenv; 831 832 dtrace_eprobedesc_t *edesc; 833 dtrace_probedesc_t *pdesc; 834 dtrace_recdesc_t *rec; 835 int epid; 836 int cpu; 837 int nrecs; 838 int i; 839 840 jobject jpdata = NULL; 841 jobject jprobe = NULL; 842 jobject jflow = NULL; 843 jstring jflowkind = NULL; 844 jobject jobj = NULL; 845 846 edesc = data->dtpda_edesc; 847 epid = (int)edesc->dtepd_epid; 848 pdesc = data->dtpda_pdesc; 849 cpu = (int)data->dtpda_cpu; 850 if ((jprobe = dtj_new_probedesc(jc, pdesc)) == NULL) { 851 /* java exception pending */ 852 return (DTRACE_CONSUME_ABORT); 853 } 854 nrecs = edesc->dtepd_nrecs; 855 856 if (jc->dtjj_consumer->dtjc_flow) { 857 const char *kind; 858 switch (data->dtpda_flow) { 859 case DTRACEFLOW_ENTRY: 860 kind = "ENTRY"; 861 break; 862 case DTRACEFLOW_RETURN: 863 kind = "RETURN"; 864 break; 865 case DTRACEFLOW_NONE: 866 kind = "NONE"; 867 break; 868 default: 869 kind = NULL; 870 } 871 if (kind != NULL) { 872 int depth; 873 jflowkind = (*jenv)->NewStringUTF(jenv, kind); 874 if ((*jenv)->ExceptionCheck(jenv)) { 875 WRAP_EXCEPTION(jenv); 876 (*jenv)->DeleteLocalRef(jenv, jprobe); 877 return (DTRACE_CONSUME_ABORT); 878 } 879 /* 880 * Use the knowledge that libdtrace indents 2 spaces per 881 * level in the call stack to calculate the depth. 882 */ 883 depth = (data->dtpda_indent / 2); 884 jflow = (*jenv)->NewObject(jenv, g_flow_jc, 885 g_flowinit_jm, jflowkind, depth); 886 (*jenv)->DeleteLocalRef(jenv, jflowkind); 887 if ((*jenv)->ExceptionCheck(jenv)) { 888 WRAP_EXCEPTION(jenv); 889 (*jenv)->DeleteLocalRef(jenv, jprobe); 890 return (DTRACE_CONSUME_ABORT); 891 } 892 } 893 } 894 895 /* Create ProbeData instance */ 896 jpdata = (*jenv)->NewObject(jenv, g_pdata_jc, g_pdatainit_jm, 897 epid, cpu, jprobe, jflow, nrecs); 898 (*jenv)->DeleteLocalRef(jenv, jprobe); 899 (*jenv)->DeleteLocalRef(jenv, jflow); 900 if ((*jenv)->ExceptionCheck(jenv)) { 901 WRAP_EXCEPTION(jenv); 902 return (DTRACE_CONSUME_ABORT); 903 } 904 905 /* 906 * Populate the ProbeData list of Java data elements in advance so we 907 * don't need to peek back in the record handler at libdtrace records 908 * that have already been consumed. In the Java API, each ProbeData 909 * Record is generated by one D action, while in the native libdtrace 910 * there may be more than one probedata record (each a single data 911 * element) per D action. For example PrintfRecord has multiple 912 * unformatted elements, each represented by a native probedata record, 913 * but combined by the API into a single PrintfRecord. 914 */ 915 for (i = 0; i < nrecs; ++i) { 916 rec = &edesc->dtepd_rec[i]; 917 /* 918 * A statement that is not a D action, such as assignment to a 919 * variable, has no size. Add a NULL placeholder to the scratch 920 * list of Java probedata elements in that case. 921 */ 922 jobj = NULL; /* initialize object reference to null */ 923 if (rec->dtrd_size > 0) { 924 if (dtj_is_stack_action(rec->dtrd_action)) { 925 jobj = dtj_new_probedata_stack_record(data, 926 rec, jc); 927 } else if (dtj_is_symbol_action(rec->dtrd_action)) { 928 jobj = dtj_new_probedata_symbol_record(data, 929 rec, jc); 930 } else { 931 jobj = dtj_recdata(jc, rec->dtrd_size, 932 (data->dtpda_data + rec->dtrd_offset)); 933 } 934 if ((*jenv)->ExceptionCheck(jenv)) { 935 WRAP_EXCEPTION(jenv); 936 (*jenv)->DeleteLocalRef(jenv, jpdata); 937 return (DTRACE_CONSUME_ABORT); 938 } 939 } 940 941 (*jenv)->CallVoidMethod(jenv, jpdata, g_pdataadd_jm, jobj); 942 (*jenv)->DeleteLocalRef(jenv, jobj); 943 if ((*jenv)->ExceptionCheck(jenv)) { 944 WRAP_EXCEPTION(jenv); 945 (*jenv)->DeleteLocalRef(jenv, jpdata); 946 return (DTRACE_CONSUME_ABORT); 947 } 948 } 949 950 if (jc->dtjj_probedata != NULL) { 951 dtj_throw_illegal_state(jenv, "unfinished probedata"); 952 WRAP_EXCEPTION(jenv); 953 (*jenv)->DeleteLocalRef(jenv, jpdata); 954 return (DTRACE_CONSUME_ABORT); 955 } 956 jc->dtjj_probedata = jpdata; 957 958 /* Initialize per-consumer probedata fields */ 959 jc->dtjj_consumer->dtjc_probedata_rec_i = 0; 960 jc->dtjj_consumer->dtjc_probedata_act = DTRACEACT_NONE; 961 dtj_aggwalk_init(jc); 962 if ((*jenv)->ExceptionCheck(jenv)) { 963 WRAP_EXCEPTION(jenv); 964 return (DTRACE_CONSUME_ABORT); 965 } 966 967 return (DTRACE_CONSUME_THIS); 968 } 969 970 /* 971 * This is the buffered output handler registered with dtrace_handle_buffered(). 972 * It's purpose is to make the output of the libdtrace print routines available 973 * to this API, without writing any of it to a file (such as stdout). This is 974 * needed for the stack(), ustack(), and jstack() actions to get human-readable 975 * stack values, since there is no public function in libdtrace to convert stack 976 * values to strings. It is also used to get the formatted output of the D 977 * printf() and printa() actions. 978 * 979 * The bufhandler is called once for each output-producing, non-aggregating D 980 * action, such as trace() or printf(), and once for each libdtrace aggregation 981 * record (whether in response to the D printa() action, or the Consumer 982 * getAggregate() method). In the simple printa() case that takes one 983 * aggregation and does not specify a format string, there is one libdtrace 984 * record per tuple element plus one for the corresponding value. The complete 985 * tuple/value pair becomes a single AggregationRecord exported by the API. 986 * When multiple aggregations are passed to printa(), each tuple is associated 987 * with a list of values, one from each aggregation. If a printa() format 988 * string does not specify placeholders for every aggregation value and tuple 989 * member, callbacks for those values and tuple members are omitted (and the 990 * data is omitted from the resulting PrintaRecord). 991 * 992 * Notes to characterize some non-obvious bufhandler behavior: 993 * 994 * 1. dtj_bufhandler() is never called with bufdata->dtbda_recdesc->dtrd_action 995 * DTRACEACT_PRINTA. That action only appears in the probedata consumer 996 * functions dtj_chew() and dtj_chewrec() before the bufhandler is called with 997 * subsequent aggregation records. 998 * 999 * 2. If printa() specifies a format string argument, then the bufhandler is 1000 * called only for those elements of the tuple/value pair that are included in 1001 * the format string. If a stack() tuple member is omitted from the format 1002 * string, its human-readable representation will not be available to this API, 1003 * so the stack frame array is also omitted from the resulting 1004 * AggregationRecord. The bufhandler is also called once for each string of 1005 * characters surrounding printa() format string placeholders. For example, 1006 * " %@d %d stack%k\n" results in the following callbacks: 1007 * - two spaces 1008 * - the aggregation value 1009 * - a single space 1010 * - the first tuple member (an integer) 1011 * - " stack" 1012 * - the second tuple member (a stack) 1013 * - a newline 1014 * A NULL record (NULL dtbda_recdesc) distinguishes a callback with interstitial 1015 * format string characters from a callback with a tuple member or aggregation 1016 * value (which has a non-NULL recdesc). The contents are also distinguished by 1017 * the following flags: 1018 * DTRACE_BUFDATA_AGGKEY 1019 * DTRACE_BUFDATA_AGGVAL 1020 * DTRACE_BUFDATA_AGGFORMAT 1021 * DTRACE_BUFDATA_AGGLAST 1022 * 1023 * There is no final callback with the complete formatted string, so that must 1024 * be concatenated across multiple callbacks to the bufhandler. 1025 * 1026 * 3. bufdata->dtbda_probe->dtpda_data may be overwritten by libdtrace print 1027 * routines. The address is cached in the dtj_chew() function in case it is 1028 * needed in the bufhandler. 1029 */ 1030 static int 1031 /* ARGSUSED */ 1032 dtj_bufhandler(const dtrace_bufdata_t *bufdata, void *arg) 1033 { 1034 dtj_java_consumer_t *jc; 1035 JNIEnv *jenv; 1036 const dtrace_recdesc_t *rec; 1037 dtrace_actkind_t act = DTRACEACT_NONE; 1038 const char *s; 1039 1040 jobject jstr = NULL; 1041 1042 /* 1043 * Get the thread-specific java consumer. The bufhandler needs access 1044 * to the correct JNI state specific to either the consumer loop or the 1045 * getAggregate() call (aggregation snapshots can be requested 1046 * asynchronously while the consumer loop generates PrintaRecords in 1047 * dtrace_work() for ConsumerListeners). 1048 */ 1049 jc = pthread_getspecific(g_dtj_consumer_key); 1050 jenv = jc->dtjj_jenv; 1051 1052 /* 1053 * In at least one corner case (printa with multiple aggregations and a 1054 * format string that does not completely specify the tuple), returning 1055 * DTRACE_HANDLE_ABORT does not prevent a subsequent callback to this 1056 * bufhandler. This check ensures that the invalid call is ignored. 1057 */ 1058 if ((*jenv)->ExceptionCheck(jenv)) { 1059 return (DTRACE_HANDLE_ABORT); 1060 } 1061 1062 if (bufdata->dtbda_aggdata) { 1063 return (dtj_agghandler(bufdata, jc)); 1064 } 1065 1066 s = bufdata->dtbda_buffered; 1067 if (s == NULL) { 1068 return (DTRACE_HANDLE_OK); 1069 } 1070 1071 rec = bufdata->dtbda_recdesc; 1072 if (rec) { 1073 act = rec->dtrd_action; 1074 } 1075 1076 switch (act) { 1077 case DTRACEACT_DIFEXPR: 1078 /* trace() action */ 1079 break; 1080 case DTRACEACT_PRINTF: 1081 /* 1082 * Only the formatted string was not available to dtj_chewrec(), 1083 * so we attach that now. 1084 */ 1085 jstr = dtj_NewStringNative(jenv, s); 1086 if ((*jenv)->ExceptionCheck(jenv)) { 1087 WRAP_EXCEPTION(jenv); 1088 return (DTRACE_HANDLE_ABORT); 1089 } 1090 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1091 g_pdataset_formatted_jm, jstr); 1092 (*jenv)->DeleteLocalRef(jenv, jstr); 1093 if ((*jenv)->ExceptionCheck(jenv)) { 1094 WRAP_EXCEPTION(jenv); 1095 return (DTRACE_HANDLE_ABORT); 1096 } 1097 break; 1098 case DTRACEACT_STACK: 1099 case DTRACEACT_USTACK: 1100 case DTRACEACT_JSTACK: 1101 /* stand-alone stack(), ustack(), or jstack() action */ 1102 jstr = (*jenv)->NewStringUTF(jenv, s); 1103 if (!jstr) { 1104 /* OutOfMemoryError pending */ 1105 return (DTRACE_HANDLE_ABORT); 1106 } 1107 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1108 g_pdataadd_stack_jm, 1109 jc->dtjj_consumer->dtjc_probedata_rec_i, jstr); 1110 (*jenv)->DeleteLocalRef(jenv, jstr); 1111 if ((*jenv)->ExceptionCheck(jenv)) { 1112 WRAP_EXCEPTION(jenv); 1113 return (DTRACE_HANDLE_ABORT); 1114 } 1115 break; 1116 case DTRACEACT_USYM: 1117 case DTRACEACT_UADDR: 1118 case DTRACEACT_UMOD: 1119 case DTRACEACT_SYM: 1120 case DTRACEACT_MOD: 1121 /* stand-alone symbol lookup action */ 1122 jstr = (*jenv)->NewStringUTF(jenv, s); 1123 if (!jstr) { 1124 /* OutOfMemoryError pending */ 1125 return (DTRACE_HANDLE_ABORT); 1126 } 1127 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1128 g_pdataadd_symbol_jm, 1129 jc->dtjj_consumer->dtjc_probedata_rec_i, jstr); 1130 (*jenv)->DeleteLocalRef(jenv, jstr); 1131 if ((*jenv)->ExceptionCheck(jenv)) { 1132 WRAP_EXCEPTION(jenv); 1133 return (DTRACE_HANDLE_ABORT); 1134 } 1135 break; 1136 default: 1137 /* 1138 * The record handler dtj_chewrec() defers nothing else to this 1139 * bufhandler. 1140 */ 1141 break; 1142 } 1143 1144 return (DTRACE_HANDLE_OK); 1145 } 1146 1147 static boolean_t 1148 dtj_is_stack_action(dtrace_actkind_t act) 1149 { 1150 boolean_t stack_action; 1151 switch (act) { 1152 case DTRACEACT_STACK: 1153 case DTRACEACT_USTACK: 1154 case DTRACEACT_JSTACK: 1155 stack_action = B_TRUE; 1156 break; 1157 default: 1158 stack_action = B_FALSE; 1159 } 1160 return (stack_action); 1161 } 1162 1163 static boolean_t 1164 dtj_is_symbol_action(dtrace_actkind_t act) 1165 { 1166 boolean_t symbol_action; 1167 switch (act) { 1168 case DTRACEACT_USYM: 1169 case DTRACEACT_UADDR: 1170 case DTRACEACT_UMOD: 1171 case DTRACEACT_SYM: 1172 case DTRACEACT_MOD: 1173 symbol_action = B_TRUE; 1174 break; 1175 default: 1176 symbol_action = B_FALSE; 1177 } 1178 return (symbol_action); 1179 } 1180 1181 /* 1182 * Called by get_aggregate() to clear only those aggregations specified by the 1183 * caller. 1184 */ 1185 static int 1186 dtj_clear(const dtrace_aggdata_t *data, void *arg) 1187 { 1188 dtj_java_consumer_t *jc = arg; 1189 jboolean cleared = JNI_FALSE; 1190 1191 jstring jname = NULL; 1192 1193 if (jc->dtjj_aggregate_spec) { 1194 JNIEnv *jenv = jc->dtjj_jenv; 1195 1196 dtrace_aggdesc_t *aggdesc = data->dtada_desc; 1197 1198 jname = (*jenv)->NewStringUTF(jenv, aggdesc->dtagd_name); 1199 if (!jname) { 1200 /* java exception pending */ 1201 return (DTRACE_AGGWALK_ABORT); 1202 } 1203 1204 cleared = (*jenv)->CallBooleanMethod(jenv, 1205 jc->dtjj_aggregate_spec, g_aggspec_cleared_jm, jname); 1206 (*jenv)->DeleteLocalRef(jenv, jname); 1207 if ((*jenv)->ExceptionCheck(jenv)) { 1208 WRAP_EXCEPTION(jenv); 1209 return (DTRACE_AGGWALK_ABORT); 1210 } 1211 } 1212 1213 return (cleared ? DTRACE_AGGWALK_CLEAR : DTRACE_AGGWALK_NEXT); 1214 } 1215 1216 static int64_t 1217 dtj_average(caddr_t addr, uint64_t normal) 1218 { 1219 /* LINTED - alignment */ 1220 uint64_t *data = (uint64_t *)addr; 1221 1222 return (data[0] ? 1223 (long long)(data[1] / normal / data[0]) : 0); 1224 } 1225 1226 static int64_t 1227 dtj_avg_total(caddr_t addr, uint64_t normal) 1228 { 1229 /* LINTED - alignment */ 1230 uint64_t *data = (uint64_t *)addr; 1231 1232 return ((long long)(data[1] / normal)); 1233 } 1234 1235 static int64_t 1236 dtj_avg_count(caddr_t addr) 1237 { 1238 /* LINTED - alignment */ 1239 uint64_t *data = (uint64_t *)addr; 1240 1241 return ((long long)data[0]); 1242 } 1243 1244 static jobject 1245 dtj_new_probedata_stack_record(const dtrace_probedata_t *data, 1246 const dtrace_recdesc_t *rec, dtj_java_consumer_t *jc) 1247 { 1248 caddr_t addr; 1249 1250 /* Get raw stack data */ 1251 addr = data->dtpda_data + rec->dtrd_offset; 1252 return (dtj_new_stack_record(addr, rec, jc)); 1253 } 1254 1255 static jobject 1256 dtj_new_tuple_stack_record(const dtrace_aggdata_t *data, 1257 const dtrace_recdesc_t *rec, const char *s, dtj_java_consumer_t *jc) 1258 { 1259 caddr_t addr; 1260 JNIEnv *jenv = jc->dtjj_jenv; 1261 1262 jobjectArray frames = NULL; 1263 jobject jobj = NULL; /* tuple element */ 1264 jstring jstr = NULL; 1265 1266 /* Get raw stack data */ 1267 addr = data->dtada_data + rec->dtrd_offset; 1268 jobj = dtj_new_stack_record(addr, rec, jc); 1269 if (!jobj) { 1270 return (NULL); /* java exception pending */ 1271 } 1272 1273 jstr = dtj_NewStringNative(jenv, s); 1274 if ((*jenv)->ExceptionCheck(jenv)) { 1275 (*jenv)->DeleteLocalRef(jenv, jobj); 1276 return (NULL); 1277 } 1278 frames = (*jenv)->CallStaticObjectMethod(jenv, g_stack_jc, 1279 g_parsestack_jsm, jstr); 1280 (*jenv)->DeleteLocalRef(jenv, jstr); 1281 if ((*jenv)->ExceptionCheck(jenv)) { 1282 (*jenv)->DeleteLocalRef(jenv, jobj); 1283 return (NULL); 1284 } 1285 dtj_attach_frames(jc, jobj, frames); 1286 (*jenv)->DeleteLocalRef(jenv, frames); 1287 if ((*jenv)->ExceptionCheck(jenv)) { 1288 WRAP_EXCEPTION(jenv); 1289 return (NULL); 1290 } 1291 1292 return (jobj); 1293 } 1294 1295 static jobject 1296 dtj_new_probedata_symbol_record(const dtrace_probedata_t *data, 1297 const dtrace_recdesc_t *rec, dtj_java_consumer_t *jc) 1298 { 1299 caddr_t addr; 1300 1301 addr = data->dtpda_data + rec->dtrd_offset; 1302 return (dtj_new_symbol_record(addr, rec, jc)); 1303 } 1304 1305 static jobject 1306 dtj_new_tuple_symbol_record(const dtrace_aggdata_t *data, 1307 const dtrace_recdesc_t *rec, const char *s, dtj_java_consumer_t *jc) 1308 { 1309 caddr_t addr; 1310 JNIEnv *jenv = jc->dtjj_jenv; 1311 1312 jobject jobj = NULL; /* tuple element */ 1313 jstring jstr = NULL; /* lookup value */ 1314 jstring tstr = NULL; /* trimmed lookup value */ 1315 1316 addr = data->dtada_data + rec->dtrd_offset; 1317 jobj = dtj_new_symbol_record(addr, rec, jc); 1318 if (!jobj) { 1319 return (NULL); /* java exception pending */ 1320 } 1321 1322 /* Get symbol lookup */ 1323 jstr = (*jenv)->NewStringUTF(jenv, s); 1324 if (!jstr) { 1325 /* OutOfMemoryError pending */ 1326 (*jenv)->DeleteLocalRef(jenv, jobj); 1327 return (NULL); 1328 } 1329 /* Trim leading and trailing whitespace */ 1330 tstr = (*jenv)->CallObjectMethod(jenv, jstr, g_trim_jm); 1331 /* trim() returns a new string; don't leak the old one */ 1332 (*jenv)->DeleteLocalRef(jenv, jstr); 1333 jstr = tstr; 1334 tstr = NULL; 1335 1336 dtj_attach_name(jc, jobj, jstr); 1337 (*jenv)->DeleteLocalRef(jenv, jstr); 1338 if ((*jenv)->ExceptionCheck(jenv)) { 1339 WRAP_EXCEPTION(jenv); 1340 return (NULL); 1341 } 1342 1343 return (jobj); 1344 } 1345 1346 /* Caller must be holding per-consumer lock */ 1347 static void 1348 dtj_aggwalk_init(dtj_java_consumer_t *jc) 1349 { 1350 jc->dtjj_consumer->dtjc_aggid = -1; 1351 jc->dtjj_consumer->dtjc_expected = -1; 1352 if (jc->dtjj_tuple != NULL) { 1353 /* assert without crashing */ 1354 dtj_throw_illegal_state(jc->dtjj_jenv, 1355 "stale aggregation tuple"); 1356 } 1357 } 1358 1359 static jobject 1360 dtj_new_stack_record(const caddr_t addr, const dtrace_recdesc_t *rec, 1361 dtj_java_consumer_t *jc) 1362 { 1363 JNIEnv *jenv = jc->dtjj_jenv; 1364 1365 dtrace_actkind_t act; 1366 uint64_t *pc; 1367 pid_t pid = -1; 1368 int size; /* size of raw bytes not including trailing zeros */ 1369 int i; /* index of last non-zero byte */ 1370 1371 jbyteArray raw = NULL; 1372 jobject stack = NULL; /* return value */ 1373 1374 /* trim trailing zeros */ 1375 for (i = rec->dtrd_size - 1; (i >= 0) && !addr[i]; --i) { 1376 } 1377 size = (i + 1); 1378 raw = (*jenv)->NewByteArray(jenv, size); 1379 if (!raw) { 1380 return (NULL); /* OutOfMemoryError pending */ 1381 } 1382 (*jenv)->SetByteArrayRegion(jenv, raw, 0, size, 1383 (const jbyte *)addr); 1384 if ((*jenv)->ExceptionCheck(jenv)) { 1385 WRAP_EXCEPTION(jenv); 1386 (*jenv)->DeleteLocalRef(jenv, raw); 1387 return (NULL); 1388 } 1389 1390 /* Create StackValueRecord instance from raw stack data */ 1391 act = rec->dtrd_action; 1392 switch (act) { 1393 case DTRACEACT_STACK: 1394 stack = (*jenv)->NewObject(jenv, g_stack_jc, 1395 g_stackinit_jm, raw); 1396 break; 1397 case DTRACEACT_USTACK: 1398 case DTRACEACT_JSTACK: 1399 /* Get pid of user process */ 1400 pc = (uint64_t *)(uintptr_t)addr; 1401 pid = (pid_t)*pc; 1402 stack = (*jenv)->NewObject(jenv, g_ustack_jc, 1403 g_ustackinit_jm, pid, raw); 1404 break; 1405 default: 1406 dtj_throw_illegal_argument(jenv, 1407 "Expected stack action, got %d\n", act); 1408 } 1409 (*jenv)->DeleteLocalRef(jenv, raw); 1410 if ((*jenv)->ExceptionCheck(jenv)) { 1411 WRAP_EXCEPTION(jenv); 1412 return (NULL); 1413 } 1414 return (stack); 1415 } 1416 1417 static jobject 1418 dtj_new_symbol_record(const caddr_t addr, const dtrace_recdesc_t *rec, 1419 dtj_java_consumer_t *jc) 1420 { 1421 JNIEnv *jenv = jc->dtjj_jenv; 1422 1423 dtrace_actkind_t act; 1424 uint64_t *pc; 1425 pid_t pid = -1; 1426 1427 jobject symbol = NULL; /* return value */ 1428 1429 act = rec->dtrd_action; 1430 switch (act) { 1431 case DTRACEACT_SYM: 1432 case DTRACEACT_MOD: 1433 /* LINTED - alignment */ 1434 pc = (uint64_t *)addr; 1435 symbol = (*jenv)->NewObject(jenv, g_symbol_jc, 1436 g_symbolinit_jm, *pc); 1437 break; 1438 case DTRACEACT_USYM: 1439 case DTRACEACT_UADDR: 1440 case DTRACEACT_UMOD: 1441 /* Get pid of user process */ 1442 pc = (uint64_t *)(uintptr_t)addr; 1443 pid = (pid_t)*pc; 1444 ++pc; 1445 symbol = (*jenv)->NewObject(jenv, g_usymbol_jc, 1446 g_usymbolinit_jm, pid, *pc); 1447 break; 1448 default: 1449 dtj_throw_illegal_argument(jenv, 1450 "Expected stack action, got %d\n", act); 1451 } 1452 if ((*jenv)->ExceptionCheck(jenv)) { 1453 WRAP_EXCEPTION(jenv); 1454 return (NULL); 1455 } 1456 return (symbol); 1457 } 1458 1459 /* 1460 * Return NULL if java exception pending, otherwise return Distribution value. 1461 */ 1462 static jobject 1463 dtj_new_distribution(const dtrace_aggdata_t *data, const dtrace_recdesc_t *rec, 1464 dtj_java_consumer_t *jc) 1465 { 1466 JNIEnv *jenv = jc->dtjj_jenv; 1467 1468 jlongArray jbuckets = NULL; 1469 jobject jdist = NULL; /* return value */ 1470 1471 dtrace_actkind_t act = rec->dtrd_action; 1472 /* LINTED - alignment */ 1473 int64_t *aggbuckets = (int64_t *) 1474 (data->dtada_data + rec->dtrd_offset); 1475 size_t size = rec->dtrd_size; 1476 int64_t value; 1477 uint64_t normal = data->dtada_normal; 1478 int64_t base, step; 1479 int levels; 1480 int n; /* number of buckets */ 1481 1482 /* distribution */ 1483 if (act == DTRACEAGG_LQUANTIZE) { 1484 /* first "bucket" used for range and step */ 1485 value = *aggbuckets++; 1486 base = DTRACE_LQUANTIZE_BASE(value); 1487 step = DTRACE_LQUANTIZE_STEP(value); 1488 levels = DTRACE_LQUANTIZE_LEVELS(value); 1489 size -= sizeof (int64_t); /* exclude non-bucket */ 1490 /* 1491 * Add one for the base bucket and one for the bucket of values 1492 * less than the base. 1493 */ 1494 n = levels + 2; 1495 } else { 1496 n = DTRACE_QUANTIZE_NBUCKETS; 1497 levels = n - 1; /* levels excludes base */ 1498 } 1499 if (size != (n * sizeof (uint64_t)) || n < 1) { 1500 dtj_throw_illegal_state(jenv, 1501 "size mismatch: record %d, buckets %d", size, 1502 (n * sizeof (uint64_t))); 1503 WRAP_EXCEPTION(jenv); 1504 return (NULL); 1505 } 1506 1507 jbuckets = (*jenv)->NewLongArray(jenv, n); 1508 if (!jbuckets) { 1509 return (NULL); /* exception pending */ 1510 } 1511 if (n > 0) { 1512 (*jenv)->SetLongArrayRegion(jenv, jbuckets, 0, n, aggbuckets); 1513 /* check for ArrayIndexOutOfBounds */ 1514 if ((*jenv)->ExceptionCheck(jenv)) { 1515 WRAP_EXCEPTION(jenv); 1516 (*jenv)->DeleteLocalRef(jenv, jbuckets); 1517 return (NULL); 1518 } 1519 } 1520 1521 if (act == DTRACEAGG_LQUANTIZE) { 1522 /* Must pass 64-bit base and step or constructor gets junk. */ 1523 jdist = (*jenv)->NewObject(jenv, g_ldist_jc, g_ldistinit_jm, 1524 base, step, jbuckets); 1525 } else { 1526 jdist = (*jenv)->NewObject(jenv, g_dist_jc, g_distinit_jm, 1527 jbuckets); 1528 } 1529 1530 (*jenv)->DeleteLocalRef(jenv, jbuckets); 1531 if (!jdist) { 1532 return (NULL); /* exception pending */ 1533 } 1534 1535 if (normal != 1) { 1536 (*jenv)->CallVoidMethod(jenv, jdist, g_dist_normal_jm, normal); 1537 if ((*jenv)->ExceptionCheck(jenv)) { 1538 WRAP_EXCEPTION(jenv); 1539 (*jenv)->DeleteLocalRef(jenv, jdist); 1540 return (NULL); 1541 } 1542 } 1543 return (jdist); 1544 } 1545 1546 static void 1547 dtj_attach_frames(dtj_java_consumer_t *jc, jobject stack, 1548 jobjectArray frames) 1549 { 1550 JNIEnv *jenv = jc->dtjj_jenv; 1551 1552 if ((*jenv)->IsInstanceOf(jenv, stack, g_stack_jc)) { 1553 (*jenv)->CallVoidMethod(jenv, stack, g_stackset_frames_jm, 1554 frames); 1555 } else if ((*jenv)->IsInstanceOf(jenv, stack, g_ustack_jc)) { 1556 (*jenv)->CallVoidMethod(jenv, stack, g_ustackset_frames_jm, 1557 frames); 1558 } 1559 } 1560 1561 static void 1562 dtj_attach_name(dtj_java_consumer_t *jc, jobject symbol, jstring s) 1563 { 1564 JNIEnv *jenv = jc->dtjj_jenv; 1565 1566 if ((*jenv)->IsInstanceOf(jenv, symbol, g_symbol_jc)) { 1567 (*jenv)->CallVoidMethod(jenv, symbol, g_symbolset_name_jm, s); 1568 } else if ((*jenv)->IsInstanceOf(jenv, symbol, g_usymbol_jc)) { 1569 (*jenv)->CallVoidMethod(jenv, symbol, g_usymbolset_name_jm, s); 1570 } 1571 } 1572 1573 /* 1574 * Note: It is not valid to look outside the current libdtrace record in the 1575 * given aggdata (except to get the aggregation ID from the first record). 1576 * 1577 * Return DTRACE_HANDLE_ABORT if java exception pending, otherwise 1578 * DTRACE_HANDLE_OK. 1579 */ 1580 static int 1581 dtj_agghandler(const dtrace_bufdata_t *bufdata, dtj_java_consumer_t *jc) 1582 { 1583 JNIEnv *jenv = jc->dtjj_jenv; 1584 1585 const dtrace_aggdata_t *aggdata = bufdata->dtbda_aggdata; 1586 const dtrace_aggdesc_t *aggdesc; 1587 const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc; 1588 const char *s = bufdata->dtbda_buffered; 1589 dtrace_actkind_t act = DTRACEACT_NONE; 1590 int64_t aggid; 1591 1592 jobject jobj = NULL; 1593 1594 if (aggdata == NULL) { 1595 /* Assert without crashing */ 1596 dtj_throw_illegal_state(jenv, "null aggdata"); 1597 WRAP_EXCEPTION(jenv); 1598 return (DTRACE_HANDLE_ABORT); 1599 } 1600 aggdesc = aggdata->dtada_desc; 1601 1602 /* 1603 * Get the aggregation ID from the first record. 1604 */ 1605 /* LINTED - alignment */ 1606 aggid = *((int64_t *)(aggdata->dtada_data + 1607 aggdesc->dtagd_rec[0].dtrd_offset)); 1608 if (aggid < 0) { 1609 /* Assert without crashing */ 1610 dtj_throw_illegal_argument(jenv, "negative aggregation ID"); 1611 WRAP_EXCEPTION(jenv); 1612 return (DTRACE_HANDLE_ABORT); 1613 } 1614 1615 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1616 /* Append buffered output if this is a printa() callback. */ 1617 jstring jstr = dtj_NewStringNative(jenv, s); 1618 if ((*jenv)->ExceptionCheck(jenv)) { 1619 WRAP_EXCEPTION(jenv); 1620 return (DTRACE_HANDLE_ABORT); 1621 } 1622 /* 1623 * StringBuilder append() returns a reference to the 1624 * StringBuilder; must not leak the returned reference. 1625 */ 1626 jobj = (*jenv)->CallObjectMethod(jenv, 1627 jc->dtjj_printa_buffer, g_buf_append_str_jm, jstr); 1628 (*jenv)->DeleteLocalRef(jenv, jstr); 1629 (*jenv)->DeleteLocalRef(jenv, jobj); 1630 if ((*jenv)->ExceptionCheck(jenv)) { 1631 WRAP_EXCEPTION(jenv); 1632 return (DTRACE_HANDLE_ABORT); 1633 } 1634 } else { 1635 /* 1636 * Test whether to include the aggregation if this is a 1637 * getAggregate() callback. Optimization: perform the inclusion 1638 * test only when the aggregation has changed. 1639 */ 1640 if (aggid != jc->dtjj_consumer->dtjc_aggid) { 1641 jc->dtjj_consumer->dtjc_included = 1642 dtj_is_included(aggdata, jc); 1643 if ((*jenv)->ExceptionCheck(jenv)) { 1644 WRAP_EXCEPTION(jenv); 1645 return (DTRACE_HANDLE_ABORT); 1646 } 1647 } 1648 if (!jc->dtjj_consumer->dtjc_included) { 1649 return (DTRACE_HANDLE_OK); 1650 } 1651 } 1652 jc->dtjj_consumer->dtjc_aggid = aggid; 1653 1654 /* 1655 * Determine the expected number of tuple members. While it is not 1656 * technically valid to look outside the current record in the current 1657 * aggdata, this implementation does so without a known failure case. 1658 * Any method relying only on the current callback record makes riskier 1659 * assumptions and still does not cover every corner case (for example, 1660 * counting the records from index 1 up to and not including the index 1661 * of the current DTRACE_BUFDATA_AGGVAL record, which fails when a 1662 * format string specifies the value ahead of one or more tuple 1663 * elements). Knowing that the calculation of the expected tuple size 1664 * is technically invalid (because it looks outside the current record), 1665 * we make the calculation at the earliest opportunity, before anything 1666 * might happen to invalidate any part of the aggdata. It ought to be 1667 * safe in any case: dtrd_action and dtrd_size do not appear ever to be 1668 * overwritten, and dtrd_offset is not used outside the current record. 1669 * 1670 * It is possible (if the assumptions here ever prove untrue) that the 1671 * libdtrace buffered output handler may need to be enhanced to provide 1672 * the expected number of tuple members. 1673 */ 1674 if (jc->dtjj_consumer->dtjc_expected < 0) { 1675 int r; 1676 for (r = 1; r < aggdesc->dtagd_nrecs; ++r) { 1677 act = aggdesc->dtagd_rec[r].dtrd_action; 1678 if (DTRACEACT_ISAGG(act) || 1679 aggdesc->dtagd_rec[r].dtrd_size == 0) { 1680 break; 1681 } 1682 } 1683 jc->dtjj_consumer->dtjc_expected = r - 1; 1684 } 1685 1686 if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGKEY) { 1687 /* record value is a tuple member */ 1688 1689 if (jc->dtjj_tuple == NULL) { 1690 jc->dtjj_tuple = (*jenv)->NewObject(jenv, 1691 g_tuple_jc, g_tupleinit_jm); 1692 if (!jc->dtjj_tuple) { 1693 /* java exception pending */ 1694 return (DTRACE_HANDLE_ABORT); 1695 } 1696 } 1697 1698 act = rec->dtrd_action; 1699 1700 switch (act) { 1701 case DTRACEACT_STACK: 1702 case DTRACEACT_USTACK: 1703 case DTRACEACT_JSTACK: 1704 jobj = dtj_new_tuple_stack_record(aggdata, rec, s, jc); 1705 break; 1706 case DTRACEACT_USYM: 1707 case DTRACEACT_UADDR: 1708 case DTRACEACT_UMOD: 1709 case DTRACEACT_SYM: 1710 case DTRACEACT_MOD: 1711 jobj = dtj_new_tuple_symbol_record(aggdata, rec, s, jc); 1712 break; 1713 default: 1714 jobj = dtj_recdata(jc, rec->dtrd_size, 1715 (aggdata->dtada_data + rec->dtrd_offset)); 1716 } 1717 1718 if (!jobj) { 1719 /* java exception pending */ 1720 return (DTRACE_HANDLE_ABORT); 1721 } 1722 1723 (*jenv)->CallVoidMethod(jenv, jc->dtjj_tuple, 1724 g_tupleadd_jm, jobj); 1725 (*jenv)->DeleteLocalRef(jenv, jobj); 1726 if ((*jenv)->ExceptionCheck(jenv)) { 1727 WRAP_EXCEPTION(jenv); 1728 return (DTRACE_HANDLE_ABORT); 1729 } 1730 } else if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGVAL) { 1731 /* 1732 * Record value is that of an aggregating action. The printa() 1733 * format string may place the tuple ahead of the aggregation 1734 * value(s), so we can't be sure we have the tuple until we get 1735 * the AGGLAST flag indicating the last callback associated with 1736 * the current tuple. Save the aggregation value or values 1737 * (multiple values if more than one aggregation is passed to 1738 * printa()) until then. 1739 */ 1740 dtj_aggval_t *aggval; 1741 1742 jstring jvalue = NULL; 1743 1744 jvalue = dtj_new_aggval(jc, aggdata, rec); 1745 if (!jvalue) { 1746 /* java exception pending */ 1747 WRAP_EXCEPTION(jenv); 1748 return (DTRACE_HANDLE_ABORT); 1749 } 1750 aggval = dtj_aggval_create(jenv, jvalue, aggdesc->dtagd_name, 1751 aggid); 1752 if (!aggval) { 1753 /* OutOfMemoryError pending */ 1754 (*jenv)->DeleteLocalRef(jenv, jvalue); 1755 return (DTRACE_HANDLE_ABORT); 1756 } 1757 if (!dtj_list_add(jc->dtjj_aggval_list, aggval)) { 1758 /* deletes jvalue reference */ 1759 dtj_aggval_destroy(aggval, jenv); 1760 dtj_throw_out_of_memory(jenv, "Failed to add aggval"); 1761 return (DTRACE_HANDLE_ABORT); 1762 } 1763 } 1764 1765 if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGLAST) { 1766 /* No more values associated with the current tuple. */ 1767 1768 dtj_aggval_t *aggval; 1769 uu_list_walk_t *itr; 1770 int tuple_member_count; 1771 1772 jobject jrec = NULL; 1773 jstring jname = NULL; 1774 1775 if (jc->dtjj_consumer->dtjc_expected == 0) { 1776 /* 1777 * singleton aggregation declared in D with no square 1778 * brackets 1779 */ 1780 jc->dtjj_tuple = (*jenv)->GetStaticObjectField(jenv, 1781 g_tuple_jc, g_tuple_EMPTY_jsf); 1782 if (jc->dtjj_tuple == NULL) { 1783 dtj_throw_out_of_memory(jenv, 1784 "Failed to reference Tuple.EMPTY"); 1785 return (DTRACE_HANDLE_ABORT); 1786 } 1787 } 1788 1789 if (jc->dtjj_tuple == NULL) { 1790 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1791 g_pdatainvalidate_printa_jm); 1792 goto printa_output; 1793 } 1794 1795 tuple_member_count = (*jenv)->CallIntMethod(jenv, 1796 jc->dtjj_tuple, g_tuplesize_jm); 1797 if (tuple_member_count < 1798 jc->dtjj_consumer->dtjc_expected) { 1799 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1800 g_pdatainvalidate_printa_jm); 1801 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1802 jc->dtjj_tuple = NULL; 1803 goto printa_output; 1804 } 1805 1806 itr = uu_list_walk_start(jc->dtjj_aggval_list, 0); 1807 while ((aggval = uu_list_walk_next(itr)) != NULL) { 1808 /* 1809 * new AggregationRecord: Combine the aggregation value 1810 * with the saved tuple and add it to the current 1811 * Aggregate or PrintaRecord. 1812 */ 1813 jrec = (*jenv)->NewObject(jenv, g_aggrec_jc, 1814 g_aggrecinit_jm, jc->dtjj_tuple, 1815 aggval->dtja_value); 1816 (*jenv)->DeleteLocalRef(jenv, aggval->dtja_value); 1817 aggval->dtja_value = NULL; 1818 if (!jrec) { 1819 /* java exception pending */ 1820 WRAP_EXCEPTION(jenv); 1821 return (DTRACE_HANDLE_ABORT); 1822 } 1823 1824 /* aggregation name */ 1825 jname = (*jenv)->NewStringUTF(jenv, 1826 aggval->dtja_aggname); 1827 if (!jname) { 1828 /* OutOfMemoryError pending */ 1829 (*jenv)->DeleteLocalRef(jenv, jrec); 1830 return (DTRACE_HANDLE_ABORT); 1831 } 1832 1833 /* 1834 * If the printa() format string specifies the value of 1835 * the aggregating action multiple times, PrintaRecord 1836 * ignores the attempt to add the duplicate record. 1837 */ 1838 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1839 /* add to PrintaRecord */ 1840 (*jenv)->CallVoidMethod(jenv, 1841 jc->dtjj_probedata, 1842 g_pdataadd_aggrec_jm, 1843 jname, aggval->dtja_aggid, jrec); 1844 } else { 1845 /* add to Aggregate */ 1846 (*jenv)->CallVoidMethod(jenv, 1847 jc->dtjj_aggregate, g_aggaddrec_jm, 1848 jname, aggval->dtja_aggid, jrec); 1849 } 1850 1851 (*jenv)->DeleteLocalRef(jenv, jrec); 1852 (*jenv)->DeleteLocalRef(jenv, jname); 1853 if ((*jenv)->ExceptionCheck(jenv)) { 1854 WRAP_EXCEPTION(jenv); 1855 return (DTRACE_HANDLE_ABORT); 1856 } 1857 } 1858 uu_list_walk_end(itr); 1859 dtj_list_clear(jc->dtjj_aggval_list, dtj_aggval_destroy, 1860 jenv); 1861 1862 printa_output: 1863 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1864 /* 1865 * Get the formatted string associated with the current 1866 * tuple if this is a printa() callback. 1867 */ 1868 jstring jstr = (*jenv)->CallObjectMethod(jenv, 1869 jc->dtjj_printa_buffer, g_tostring_jm); 1870 if ((*jenv)->ExceptionCheck(jenv)) { 1871 WRAP_EXCEPTION(jenv); 1872 return (DTRACE_HANDLE_ABORT); 1873 } 1874 /* 1875 * Clear the StringBuilder: this does not throw 1876 * exceptions. Reuse the StringBuilder until the end of 1877 * the current probedata then dispose of it. 1878 */ 1879 (*jenv)->CallVoidMethod(jenv, jc->dtjj_printa_buffer, 1880 g_bufsetlen_jm, 0); 1881 /* Add formatted string to PrintaRecord */ 1882 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1883 g_pdataadd_printa_str_jm, jc->dtjj_tuple, jstr); 1884 (*jenv)->DeleteLocalRef(jenv, jstr); 1885 if ((*jenv)->ExceptionCheck(jenv)) { 1886 WRAP_EXCEPTION(jenv); 1887 return (DTRACE_HANDLE_ABORT); 1888 } 1889 } 1890 1891 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1892 jc->dtjj_tuple = NULL; 1893 jc->dtjj_consumer->dtjc_expected = -1; 1894 } 1895 1896 return (DTRACE_HANDLE_OK); 1897 } 1898 1899 /* 1900 * Return B_TRUE if the aggregation is included, B_FALSE otherwise. Only in the 1901 * latter case might there be an exception pending. 1902 */ 1903 static boolean_t 1904 dtj_is_included(const dtrace_aggdata_t *data, dtj_java_consumer_t *jc) 1905 { 1906 JNIEnv *jenv = jc->dtjj_jenv; 1907 1908 if (jc->dtjj_aggregate_spec) { 1909 jboolean included; 1910 jstring aggname = NULL; 1911 1912 const dtrace_aggdesc_t *aggdesc = data->dtada_desc; 1913 aggname = (*jenv)->NewStringUTF(jenv, aggdesc->dtagd_name); 1914 if (!aggname) { 1915 /* java exception pending */ 1916 return (B_FALSE); 1917 } 1918 1919 included = (*jenv)->CallBooleanMethod(jenv, 1920 jc->dtjj_aggregate_spec, g_aggspec_included_jm, 1921 aggname); 1922 (*jenv)->DeleteLocalRef(jenv, aggname); 1923 if ((*jenv)->ExceptionCheck(jenv)) { 1924 WRAP_EXCEPTION(jenv); 1925 return (B_FALSE); 1926 } 1927 1928 return (included); 1929 } 1930 1931 return (B_TRUE); 1932 } 1933 1934 /* 1935 * Return NULL if a java exception is pending, otherwise return a new 1936 * AggregationValue instance. 1937 */ 1938 static jobject 1939 dtj_new_aggval(dtj_java_consumer_t *jc, const dtrace_aggdata_t *data, 1940 const dtrace_recdesc_t *rec) 1941 { 1942 JNIEnv *jenv = jc->dtjj_jenv; 1943 1944 jobject jvalue = NULL; /* return value */ 1945 1946 dtrace_actkind_t act; 1947 uint64_t normal; 1948 caddr_t addr; 1949 int64_t value; 1950 1951 act = rec->dtrd_action; 1952 normal = data->dtada_normal; 1953 addr = data->dtada_data + rec->dtrd_offset; 1954 if (act == DTRACEAGG_AVG) { 1955 value = dtj_average(addr, normal); 1956 } else { 1957 /* LINTED - alignment */ 1958 value = (*((int64_t *)addr)) / normal; 1959 } 1960 1961 if (act == DTRACEAGG_QUANTIZE || act == DTRACEAGG_LQUANTIZE) { 1962 jvalue = dtj_new_distribution(data, rec, jc); 1963 } else { 1964 switch (act) { 1965 case DTRACEAGG_COUNT: 1966 jvalue = (*jenv)->NewObject(jenv, g_aggcount_jc, 1967 g_aggcountinit_jm, value); 1968 break; 1969 case DTRACEAGG_SUM: 1970 jvalue = (*jenv)->NewObject(jenv, g_aggsum_jc, 1971 g_aggsuminit_jm, value); 1972 break; 1973 case DTRACEAGG_AVG: 1974 jvalue = (*jenv)->NewObject(jenv, g_aggavg_jc, 1975 g_aggavginit_jm, value, dtj_avg_total(addr, 1976 normal), dtj_avg_count(addr)); 1977 break; 1978 case DTRACEAGG_MIN: 1979 jvalue = (*jenv)->NewObject(jenv, g_aggmin_jc, 1980 g_aggmininit_jm, value); 1981 break; 1982 case DTRACEAGG_MAX: 1983 jvalue = (*jenv)->NewObject(jenv, g_aggmax_jc, 1984 g_aggmaxinit_jm, value); 1985 break; 1986 default: 1987 jvalue = NULL; 1988 dtj_throw_illegal_argument(jenv, 1989 "unexpected aggregation action: %d", act); 1990 } 1991 } 1992 1993 return (jvalue); 1994 } 1995 1996 /* 1997 * Stops the given consumer if it is running. Throws DTraceException if 1998 * dtrace_stop() fails and no other exception is already pending. Clears and 1999 * rethrows any pending exception in order to grab the global lock safely. 2000 */ 2001 void 2002 dtj_stop(dtj_java_consumer_t *jc) 2003 { 2004 JNIEnv *jenv; 2005 int rc; 2006 jthrowable e; 2007 2008 switch (jc->dtjj_consumer->dtjc_state) { 2009 case DTJ_CONSUMER_GO: 2010 case DTJ_CONSUMER_START: 2011 break; 2012 default: 2013 return; 2014 } 2015 2016 jenv = jc->dtjj_jenv; 2017 e = (*jenv)->ExceptionOccurred(jenv); 2018 if (e) { 2019 (*jenv)->ExceptionClear(jenv); 2020 } 2021 2022 (*jenv)->MonitorEnter(jenv, g_caller_jc); 2023 if ((*jenv)->ExceptionCheck(jenv)) { 2024 goto rethrow; 2025 } 2026 2027 rc = dtrace_status(jc->dtjj_consumer->dtjc_dtp); 2028 if (rc != DTRACE_STATUS_STOPPED) { 2029 rc = dtrace_stop(jc->dtjj_consumer->dtjc_dtp); 2030 } 2031 2032 (*jenv)->MonitorExit(jenv, g_caller_jc); 2033 if ((*jenv)->ExceptionCheck(jenv)) { 2034 goto rethrow; 2035 } 2036 2037 if (rc == -1) { 2038 (*jenv)->MonitorEnter(jenv, g_caller_jc); 2039 if ((*jenv)->ExceptionCheck(jenv)) { 2040 goto rethrow; 2041 } 2042 /* Do not wrap DTraceException */ 2043 dtj_throw_dtrace_exception(jc, 2044 "couldn't stop tracing: %s", 2045 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2046 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2047 /* safe to call with pending exception */ 2048 (*jenv)->MonitorExit(jenv, g_caller_jc); 2049 } else { 2050 jc->dtjj_consumer->dtjc_state = DTJ_CONSUMER_STOP; 2051 } 2052 2053 rethrow: 2054 if (e) { 2055 if ((*jenv)->ExceptionCheck(jenv)) { 2056 /* 2057 * Favor earlier pending exception over 2058 * exception thrown in this function. 2059 */ 2060 (*jenv)->ExceptionClear(jenv); 2061 } 2062 (*jenv)->Throw(jenv, e); 2063 (*jenv)->DeleteLocalRef(jenv, e); 2064 } 2065 } 2066 2067 /* 2068 * Return Aggregate instance, or null if java exception pending. 2069 */ 2070 jobject 2071 dtj_get_aggregate(dtj_java_consumer_t *jc) 2072 { 2073 JNIEnv *jenv = jc->dtjj_jenv; 2074 hrtime_t snaptime; 2075 int rc; 2076 2077 jobject aggregate = NULL; 2078 2079 /* Must not call MonitorEnter with a pending exception */ 2080 if ((*jenv)->ExceptionCheck(jenv)) { 2081 WRAP_EXCEPTION(jenv); 2082 return (NULL); 2083 } 2084 2085 /* 2086 * Aggregations must be snapped, walked, and cleared atomically, 2087 * otherwise clearing loses data accumulated since the most recent snap. 2088 * This per-consumer lock prevents dtrace_work() from snapping or 2089 * clearing aggregations while we're in the middle of this atomic 2090 * operation, so we continue to hold it until done clearing. 2091 */ 2092 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2093 if ((*jenv)->ExceptionCheck(jenv)) { 2094 WRAP_EXCEPTION(jenv); 2095 return (NULL); 2096 } 2097 2098 dtj_aggwalk_init(jc); 2099 if ((*jenv)->ExceptionCheck(jenv)) { 2100 WRAP_EXCEPTION(jenv); 2101 /* release per-consumer lock */ 2102 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2103 return (NULL); 2104 } 2105 2106 /* 2107 * Snap aggregations 2108 * 2109 * We need to record the snaptime here for the caller. Leaving it to 2110 * the caller to record the snaptime before calling getAggregate() may 2111 * be inaccurate because of the indeterminate delay waiting on the 2112 * consumer lock before calling dtrace_aggregate_snap(). 2113 */ 2114 snaptime = gethrtime(); 2115 if (dtrace_aggregate_snap(jc->dtjj_consumer->dtjc_dtp) != 0) { 2116 dtj_error_t e; 2117 2118 /* 2119 * The dataDropped() ConsumerListener method can throw an 2120 * exception in the getAggregate() thread if the drop handler is 2121 * invoked during dtrace_aggregate_snap(). 2122 */ 2123 if ((*jenv)->ExceptionCheck(jenv)) { 2124 /* Do not wrap exception thrown from ConsumerListener */ 2125 /* release per-consumer lock */ 2126 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2127 return (NULL); 2128 } 2129 2130 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2131 /* Do not wrap DTraceException */ 2132 dtj_throw_dtrace_exception(jc, e.dtje_message); 2133 } 2134 /* release per-consumer lock */ 2135 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2136 return (NULL); 2137 } 2138 2139 if ((*jenv)->ExceptionCheck(jenv)) { 2140 /* 2141 * Wrap the exception thrown from ConsumerListener in this case, 2142 * so we can see that it unexpectedly reached this spot in 2143 * native code (dtrace_aggregate_snap should have returned 2144 * non-zero). 2145 */ 2146 WRAP_EXCEPTION(jenv); 2147 /* release per-consumer lock */ 2148 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2149 return (NULL); 2150 } 2151 2152 /* Create the Java representation of the aggregate snapshot. */ 2153 aggregate = (*jenv)->NewObject(jenv, g_agg_jc, g_agginit_jm, 2154 snaptime); 2155 if ((*jenv)->ExceptionCheck(jenv)) { 2156 WRAP_EXCEPTION(jenv); 2157 /* release per-consumer lock */ 2158 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2159 return (NULL); 2160 } 2161 jc->dtjj_aggregate = aggregate; 2162 2163 /* 2164 * Walk the aggregate, converting the data into Java Objects. Traverse 2165 * in order by aggregation ID first and tuple second by using 2166 * dtrace_aggregate_walk_keysorted (uses varkeycmp). We cannot do the 2167 * same for aggregations generated by the printa() action, since 2168 * dtrace_work() traverses aggregation data in the order determined by 2169 * the various "aggsort" options. Functions used by both the consumer 2170 * loop and the competing getAggregate() thread must not depend on the 2171 * ordering of records by tuple key. 2172 * 2173 * It is impractical to hold the global lock around 2174 * dtrace_aggregate_print(), since it may take a long time (e.g. an 2175 * entire second) if it performs expensive conversions such as that 2176 * needed for user stack traces. Most libdtrace functions are not 2177 * guaranteed to be MT-safe, even when each thread has its own dtrace 2178 * handle; or even if they are safe, there is no guarantee that future 2179 * changes may not make them unsafe. Fortunately in this case, however, 2180 * only a per-consumer lock is necessary to avoid conflict with 2181 * dtrace_work() running in another thread (the consumer loop). 2182 */ 2183 rc = dtrace_aggregate_print(jc->dtjj_consumer->dtjc_dtp, NULL, 2184 dtrace_aggregate_walk_keysorted); 2185 if ((*jenv)->ExceptionCheck(jenv)) { 2186 WRAP_EXCEPTION(jenv); 2187 /* release per-consumer lock */ 2188 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2189 return (NULL); 2190 } 2191 if (rc != 0) { 2192 dtj_error_t e; 2193 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2194 /* release per-consumer lock */ 2195 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2196 return (NULL); 2197 } 2198 2199 if (e.dtje_number != EINTR) { 2200 /* Do not wrap DTraceException */ 2201 dtj_throw_dtrace_exception(jc, e.dtje_message); 2202 /* release per-consumer lock */ 2203 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2204 return (NULL); 2205 } 2206 } 2207 2208 dtj_aggwalk_init(jc); 2209 if ((*jenv)->ExceptionCheck(jenv)) { 2210 WRAP_EXCEPTION(jenv); 2211 /* release per-consumer lock */ 2212 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2213 return (NULL); 2214 } 2215 2216 /* 2217 * dtrace_aggregate_clear() clears all aggregations, and we need to 2218 * clear aggregations selectively. It also fails to preserve the 2219 * lquantize() range and step size; using aggregate_walk() to clear 2220 * aggregations does not have this problem. 2221 */ 2222 rc = dtrace_aggregate_walk(jc->dtjj_consumer->dtjc_dtp, dtj_clear, jc); 2223 if ((*jenv)->ExceptionCheck(jenv)) { 2224 WRAP_EXCEPTION(jenv); 2225 /* release per-consumer lock */ 2226 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2227 return (NULL); 2228 } 2229 if (rc != 0) { 2230 dtj_error_t e; 2231 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2232 /* Do not wrap DTraceException */ 2233 dtj_throw_dtrace_exception(jc, e.dtje_message); 2234 } 2235 /* release per-consumer lock */ 2236 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2237 return (NULL); 2238 } 2239 2240 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2241 if ((*jenv)->ExceptionCheck(jenv)) { 2242 WRAP_EXCEPTION(jenv); 2243 return (NULL); 2244 } 2245 2246 aggregate = jc->dtjj_aggregate; 2247 jc->dtjj_aggregate = NULL; 2248 2249 return (aggregate); 2250 } 2251 2252 /* 2253 * Process any requests, such as the setting of runtime options, enqueued during 2254 * dtrace_sleep(). A Java exception is pending if this function returns 2255 * DTJ_ERR. 2256 */ 2257 static dtj_status_t 2258 dtj_process_requests(dtj_java_consumer_t *jc) 2259 { 2260 dtj_request_t *r; 2261 uu_list_t *list = jc->dtjj_consumer->dtjc_request_list; 2262 pthread_mutex_t *list_lock = &jc->dtjj_consumer-> 2263 dtjc_request_list_lock; 2264 const char *opt; 2265 const char *val; 2266 2267 (void) pthread_mutex_lock(list_lock); 2268 while (!dtj_list_empty(list)) { 2269 r = uu_list_first(list); 2270 uu_list_remove(list, r); 2271 2272 switch (r->dtjr_type) { 2273 case DTJ_REQUEST_OPTION: 2274 opt = dtj_string_list_first(r->dtjr_args); 2275 val = dtj_string_list_last(r->dtjr_args); 2276 if (dtrace_setopt(jc->dtjj_consumer->dtjc_dtp, opt, 2277 val) == -1) { 2278 /* Do not wrap DTraceException */ 2279 dtj_throw_dtrace_exception(jc, 2280 "failed to set %s: %s", opt, 2281 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2282 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2283 dtj_request_destroy(r, NULL); 2284 (void) pthread_mutex_unlock(list_lock); 2285 return (DTJ_ERR); 2286 } 2287 break; 2288 } 2289 dtj_request_destroy(r, NULL); 2290 } 2291 (void) pthread_mutex_unlock(list_lock); 2292 return (DTJ_OK); 2293 } 2294 2295 /* 2296 * Return DTJ_OK if the consumer loop is stopped normally by either the exit() 2297 * action or the Consumer stop() method. Otherwise return DTJ_ERR if the 2298 * consumer loop terminates abnormally with an exception pending. 2299 */ 2300 dtj_status_t 2301 dtj_consume(dtj_java_consumer_t *jc) 2302 { 2303 JNIEnv *jenv = jc->dtjj_jenv; 2304 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 2305 boolean_t done = B_FALSE; 2306 dtj_error_t e; 2307 2308 do { 2309 if (!jc->dtjj_consumer->dtjc_interrupt) { 2310 dtrace_sleep(dtp); 2311 } 2312 2313 if (jc->dtjj_consumer->dtjc_interrupt) { 2314 done = B_TRUE; 2315 dtj_stop(jc); 2316 if ((*jenv)->ExceptionCheck(jenv)) { 2317 /* 2318 * Exception left pending by Consumer 2319 * getAggregate() method. 2320 */ 2321 return (DTJ_ERR); 2322 } 2323 } else if (jc->dtjj_consumer->dtjc_process_list != NULL) { 2324 int nprocs = uu_list_numnodes(jc->dtjj_consumer-> 2325 dtjc_process_list); 2326 if (jc->dtjj_consumer->dtjc_procs_ended == nprocs) { 2327 done = B_TRUE; 2328 dtj_stop(jc); 2329 } 2330 } 2331 2332 /* 2333 * Functions like dtrace_setopt() are not safe to call during 2334 * dtrace_sleep(). Check the request list every time we wake up 2335 * from dtrace_sleep(). 2336 */ 2337 if (!done) { 2338 if (dtj_process_requests(jc) != DTJ_OK) { 2339 /* Do not wrap DTraceException */ 2340 return (DTJ_ERR); 2341 } 2342 } 2343 2344 /* Must not call MonitorEnter with a pending exception */ 2345 if ((*jenv)->ExceptionCheck(jenv)) { 2346 WRAP_EXCEPTION(jenv); 2347 return (DTJ_ERR); 2348 } 2349 2350 /* 2351 * Use the per-consumer lock to avoid conflict with 2352 * get_aggregate() called from another thread. 2353 */ 2354 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2355 if ((*jenv)->ExceptionCheck(jenv)) { 2356 WRAP_EXCEPTION(jenv); 2357 return (DTJ_ERR); 2358 } 2359 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2360 g_interval_began_jm); 2361 if ((*jenv)->ExceptionCheck(jenv)) { 2362 /* Don't wrap exception thrown from ConsumerListener */ 2363 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2364 return (DTJ_ERR); 2365 } 2366 jc->dtjj_consumer->dtjc_printa_snaptime = gethrtime(); 2367 switch (dtrace_work(dtp, NULL, dtj_chew, dtj_chewrec, jc)) { 2368 case DTRACE_WORKSTATUS_DONE: 2369 done = B_TRUE; 2370 break; 2371 case DTRACE_WORKSTATUS_OKAY: 2372 break; 2373 default: 2374 /* 2375 * Check for a pending exception that got us to this 2376 * error workstatus case. 2377 */ 2378 if ((*jenv)->ExceptionCheck(jenv)) { 2379 /* 2380 * Ensure valid initial state before releasing 2381 * the consumer lock 2382 */ 2383 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2384 /* Do not wrap DTraceException */ 2385 /* Release per-consumer lock */ 2386 (*jenv)->MonitorExit(jenv, 2387 jc->dtjj_consumer_lock); 2388 return (DTJ_ERR); 2389 } 2390 2391 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2392 /* java exception pending */ 2393 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2394 /* Release per-consumer lock */ 2395 (*jenv)->MonitorExit(jenv, 2396 jc->dtjj_consumer_lock); 2397 return (DTJ_ERR); 2398 } 2399 2400 if (e.dtje_number != EINTR) { 2401 /* Do not wrap DTraceException */ 2402 dtj_throw_dtrace_exception(jc, e.dtje_message); 2403 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2404 /* Release per-consumer lock */ 2405 (*jenv)->MonitorExit(jenv, 2406 jc->dtjj_consumer_lock); 2407 return (DTJ_ERR); 2408 } 2409 } 2410 /* 2411 * Check for ConsumerException before doing anything else with 2412 * the JNIEnv. 2413 */ 2414 if ((*jenv)->ExceptionCheck(jenv)) { 2415 /* 2416 * Do not wrap exception thrown from ConsumerListener. 2417 */ 2418 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2419 /* Release per-consumer lock */ 2420 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2421 return (DTJ_ERR); 2422 } 2423 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2424 /* 2425 * Notify ConsumerListeners the the dtrace_work() interval ended 2426 * before releasing the lock. 2427 */ 2428 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2429 g_interval_ended_jm); 2430 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2431 if ((*jenv)->ExceptionCheck(jenv)) { 2432 /* Don't wrap exception thrown from ConsumerListener */ 2433 return (DTJ_ERR); 2434 } 2435 2436 /* 2437 * Check for a temporarily cleared exception set by a handler 2438 * that could not safely leave the exception pending because it 2439 * could not return an abort signal. Rethrow it now that it's 2440 * safe to do so (when it's possible to ensure that no JNI calls 2441 * will be made that are unsafe while an exception is pending). 2442 */ 2443 if (jc->dtjj_exception) { 2444 (*jenv)->Throw(jenv, jc->dtjj_exception); 2445 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_exception); 2446 jc->dtjj_exception = NULL; 2447 return (DTJ_ERR); 2448 } 2449 } while (!done); 2450 2451 return (DTJ_OK); 2452 } 2453