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