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