1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <ctype.h> 29 #include <limits.h> 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <strings.h> 34 #include <sys/wait.h> 35 #include <limits.h> 36 #include <signal.h> 37 #include <libproc.h> 38 #include <pthread.h> 39 #include <dtrace_jni.h> 40 41 /* 42 * Implements the work done in the running consumer loop. The native Java 43 * methods (JNI layer) are implemented in dtrace_jni.c. 44 */ 45 46 /* Record handler passed to dtrace_work() */ 47 static int dtj_chewrec(const dtrace_probedata_t *, const dtrace_recdesc_t *, 48 void *); 49 /* Probe data handler passed to dtrace_work() */ 50 static int dtj_chew(const dtrace_probedata_t *, void *); 51 52 /* Processes requests from LocalConsumer enqueued during dtrace_sleep() */ 53 static dtj_status_t dtj_process_requests(dtj_java_consumer_t *); 54 55 /* 56 * Callback handlers set in dtj_set_callback_handlers(), called from libdtrace 57 * in the consumer loop (from dtrace_work()) 58 */ 59 static int dtj_drophandler(const dtrace_dropdata_t *, void *); 60 static int dtj_errhandler(const dtrace_errdata_t *, void *); 61 static void dtj_prochandler(struct ps_prochandle *, const char *, void *); 62 static int dtj_setopthandler(const dtrace_setoptdata_t *, void *); 63 /* 64 * Buffered output handler called from libdtrace in both the consumer loop (from 65 * dtrace_work()) and the get_aggregate() function (from 66 * dtrace_aggregate_print()). 67 */ 68 static int dtj_bufhandler(const dtrace_bufdata_t *, void *); 69 70 /* Conversion of libdtrace data into Java Objects */ 71 static jobject dtj_recdata(dtj_java_consumer_t *, uint32_t, caddr_t); 72 static jobject dtj_bytedata(JNIEnv *, uint32_t, caddr_t); 73 static jobject dtj_new_stack_record(const caddr_t, const dtrace_recdesc_t *, 74 dtj_java_consumer_t *); 75 static jobject dtj_new_probedata_stack_record(const dtrace_probedata_t *, 76 const dtrace_recdesc_t *, dtj_java_consumer_t *); 77 static jobject dtj_new_symbol_record(const caddr_t, const dtrace_recdesc_t *, 78 dtj_java_consumer_t *); 79 static jobject dtj_new_probedata_symbol_record(const dtrace_probedata_t *, 80 const dtrace_recdesc_t *, dtj_java_consumer_t *); 81 /* Aggregation data */ 82 static jobject dtj_new_tuple_stack_record(const dtrace_aggdata_t *, 83 const dtrace_recdesc_t *, const char *, dtj_java_consumer_t *); 84 static jobject dtj_new_tuple_symbol_record(const dtrace_aggdata_t *, 85 const dtrace_recdesc_t *, const char *, dtj_java_consumer_t *); 86 static jobject dtj_new_distribution(const dtrace_aggdata_t *, 87 const dtrace_recdesc_t *, dtj_java_consumer_t *); 88 static jobject dtj_new_aggval(dtj_java_consumer_t *, const dtrace_aggdata_t *, 89 const dtrace_recdesc_t *); 90 static int64_t dtj_average(caddr_t, uint64_t); 91 static int64_t dtj_avg_total(caddr_t, uint64_t); 92 static int64_t dtj_avg_count(caddr_t); 93 static jobject dtj_stddev(JNIEnv *, caddr_t, uint64_t); 94 95 /* Aggregation functions */ 96 static void dtj_aggwalk_init(dtj_java_consumer_t *); 97 static int dtj_agghandler(const dtrace_bufdata_t *, dtj_java_consumer_t *); 98 static boolean_t dtj_is_included(const dtrace_aggdata_t *, 99 dtj_java_consumer_t *); 100 static void dtj_attach_frames(dtj_java_consumer_t *, jobject, jobjectArray); 101 static void dtj_attach_name(dtj_java_consumer_t *, jobject, jstring); 102 static boolean_t dtj_is_stack_action(dtrace_actkind_t); 103 static boolean_t dtj_is_symbol_action(dtrace_actkind_t); 104 static int dtj_clear(const dtrace_aggdata_t *, void *); 105 106 /* 107 * The consumer loop needs to protect calls to libdtrace functions with a global 108 * lock. JNI native method calls in dtrace_jni.c are already protected and do 109 * not need this function. 110 */ 111 dtj_status_t 112 dtj_get_dtrace_error(dtj_java_consumer_t *jc, dtj_error_t *e) 113 { 114 JNIEnv *jenv = jc->dtjj_jenv; 115 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 116 117 /* Must not call MonitorEnter with a pending exception */ 118 if ((*jenv)->ExceptionCheck(jenv)) { 119 WRAP_EXCEPTION(jenv); 120 return (DTJ_ERR); 121 } 122 /* Grab global lock */ 123 (*jenv)->MonitorEnter(jenv, g_caller_jc); 124 if ((*jenv)->ExceptionCheck(jenv)) { 125 WRAP_EXCEPTION(jenv); 126 return (DTJ_ERR); 127 } 128 e->dtje_number = dtrace_errno(dtp); 129 e->dtje_message = dtrace_errmsg(dtp, e->dtje_number); 130 (*jenv)->MonitorExit(jenv, g_caller_jc); 131 if ((*jenv)->ExceptionCheck(jenv)) { 132 WRAP_EXCEPTION(jenv); 133 return (DTJ_ERR); 134 } 135 return (DTJ_OK); 136 } 137 138 /* 139 * Protected by global lock (LocalConsumer.class) that protects call to 140 * Java_org_opensolaris_os_dtrace_LocalConsumer__1go() 141 */ 142 dtj_status_t 143 dtj_set_callback_handlers(dtj_java_consumer_t *jc) 144 { 145 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 146 dtrace_optval_t optval; 147 148 if (dtrace_handle_buffered(dtp, &dtj_bufhandler, NULL) == -1) { 149 dtj_throw_dtrace_exception(jc, 150 "failed to establish buffered handler: %s", 151 dtrace_errmsg(dtp, dtrace_errno(dtp))); 152 return (DTJ_ERR); 153 } 154 155 if (dtrace_handle_drop(dtp, &dtj_drophandler, NULL) == -1) { 156 dtj_throw_dtrace_exception(jc, 157 "failed to establish drop handler: %s", 158 dtrace_errmsg(dtp, dtrace_errno(dtp))); 159 return (DTJ_ERR); 160 } 161 162 if (dtrace_handle_err(dtp, &dtj_errhandler, NULL) == -1) { 163 dtj_throw_dtrace_exception(jc, 164 "failed to establish error handler: %s", 165 dtrace_errmsg(dtp, dtrace_errno(dtp))); 166 return (DTJ_ERR); 167 } 168 169 if (dtrace_handle_proc(dtp, &dtj_prochandler, NULL) == -1) { 170 dtj_throw_dtrace_exception(jc, 171 "failed to establish proc handler: %s", 172 dtrace_errmsg(dtp, dtrace_errno(dtp))); 173 return (DTJ_ERR); 174 } 175 176 if (dtrace_getopt(dtp, "flowindent", &optval) == -1) { 177 dtj_throw_dtrace_exception(jc, 178 "couldn't get option %s: %s", "flowindent", 179 dtrace_errmsg(dtp, dtrace_errno(dtp))); 180 return (DTJ_ERR); 181 } 182 183 jc->dtjj_consumer->dtjc_flow = (optval != DTRACEOPT_UNSET); 184 185 if (dtrace_handle_setopt(dtp, &dtj_setopthandler, NULL) == -1) { 186 dtj_throw_dtrace_exception(jc, 187 "failed to establish setopt handler: %s", 188 dtrace_errmsg(dtp, dtrace_errno(dtp))); 189 return (DTJ_ERR); 190 } 191 192 return (DTJ_OK); 193 } 194 195 static int 196 /* ARGSUSED */ 197 dtj_drophandler(const dtrace_dropdata_t *data, void *arg) 198 { 199 dtj_java_consumer_t *jc; 200 JNIEnv *jenv; 201 202 const char *dropkind; 203 204 jstring msg = NULL; 205 jstring kind = NULL; 206 jobject drop = NULL; 207 208 jc = pthread_getspecific(g_dtj_consumer_key); 209 jenv = jc->dtjj_jenv; 210 211 msg = dtj_NewStringNative(jenv, data->dtdda_msg); 212 if ((*jenv)->ExceptionCheck(jenv)) { 213 return (DTRACE_HANDLE_ABORT); 214 } 215 switch (data->dtdda_kind) { 216 case DTRACEDROP_PRINCIPAL: 217 dropkind = "PRINCIPAL"; 218 break; 219 case DTRACEDROP_AGGREGATION: 220 dropkind = "AGGREGATION"; 221 break; 222 case DTRACEDROP_DYNAMIC: 223 dropkind = "DYNAMIC"; 224 break; 225 case DTRACEDROP_DYNRINSE: 226 dropkind = "DYNRINSE"; 227 break; 228 case DTRACEDROP_DYNDIRTY: 229 dropkind = "DYNDIRTY"; 230 break; 231 case DTRACEDROP_SPEC: 232 dropkind = "SPEC"; 233 break; 234 case DTRACEDROP_SPECBUSY: 235 dropkind = "SPECBUSY"; 236 break; 237 case DTRACEDROP_SPECUNAVAIL: 238 dropkind = "SPECUNAVAIL"; 239 break; 240 case DTRACEDROP_STKSTROVERFLOW: 241 dropkind = "STKSTROVERFLOW"; 242 break; 243 case DTRACEDROP_DBLERROR: 244 dropkind = "DBLERROR"; 245 break; 246 default: 247 dropkind = "UNKNOWN"; 248 } 249 kind = (*jenv)->NewStringUTF(jenv, dropkind); 250 if ((*jenv)->ExceptionCheck(jenv)) { 251 (*jenv)->DeleteLocalRef(jenv, msg); 252 return (DTRACE_HANDLE_ABORT); 253 } 254 drop = (*jenv)->NewObject(jenv, g_drop_jc, g_dropinit_jm, 255 data->dtdda_cpu, kind, data->dtdda_drops, data->dtdda_total, msg); 256 (*jenv)->DeleteLocalRef(jenv, kind); 257 (*jenv)->DeleteLocalRef(jenv, msg); 258 if ((*jenv)->ExceptionCheck(jenv)) { 259 return (DTRACE_HANDLE_ABORT); 260 } 261 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_drop_jm, drop); 262 (*jenv)->DeleteLocalRef(jenv, drop); 263 if ((*jenv)->ExceptionCheck(jenv)) { 264 return (DTRACE_HANDLE_ABORT); 265 } 266 267 return (DTRACE_HANDLE_OK); 268 } 269 270 static int 271 /* ARGSUSED */ 272 dtj_errhandler(const dtrace_errdata_t *data, void *arg) 273 { 274 dtj_java_consumer_t *jc; 275 JNIEnv *jenv; 276 277 const char *f; 278 int64_t addr; 279 280 jobject probe = NULL; 281 jstring fault = NULL; 282 jstring msg = NULL; 283 jobject error = NULL; 284 285 jc = pthread_getspecific(g_dtj_consumer_key); 286 jenv = jc->dtjj_jenv; 287 288 probe = dtj_new_probedesc(jc, data->dteda_pdesc); 289 if (!probe) { 290 return (DTRACE_HANDLE_ABORT); 291 } 292 f = dtj_get_fault_name(data->dteda_fault); 293 if (f) { 294 fault = (*jenv)->NewStringUTF(jenv, f); 295 if ((*jenv)->ExceptionCheck(jenv)) { 296 (*jenv)->DeleteLocalRef(jenv, probe); 297 return (DTRACE_HANDLE_ABORT); 298 } 299 } 300 switch (data->dteda_fault) { 301 case DTRACEFLT_BADADDR: 302 case DTRACEFLT_BADALIGN: 303 case DTRACEFLT_BADSTACK: 304 addr = data->dteda_addr; 305 break; 306 default: 307 addr = -1; 308 } 309 msg = dtj_NewStringNative(jenv, data->dteda_msg); 310 if ((*jenv)->ExceptionCheck(jenv)) { 311 (*jenv)->DeleteLocalRef(jenv, probe); 312 (*jenv)->DeleteLocalRef(jenv, fault); 313 return (DTRACE_HANDLE_ABORT); 314 } 315 error = (*jenv)->NewObject(jenv, g_error_jc, g_errinit_jm, 316 probe, 317 data->dteda_edesc->dtepd_epid, 318 data->dteda_cpu, 319 data->dteda_action, 320 data->dteda_offset, 321 fault, addr, msg); 322 (*jenv)->DeleteLocalRef(jenv, msg); 323 (*jenv)->DeleteLocalRef(jenv, fault); 324 (*jenv)->DeleteLocalRef(jenv, probe); 325 if ((*jenv)->ExceptionCheck(jenv)) { 326 return (DTRACE_HANDLE_ABORT); 327 } 328 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_error_jm, error); 329 (*jenv)->DeleteLocalRef(jenv, error); 330 if ((*jenv)->ExceptionCheck(jenv)) { 331 return (DTRACE_HANDLE_ABORT); 332 } 333 334 return (DTRACE_HANDLE_OK); 335 } 336 337 /* 338 * Since the function signature does not allow us to return an abort signal, we 339 * need to temporarily clear any pending exception before returning, since 340 * without the abort we can't guarantee that the exception will be checked in 341 * time to prevent invalid JNI function calls. 342 */ 343 static void 344 /* ARGSUSED */ 345 dtj_prochandler(struct ps_prochandle *P, const char *msg, void *arg) 346 { 347 dtj_java_consumer_t *jc; 348 JNIEnv *jenv; 349 350 const psinfo_t *prp = Ppsinfo(P); 351 int pid = Pstatus(P)->pr_pid; 352 int signal = -1; 353 char signame[SIG2STR_MAX]; 354 const char *statusname; 355 int exit = INT_MAX; /* invalid initial status */ 356 357 jstring status = NULL; 358 jstring signalName = NULL; 359 jstring message = NULL; 360 jobject process = NULL; 361 362 jc = pthread_getspecific(g_dtj_consumer_key); 363 jenv = jc->dtjj_jenv; 364 365 switch (Pstate(P)) { 366 case PS_RUN: 367 statusname = "RUN"; 368 break; 369 case PS_STOP: 370 statusname = "STOP"; 371 break; 372 case PS_UNDEAD: 373 statusname = "UNDEAD"; 374 if (prp != NULL) { 375 exit = WEXITSTATUS(prp->pr_wstat); 376 } 377 if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { 378 signal = WTERMSIG(prp->pr_wstat); 379 (void) proc_signame(signal, signame, sizeof (signame)); 380 signalName = (*jenv)->NewStringUTF(jenv, signame); 381 if ((*jenv)->ExceptionCheck(jenv)) { 382 goto proc_end; 383 } 384 } 385 ++jc->dtjj_consumer->dtjc_procs_ended; 386 break; 387 case PS_LOST: 388 statusname = "LOST"; 389 ++jc->dtjj_consumer->dtjc_procs_ended; 390 break; 391 case PS_DEAD: 392 /* 393 * PS_DEAD not handled by dtrace.c prochandler, still this is a 394 * case of process termination and it can't hurt to handle it. 395 */ 396 statusname = "DEAD"; 397 ++jc->dtjj_consumer->dtjc_procs_ended; 398 break; 399 default: 400 /* 401 * Unexpected, but erring on the side of tolerance by not 402 * crashing the consumer. Failure to notify listeners of 403 * process state not handled by the dtrace.c prochandler does 404 * not seem serious. 405 */ 406 return; 407 } 408 409 status = (*jenv)->NewStringUTF(jenv, statusname); 410 if ((*jenv)->ExceptionCheck(jenv)) { 411 (*jenv)->DeleteLocalRef(jenv, signalName); 412 goto proc_end; 413 } 414 if (msg) { 415 message = dtj_NewStringNative(jenv, msg); 416 if (!message) { 417 (*jenv)->DeleteLocalRef(jenv, status); 418 (*jenv)->DeleteLocalRef(jenv, signalName); 419 goto proc_end; 420 } 421 } 422 process = (*jenv)->NewObject(jenv, g_process_jc, g_procinit_jm, 423 pid, status, signal, signalName, NULL, message); 424 (*jenv)->DeleteLocalRef(jenv, status); 425 (*jenv)->DeleteLocalRef(jenv, signalName); 426 (*jenv)->DeleteLocalRef(jenv, message); 427 if ((*jenv)->ExceptionCheck(jenv)) { 428 goto proc_end; 429 } 430 if (exit != INT_MAX) { 431 /* valid exit status */ 432 (*jenv)->CallVoidMethod(jenv, process, g_procexit_jm, exit); 433 if ((*jenv)->ExceptionCheck(jenv)) { 434 (*jenv)->DeleteLocalRef(jenv, process); 435 goto proc_end; 436 } 437 } 438 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_proc_jm, process); 439 (*jenv)->DeleteLocalRef(jenv, process); 440 441 proc_end: 442 443 if ((*jenv)->ExceptionCheck(jenv)) { 444 /* 445 * Save the exception so we can rethrow it later when it's safe. 446 */ 447 if (!jc->dtjj_exception) { 448 jthrowable e = (*jenv)->ExceptionOccurred(jenv); 449 jc->dtjj_exception = e; 450 } 451 (*jenv)->ExceptionClear(jenv); 452 } 453 } 454 455 static int 456 /* ARGSUSED */ 457 dtj_setopthandler(const dtrace_setoptdata_t *data, void *arg) 458 { 459 dtj_java_consumer_t *jc; 460 461 jc = pthread_getspecific(g_dtj_consumer_key); 462 if (strcmp(data->dtsda_option, "flowindent") == 0) { 463 jc->dtjj_consumer->dtjc_flow = 464 (data->dtsda_newval != DTRACEOPT_UNSET); 465 } 466 return (DTRACE_HANDLE_OK); 467 } 468 469 /* 470 * Most of this function lifted from libdtrace/common/dt_consume.c 471 * dt_print_bytes(). 472 */ 473 static jobject 474 dtj_bytedata(JNIEnv *jenv, uint32_t nbytes, caddr_t addr) 475 { 476 /* 477 * If the byte stream is a series of printable characters, followed by 478 * a terminating byte, we print it out as a string. Otherwise, we 479 * assume that it's something else and just print the bytes. 480 */ 481 int i, j; 482 char *c = addr; 483 484 jobject jobj = NULL; /* return value */ 485 486 if (nbytes == 0) { 487 return ((*jenv)->NewStringUTF(jenv, "")); 488 } 489 490 for (i = 0; i < nbytes; i++) { 491 /* 492 * We define a "printable character" to be one for which 493 * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 494 * or a character which is either backspace or the bell. 495 * Backspace and the bell are regrettably special because 496 * they fail the first two tests -- and yet they are entirely 497 * printable. These are the only two control characters that 498 * have meaning for the terminal and for which isprint(3C) and 499 * isspace(3C) return 0. 500 */ 501 if (isprint(c[i]) || isspace(c[i]) || 502 c[i] == '\b' || c[i] == '\a') 503 continue; 504 505 if (c[i] == '\0' && i > 0) { 506 /* 507 * This looks like it might be a string. Before we 508 * assume that it is indeed a string, check the 509 * remainder of the byte range; if it contains 510 * additional non-nul characters, we'll assume that 511 * it's a binary stream that just happens to look like 512 * a string. 513 */ 514 for (j = i + 1; j < nbytes; j++) { 515 if (c[j] != '\0') 516 break; 517 } 518 519 if (j != nbytes) 520 break; 521 522 /* It's a string */ 523 return (dtj_NewStringNative(jenv, (char *)addr)); 524 } 525 526 break; 527 } 528 529 if (i == nbytes) { 530 /* 531 * The byte range is all printable characters, but there is 532 * no trailing nul byte. We'll assume that it's a string. 533 */ 534 char *s = malloc(nbytes + 1); 535 if (!s) { 536 dtj_throw_out_of_memory(jenv, 537 "failed to allocate string value"); 538 return (NULL); 539 } 540 (void) strncpy(s, c, nbytes); 541 s[nbytes] = '\0'; 542 jobj = dtj_NewStringNative(jenv, s); 543 free(s); 544 return (jobj); 545 } 546 547 /* return byte array */ 548 jobj = (*jenv)->NewByteArray(jenv, nbytes); 549 if ((*jenv)->ExceptionCheck(jenv)) { 550 return (NULL); 551 } 552 (*jenv)->SetByteArrayRegion(jenv, (jbyteArray)jobj, 0, nbytes, 553 (const jbyte *)c); 554 if ((*jenv)->ExceptionCheck(jenv)) { 555 WRAP_EXCEPTION(jenv); 556 (*jenv)->DeleteLocalRef(jenv, jobj); 557 return (NULL); 558 } 559 return (jobj); 560 } 561 562 /* 563 * Return NULL if memory could not be allocated (OutOfMemoryError is thrown in 564 * that case). 565 */ 566 static jobject 567 dtj_recdata(dtj_java_consumer_t *jc, uint32_t size, caddr_t addr) 568 { 569 JNIEnv *jenv = jc->dtjj_jenv; 570 jobject jobj; 571 jobject jrec; 572 573 switch (size) { 574 case 1: 575 jobj = (*jenv)->NewObject(jenv, g_int_jc, 576 g_intinit_jm, (int)(*((uint8_t *)addr))); 577 break; 578 case 2: 579 jobj = (*jenv)->NewObject(jenv, g_int_jc, 580 /* LINTED - alignment */ 581 g_intinit_jm, (int)(*((uint16_t *)addr))); 582 break; 583 case 4: 584 jobj = (*jenv)->NewObject(jenv, g_int_jc, 585 /* LINTED - alignment */ 586 g_intinit_jm, *((int32_t *)addr)); 587 break; 588 case 8: 589 jobj = (*jenv)->NewObject(jenv, g_long_jc, 590 /* LINTED - alignment */ 591 g_longinit_jm, *((int64_t *)addr)); 592 break; 593 default: 594 jobj = dtj_bytedata(jenv, size, addr); 595 break; 596 } 597 598 if (!jobj) { 599 return (NULL); /* OutOfMemoryError pending */ 600 } 601 602 jrec = (*jenv)->NewObject(jenv, g_scalar_jc, 603 g_scalarinit_jm, jobj, size); 604 (*jenv)->DeleteLocalRef(jenv, jobj); 605 606 return (jrec); 607 } 608 609 /* 610 * This is the record handling function passed to dtrace_work(). It differs 611 * from the bufhandler registered with dtrace_handle_buffered() as follows: 612 * 613 * 1. It does not have access to libdtrace formatted output. 614 * 2. It is called once for every D program statement, not for every 615 * output-producing D action or aggregation record. A statement may be a 616 * variable assignment, having no size and producing no output. 617 * 3. It is called for the D exit() action; the bufhandler is not. 618 * 4. In response to the printa() action, it is called with a record having an 619 * action of type DTRACEACT_PRINTA. The bufhandler never sees that action 620 * value. It only sees the output-producing aggregation records. 621 * 5. It is called with a NULL record at the end of each probedata. 622 */ 623 static int 624 dtj_chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, 625 void *arg) 626 { 627 dtj_java_consumer_t *jc = arg; 628 JNIEnv *jenv = jc->dtjj_jenv; 629 630 const dtrace_eprobedesc_t *edesc = data->dtpda_edesc; 631 dtrace_actkind_t act; 632 int r; 633 634 /* 635 * Update the record index to that of the current record, or to that of 636 * the last record if rec is NULL (signalling end of probe data). 637 */ 638 if (rec == NULL) { 639 r = edesc->dtepd_nrecs; /* end of probe data */ 640 } else { 641 /* 642 * This record handler is called once for the printf() action, 643 * but there may be multiple records in the probedata 644 * corresponding to the unformatted elements of that printf(). 645 * We don't know ahead of time how many probedata records 646 * libdtrace will consume to produce output for one printf() 647 * action, so we look back at the previous call to dtj_chewrec() 648 * to see how many probedata records were consumed. All 649 * non-null elements in the range from the previous record index 650 * up to and not including the current record index are assumed 651 * to be unformatted printf() elements, and will be attached to 652 * the PrintfRecord from the previous call. A null element in 653 * that range is the result of a D program statement preceding 654 * the printf() that is not a D action. These generate 655 * probedata records accounted for by the null placeholder, but 656 * do not advance the probedata offset and are not part of the 657 * subsequent printf(). 658 * 659 * If rec->dtrd_size == 0, the record represents a D program 660 * statement that is not a D action. It has no size and does 661 * not advance the offset in the probedata. Handle it normally 662 * without special-casing or premature return, since in all 663 * cases we look at the previous record later in this function. 664 */ 665 for (r = jc->dtjj_consumer->dtjc_probedata_rec_i; 666 ((r < edesc->dtepd_nrecs) && 667 (edesc->dtepd_rec[r].dtrd_offset < rec->dtrd_offset)); 668 ++r) { 669 } 670 } 671 672 /* 673 * Attach the Java representations of the libdtrace data elements 674 * pertaining to the previous call to this record handler to the 675 * previous Java Record. (All data elements belonging to the current 676 * probedata are added to a single list by the probedata consumer 677 * function dtj_chew() before this record consumer function is ever 678 * called.) For example, if the previous Record was generated by the 679 * printf() action, and dtj_chew() listed 3 records for its 3 680 * unformatted elements, those 3 libdtrace records comprise 1 681 * PrintfRecord. Note that we cannot know how many data elements apply 682 * to the current rec until we find out the data index where the next 683 * rec starts. (The knowledge of how many probedata records to consume 684 * is private to libdtrace.) 685 */ 686 if (jc->dtjj_consumer->dtjc_probedata_act == DTRACEACT_PRINTF) { 687 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 688 g_pdataattach_jm, 689 jc->dtjj_consumer->dtjc_probedata_rec_i, r - 1); 690 if ((*jenv)->ExceptionCheck(jenv)) { 691 WRAP_EXCEPTION(jenv); 692 return (DTRACE_CONSUME_ABORT); 693 } 694 } 695 696 if (rec == NULL) { 697 /* 698 * End of probe data. Notify listeners of the new ProbeData 699 * instance. 700 */ 701 if (jc->dtjj_probedata) { 702 /* previous probedata */ 703 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 704 g_pdataclear_jm); 705 if ((*jenv)->ExceptionCheck(jenv)) { 706 WRAP_EXCEPTION(jenv); 707 return (DTRACE_CONSUME_ABORT); 708 } 709 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 710 g_pdatanext_jm, jc->dtjj_probedata); 711 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_probedata); 712 jc->dtjj_probedata = NULL; 713 if ((*jenv)->ExceptionCheck(jenv)) { 714 /* 715 * Do not wrap exception thrown from 716 * ConsumerListener. 717 */ 718 return (DTRACE_CONSUME_ABORT); 719 } 720 } 721 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_printa_buffer); 722 jc->dtjj_printa_buffer = NULL; 723 return (DTRACE_CONSUME_NEXT); 724 } 725 726 act = rec->dtrd_action; 727 728 /* Set previous record action and data index to current */ 729 jc->dtjj_consumer->dtjc_probedata_act = act; 730 jc->dtjj_consumer->dtjc_probedata_rec_i = r; 731 732 switch (act) { 733 case DTRACEACT_DIFEXPR: 734 case DTRACEACT_TRACEMEM: 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 case DTRACEACT_TRACEMEM: 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 switch (act) { 1535 case DTRACEAGG_LQUANTIZE: 1536 /* first "bucket" used for range and step */ 1537 value = *aggbuckets++; 1538 base = DTRACE_LQUANTIZE_BASE(value); 1539 step = DTRACE_LQUANTIZE_STEP(value); 1540 levels = DTRACE_LQUANTIZE_LEVELS(value); 1541 size -= sizeof (int64_t); /* exclude non-bucket */ 1542 /* 1543 * Add one for the base bucket and one for the bucket of values 1544 * less than the base. 1545 */ 1546 n = levels + 2; 1547 break; 1548 case DTRACEAGG_LLQUANTIZE: 1549 value = *aggbuckets++; 1550 size -= sizeof (int64_t); 1551 levels = size / sizeof (int64_t); 1552 n = levels; 1553 break; 1554 case DTRACEAGG_QUANTIZE: 1555 n = DTRACE_QUANTIZE_NBUCKETS; 1556 levels = n - 1; /* levels excludes base */ 1557 break; 1558 } 1559 1560 if (size != (n * sizeof (uint64_t)) || n < 1) { 1561 dtj_throw_illegal_state(jenv, 1562 "size mismatch: record %d, buckets %d", size, 1563 (n * sizeof (uint64_t))); 1564 WRAP_EXCEPTION(jenv); 1565 return (NULL); 1566 } 1567 1568 jbuckets = (*jenv)->NewLongArray(jenv, n); 1569 if (!jbuckets) { 1570 return (NULL); /* exception pending */ 1571 } 1572 1573 if (n > 0) { 1574 (*jenv)->SetLongArrayRegion(jenv, jbuckets, 0, n, aggbuckets); 1575 /* check for ArrayIndexOutOfBounds */ 1576 if ((*jenv)->ExceptionCheck(jenv)) { 1577 WRAP_EXCEPTION(jenv); 1578 (*jenv)->DeleteLocalRef(jenv, jbuckets); 1579 return (NULL); 1580 } 1581 } 1582 1583 switch (act) { 1584 case DTRACEAGG_LQUANTIZE: 1585 /* Must pass 64-bit base and step or constructor gets junk. */ 1586 jdist = (*jenv)->NewObject(jenv, g_ldist_jc, g_ldistinit_jm, 1587 base, step, jbuckets); 1588 break; 1589 case DTRACEAGG_QUANTIZE: 1590 jdist = (*jenv)->NewObject(jenv, g_dist_jc, g_distinit_jm, 1591 jbuckets); 1592 break; 1593 case DTRACEAGG_LLQUANTIZE: 1594 jdist = (*jenv)->NewObject(jenv, g_lldist_jc, g_lldistinit_jm, 1595 value, jbuckets); 1596 break; 1597 } 1598 1599 (*jenv)->DeleteLocalRef(jenv, jbuckets); 1600 if (!jdist) { 1601 return (NULL); /* exception pending */ 1602 } 1603 1604 if (normal != 1) { 1605 (*jenv)->CallVoidMethod(jenv, jdist, g_dist_normal_jm, normal); 1606 if ((*jenv)->ExceptionCheck(jenv)) { 1607 WRAP_EXCEPTION(jenv); 1608 (*jenv)->DeleteLocalRef(jenv, jdist); 1609 return (NULL); 1610 } 1611 } 1612 return (jdist); 1613 } 1614 1615 static void 1616 dtj_attach_frames(dtj_java_consumer_t *jc, jobject stack, 1617 jobjectArray frames) 1618 { 1619 JNIEnv *jenv = jc->dtjj_jenv; 1620 1621 if ((*jenv)->IsInstanceOf(jenv, stack, g_stack_jc)) { 1622 (*jenv)->CallVoidMethod(jenv, stack, g_stackset_frames_jm, 1623 frames); 1624 } else if ((*jenv)->IsInstanceOf(jenv, stack, g_ustack_jc)) { 1625 (*jenv)->CallVoidMethod(jenv, stack, g_ustackset_frames_jm, 1626 frames); 1627 } 1628 } 1629 1630 static void 1631 dtj_attach_name(dtj_java_consumer_t *jc, jobject symbol, jstring s) 1632 { 1633 JNIEnv *jenv = jc->dtjj_jenv; 1634 1635 if ((*jenv)->IsInstanceOf(jenv, symbol, g_symbol_jc)) { 1636 (*jenv)->CallVoidMethod(jenv, symbol, g_symbolset_name_jm, s); 1637 } else if ((*jenv)->IsInstanceOf(jenv, symbol, g_usymbol_jc)) { 1638 (*jenv)->CallVoidMethod(jenv, symbol, g_usymbolset_name_jm, s); 1639 } 1640 } 1641 1642 /* 1643 * Note: It is not valid to look outside the current libdtrace record in the 1644 * given aggdata (except to get the aggregation ID from the first record). 1645 * 1646 * Return DTRACE_HANDLE_ABORT if java exception pending, otherwise 1647 * DTRACE_HANDLE_OK. 1648 */ 1649 static int 1650 dtj_agghandler(const dtrace_bufdata_t *bufdata, dtj_java_consumer_t *jc) 1651 { 1652 JNIEnv *jenv = jc->dtjj_jenv; 1653 1654 const dtrace_aggdata_t *aggdata = bufdata->dtbda_aggdata; 1655 const dtrace_aggdesc_t *aggdesc; 1656 const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc; 1657 const char *s = bufdata->dtbda_buffered; 1658 dtrace_actkind_t act = DTRACEACT_NONE; 1659 int64_t aggid; 1660 1661 jobject jobj = NULL; 1662 1663 if (aggdata == NULL) { 1664 /* Assert without crashing */ 1665 dtj_throw_illegal_state(jenv, "null aggdata"); 1666 WRAP_EXCEPTION(jenv); 1667 return (DTRACE_HANDLE_ABORT); 1668 } 1669 aggdesc = aggdata->dtada_desc; 1670 1671 /* 1672 * Get the aggregation ID from the first record. 1673 */ 1674 /* LINTED - alignment */ 1675 aggid = *((int64_t *)(aggdata->dtada_data + 1676 aggdesc->dtagd_rec[0].dtrd_offset)); 1677 if (aggid < 0) { 1678 /* Assert without crashing */ 1679 dtj_throw_illegal_argument(jenv, "negative aggregation ID"); 1680 WRAP_EXCEPTION(jenv); 1681 return (DTRACE_HANDLE_ABORT); 1682 } 1683 1684 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1685 /* Append buffered output if this is a printa() callback. */ 1686 jstring jstr = dtj_NewStringNative(jenv, s); 1687 if ((*jenv)->ExceptionCheck(jenv)) { 1688 WRAP_EXCEPTION(jenv); 1689 return (DTRACE_HANDLE_ABORT); 1690 } 1691 /* 1692 * StringBuilder append() returns a reference to the 1693 * StringBuilder; must not leak the returned reference. 1694 */ 1695 jobj = (*jenv)->CallObjectMethod(jenv, 1696 jc->dtjj_printa_buffer, g_buf_append_str_jm, jstr); 1697 (*jenv)->DeleteLocalRef(jenv, jstr); 1698 (*jenv)->DeleteLocalRef(jenv, jobj); 1699 if ((*jenv)->ExceptionCheck(jenv)) { 1700 WRAP_EXCEPTION(jenv); 1701 return (DTRACE_HANDLE_ABORT); 1702 } 1703 } else { 1704 /* 1705 * Test whether to include the aggregation if this is a 1706 * getAggregate() call. Optimization: perform the inclusion 1707 * test only when the aggregation has changed. 1708 */ 1709 if (aggid != jc->dtjj_consumer->dtjc_aggid) { 1710 jc->dtjj_consumer->dtjc_included = 1711 dtj_is_included(aggdata, jc); 1712 if ((*jenv)->ExceptionCheck(jenv)) { 1713 WRAP_EXCEPTION(jenv); 1714 return (DTRACE_HANDLE_ABORT); 1715 } 1716 } 1717 if (!jc->dtjj_consumer->dtjc_included) { 1718 return (DTRACE_HANDLE_OK); 1719 } 1720 } 1721 jc->dtjj_consumer->dtjc_aggid = aggid; 1722 1723 /* 1724 * Determine the expected number of tuple members. While it is not 1725 * technically valid to look outside the current record in the current 1726 * aggdata, this implementation does so without a known failure case. 1727 * Any method relying only on the current callback record makes riskier 1728 * assumptions and still does not cover every corner case (for example, 1729 * counting the records from index 1 up to and not including the index 1730 * of the current DTRACE_BUFDATA_AGGVAL record, which fails when a 1731 * format string specifies the value ahead of one or more tuple 1732 * elements). Knowing that the calculation of the expected tuple size 1733 * is technically invalid (because it looks outside the current record), 1734 * we make the calculation at the earliest opportunity, before anything 1735 * might happen to invalidate any part of the aggdata. It ought to be 1736 * safe in any case: dtrd_action and dtrd_size do not appear ever to be 1737 * overwritten, and dtrd_offset is not used outside the current record. 1738 * 1739 * It is possible (if the assumptions here ever prove untrue) that the 1740 * libdtrace buffered output handler may need to be enhanced to provide 1741 * the expected number of tuple members. 1742 */ 1743 if (jc->dtjj_consumer->dtjc_expected < 0) { 1744 int r; 1745 for (r = 1; r < aggdesc->dtagd_nrecs; ++r) { 1746 act = aggdesc->dtagd_rec[r].dtrd_action; 1747 if (DTRACEACT_ISAGG(act) || 1748 aggdesc->dtagd_rec[r].dtrd_size == 0) { 1749 break; 1750 } 1751 } 1752 jc->dtjj_consumer->dtjc_expected = r - 1; 1753 } 1754 1755 if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGKEY) { 1756 /* record value is a tuple member */ 1757 1758 if (jc->dtjj_tuple == NULL) { 1759 jc->dtjj_tuple = (*jenv)->NewObject(jenv, 1760 g_tuple_jc, g_tupleinit_jm); 1761 if (!jc->dtjj_tuple) { 1762 /* java exception pending */ 1763 return (DTRACE_HANDLE_ABORT); 1764 } 1765 } 1766 1767 act = rec->dtrd_action; 1768 1769 switch (act) { 1770 case DTRACEACT_STACK: 1771 case DTRACEACT_USTACK: 1772 case DTRACEACT_JSTACK: 1773 jobj = dtj_new_tuple_stack_record(aggdata, rec, s, jc); 1774 break; 1775 case DTRACEACT_USYM: 1776 case DTRACEACT_UADDR: 1777 case DTRACEACT_UMOD: 1778 case DTRACEACT_SYM: 1779 case DTRACEACT_MOD: 1780 jobj = dtj_new_tuple_symbol_record(aggdata, rec, s, jc); 1781 break; 1782 default: 1783 jobj = dtj_recdata(jc, rec->dtrd_size, 1784 (aggdata->dtada_data + rec->dtrd_offset)); 1785 } 1786 1787 if (!jobj) { 1788 /* java exception pending */ 1789 return (DTRACE_HANDLE_ABORT); 1790 } 1791 1792 (*jenv)->CallVoidMethod(jenv, jc->dtjj_tuple, 1793 g_tupleadd_jm, jobj); 1794 (*jenv)->DeleteLocalRef(jenv, jobj); 1795 if ((*jenv)->ExceptionCheck(jenv)) { 1796 WRAP_EXCEPTION(jenv); 1797 return (DTRACE_HANDLE_ABORT); 1798 } 1799 } else if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGVAL) { 1800 /* 1801 * Record value is that of an aggregating action. The printa() 1802 * format string may place the tuple ahead of the aggregation 1803 * value(s), so we can't be sure we have the tuple until we get 1804 * the AGGLAST flag indicating the last callback associated with 1805 * the current tuple. Save the aggregation value or values 1806 * (multiple values if more than one aggregation is passed to 1807 * printa()) until then. 1808 */ 1809 dtj_aggval_t *aggval; 1810 1811 jstring jvalue = NULL; 1812 1813 jvalue = dtj_new_aggval(jc, aggdata, rec); 1814 if (!jvalue) { 1815 /* java exception pending */ 1816 WRAP_EXCEPTION(jenv); 1817 return (DTRACE_HANDLE_ABORT); 1818 } 1819 aggval = dtj_aggval_create(jenv, jvalue, aggdesc->dtagd_name, 1820 aggid); 1821 if (!aggval) { 1822 /* OutOfMemoryError pending */ 1823 (*jenv)->DeleteLocalRef(jenv, jvalue); 1824 return (DTRACE_HANDLE_ABORT); 1825 } 1826 if (!dtj_list_add(jc->dtjj_aggval_list, aggval)) { 1827 /* deletes jvalue reference */ 1828 dtj_aggval_destroy(aggval, jenv); 1829 dtj_throw_out_of_memory(jenv, "Failed to add aggval"); 1830 return (DTRACE_HANDLE_ABORT); 1831 } 1832 } 1833 1834 if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGLAST) { 1835 /* No more values associated with the current tuple. */ 1836 1837 dtj_aggval_t *aggval; 1838 uu_list_walk_t *itr; 1839 int tuple_member_count; 1840 1841 jobject jrec = NULL; 1842 jstring jname = NULL; 1843 1844 if (jc->dtjj_consumer->dtjc_expected == 0) { 1845 /* 1846 * singleton aggregation declared in D with no square 1847 * brackets 1848 */ 1849 jc->dtjj_tuple = (*jenv)->GetStaticObjectField(jenv, 1850 g_tuple_jc, g_tuple_EMPTY_jsf); 1851 if (jc->dtjj_tuple == NULL) { 1852 dtj_throw_out_of_memory(jenv, 1853 "Failed to reference Tuple.EMPTY"); 1854 return (DTRACE_HANDLE_ABORT); 1855 } 1856 } 1857 1858 if (jc->dtjj_tuple == NULL) { 1859 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1860 g_pdatainvalidate_printa_jm); 1861 goto printa_output; 1862 } 1863 1864 tuple_member_count = (*jenv)->CallIntMethod(jenv, 1865 jc->dtjj_tuple, g_tuplesize_jm); 1866 if (tuple_member_count < 1867 jc->dtjj_consumer->dtjc_expected) { 1868 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1869 g_pdatainvalidate_printa_jm); 1870 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1871 jc->dtjj_tuple = NULL; 1872 goto printa_output; 1873 } 1874 1875 itr = uu_list_walk_start(jc->dtjj_aggval_list, 0); 1876 while ((aggval = uu_list_walk_next(itr)) != NULL) { 1877 /* 1878 * new AggregationRecord: Combine the aggregation value 1879 * with the saved tuple and add it to the current 1880 * Aggregate or PrintaRecord. 1881 */ 1882 jrec = (*jenv)->NewObject(jenv, g_aggrec_jc, 1883 g_aggrecinit_jm, jc->dtjj_tuple, 1884 aggval->dtja_value); 1885 (*jenv)->DeleteLocalRef(jenv, aggval->dtja_value); 1886 aggval->dtja_value = NULL; 1887 if (!jrec) { 1888 /* java exception pending */ 1889 WRAP_EXCEPTION(jenv); 1890 return (DTRACE_HANDLE_ABORT); 1891 } 1892 1893 /* aggregation name */ 1894 jname = (*jenv)->NewStringUTF(jenv, 1895 aggval->dtja_aggname); 1896 if (!jname) { 1897 /* OutOfMemoryError pending */ 1898 (*jenv)->DeleteLocalRef(jenv, jrec); 1899 return (DTRACE_HANDLE_ABORT); 1900 } 1901 1902 /* 1903 * If the printa() format string specifies the value of 1904 * the aggregating action multiple times, PrintaRecord 1905 * ignores the attempt to add the duplicate record. 1906 */ 1907 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1908 /* add to PrintaRecord */ 1909 (*jenv)->CallVoidMethod(jenv, 1910 jc->dtjj_probedata, 1911 g_pdataadd_aggrec_jm, 1912 jname, aggval->dtja_aggid, jrec); 1913 } else { 1914 /* add to Aggregate */ 1915 (*jenv)->CallVoidMethod(jenv, 1916 jc->dtjj_aggregate, g_aggaddrec_jm, 1917 jname, aggval->dtja_aggid, jrec); 1918 } 1919 1920 (*jenv)->DeleteLocalRef(jenv, jrec); 1921 (*jenv)->DeleteLocalRef(jenv, jname); 1922 if ((*jenv)->ExceptionCheck(jenv)) { 1923 WRAP_EXCEPTION(jenv); 1924 return (DTRACE_HANDLE_ABORT); 1925 } 1926 } 1927 uu_list_walk_end(itr); 1928 dtj_list_clear(jc->dtjj_aggval_list, dtj_aggval_destroy, 1929 jenv); 1930 1931 printa_output: 1932 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1933 /* 1934 * Get the formatted string associated with the current 1935 * tuple if this is a printa() callback. 1936 */ 1937 jstring jstr = (*jenv)->CallObjectMethod(jenv, 1938 jc->dtjj_printa_buffer, g_tostring_jm); 1939 if ((*jenv)->ExceptionCheck(jenv)) { 1940 WRAP_EXCEPTION(jenv); 1941 return (DTRACE_HANDLE_ABORT); 1942 } 1943 /* 1944 * Clear the StringBuilder: this does not throw 1945 * exceptions. Reuse the StringBuilder until the end of 1946 * the current probedata then dispose of it. 1947 */ 1948 (*jenv)->CallVoidMethod(jenv, jc->dtjj_printa_buffer, 1949 g_bufsetlen_jm, 0); 1950 /* Add formatted string to PrintaRecord */ 1951 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1952 g_pdataadd_printa_str_jm, jc->dtjj_tuple, jstr); 1953 (*jenv)->DeleteLocalRef(jenv, jstr); 1954 if ((*jenv)->ExceptionCheck(jenv)) { 1955 WRAP_EXCEPTION(jenv); 1956 return (DTRACE_HANDLE_ABORT); 1957 } 1958 } 1959 1960 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1961 jc->dtjj_tuple = NULL; 1962 jc->dtjj_consumer->dtjc_expected = -1; 1963 } 1964 1965 return (DTRACE_HANDLE_OK); 1966 } 1967 1968 /* 1969 * Return B_TRUE if the aggregation is included, B_FALSE otherwise. Only in the 1970 * latter case might there be an exception pending. 1971 */ 1972 static boolean_t 1973 dtj_is_included(const dtrace_aggdata_t *data, dtj_java_consumer_t *jc) 1974 { 1975 JNIEnv *jenv = jc->dtjj_jenv; 1976 1977 if (jc->dtjj_aggregate_spec) { 1978 jboolean included; 1979 jstring aggname = NULL; 1980 1981 const dtrace_aggdesc_t *aggdesc = data->dtada_desc; 1982 aggname = (*jenv)->NewStringUTF(jenv, aggdesc->dtagd_name); 1983 if (!aggname) { 1984 /* java exception pending */ 1985 return (B_FALSE); 1986 } 1987 1988 included = (*jenv)->CallBooleanMethod(jenv, 1989 jc->dtjj_aggregate_spec, g_aggspec_included_jm, 1990 aggname); 1991 (*jenv)->DeleteLocalRef(jenv, aggname); 1992 if ((*jenv)->ExceptionCheck(jenv)) { 1993 WRAP_EXCEPTION(jenv); 1994 return (B_FALSE); 1995 } 1996 1997 return (included); 1998 } 1999 2000 return (B_TRUE); 2001 } 2002 2003 /* 2004 * Return NULL if a java exception is pending, otherwise return a new 2005 * AggregationValue instance. 2006 */ 2007 static jobject 2008 dtj_new_aggval(dtj_java_consumer_t *jc, const dtrace_aggdata_t *data, 2009 const dtrace_recdesc_t *rec) 2010 { 2011 JNIEnv *jenv = jc->dtjj_jenv; 2012 2013 jobject jvalue = NULL; /* return value */ 2014 2015 dtrace_actkind_t act; 2016 uint64_t normal; 2017 caddr_t addr; 2018 int64_t value; 2019 2020 act = rec->dtrd_action; 2021 normal = data->dtada_normal; 2022 addr = data->dtada_data + rec->dtrd_offset; 2023 if (act == DTRACEAGG_AVG) { 2024 value = dtj_average(addr, normal); 2025 } else { 2026 /* LINTED - alignment */ 2027 value = (*((int64_t *)addr)) / normal; 2028 } 2029 2030 if ((act == DTRACEAGG_QUANTIZE) || (act == DTRACEAGG_LQUANTIZE) || 2031 (act == DTRACEAGG_LLQUANTIZE)) { 2032 jvalue = dtj_new_distribution(data, rec, jc); 2033 } else { 2034 switch (act) { 2035 case DTRACEAGG_COUNT: 2036 jvalue = (*jenv)->NewObject(jenv, g_aggcount_jc, 2037 g_aggcountinit_jm, value); 2038 break; 2039 case DTRACEAGG_SUM: 2040 jvalue = (*jenv)->NewObject(jenv, g_aggsum_jc, 2041 g_aggsuminit_jm, value); 2042 break; 2043 case DTRACEAGG_AVG: 2044 jvalue = (*jenv)->NewObject(jenv, g_aggavg_jc, 2045 g_aggavginit_jm, value, dtj_avg_total(addr, 2046 normal), dtj_avg_count(addr)); 2047 break; 2048 case DTRACEAGG_MIN: 2049 jvalue = (*jenv)->NewObject(jenv, g_aggmin_jc, 2050 g_aggmininit_jm, value); 2051 break; 2052 case DTRACEAGG_MAX: 2053 jvalue = (*jenv)->NewObject(jenv, g_aggmax_jc, 2054 g_aggmaxinit_jm, value); 2055 break; 2056 case DTRACEAGG_STDDEV: 2057 jvalue = dtj_stddev(jenv, addr, normal); 2058 break; 2059 default: 2060 jvalue = NULL; 2061 dtj_throw_illegal_argument(jenv, 2062 "unexpected aggregation action: %d", act); 2063 } 2064 } 2065 2066 return (jvalue); 2067 } 2068 2069 /* 2070 * Stops the given consumer if it is running. Throws DTraceException if 2071 * dtrace_stop() fails and no other exception is already pending. Clears and 2072 * rethrows any pending exception in order to grab the global lock safely. 2073 */ 2074 void 2075 dtj_stop(dtj_java_consumer_t *jc) 2076 { 2077 JNIEnv *jenv; 2078 int rc; 2079 jthrowable e; 2080 2081 switch (jc->dtjj_consumer->dtjc_state) { 2082 case DTJ_CONSUMER_GO: 2083 case DTJ_CONSUMER_START: 2084 break; 2085 default: 2086 return; 2087 } 2088 2089 jenv = jc->dtjj_jenv; 2090 e = (*jenv)->ExceptionOccurred(jenv); 2091 if (e) { 2092 (*jenv)->ExceptionClear(jenv); 2093 } 2094 2095 (*jenv)->MonitorEnter(jenv, g_caller_jc); 2096 if ((*jenv)->ExceptionCheck(jenv)) { 2097 goto rethrow; 2098 } 2099 2100 rc = dtrace_status(jc->dtjj_consumer->dtjc_dtp); 2101 if (rc != DTRACE_STATUS_STOPPED) { 2102 rc = dtrace_stop(jc->dtjj_consumer->dtjc_dtp); 2103 } 2104 2105 (*jenv)->MonitorExit(jenv, g_caller_jc); 2106 if ((*jenv)->ExceptionCheck(jenv)) { 2107 goto rethrow; 2108 } 2109 2110 if (rc == -1) { 2111 (*jenv)->MonitorEnter(jenv, g_caller_jc); 2112 if ((*jenv)->ExceptionCheck(jenv)) { 2113 goto rethrow; 2114 } 2115 /* Do not wrap DTraceException */ 2116 dtj_throw_dtrace_exception(jc, 2117 "couldn't stop tracing: %s", 2118 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2119 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2120 /* safe to call with pending exception */ 2121 (*jenv)->MonitorExit(jenv, g_caller_jc); 2122 } else { 2123 jc->dtjj_consumer->dtjc_state = DTJ_CONSUMER_STOP; 2124 } 2125 2126 rethrow: 2127 if (e) { 2128 if ((*jenv)->ExceptionCheck(jenv)) { 2129 /* 2130 * Favor earlier pending exception over 2131 * exception thrown in this function. 2132 */ 2133 (*jenv)->ExceptionClear(jenv); 2134 } 2135 (*jenv)->Throw(jenv, e); 2136 (*jenv)->DeleteLocalRef(jenv, e); 2137 } 2138 } 2139 2140 /* 2141 * Return Aggregate instance, or null if java exception pending. 2142 */ 2143 jobject 2144 dtj_get_aggregate(dtj_java_consumer_t *jc) 2145 { 2146 JNIEnv *jenv = jc->dtjj_jenv; 2147 hrtime_t snaptime; 2148 int rc; 2149 2150 jobject aggregate = NULL; 2151 2152 /* Must not call MonitorEnter with a pending exception */ 2153 if ((*jenv)->ExceptionCheck(jenv)) { 2154 WRAP_EXCEPTION(jenv); 2155 return (NULL); 2156 } 2157 2158 /* 2159 * Aggregations must be snapped, walked, and cleared atomically, 2160 * otherwise clearing loses data accumulated since the most recent snap. 2161 * This per-consumer lock prevents dtrace_work() from snapping or 2162 * clearing aggregations while we're in the middle of this atomic 2163 * operation, so we continue to hold it until done clearing. 2164 */ 2165 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2166 if ((*jenv)->ExceptionCheck(jenv)) { 2167 WRAP_EXCEPTION(jenv); 2168 return (NULL); 2169 } 2170 2171 dtj_aggwalk_init(jc); 2172 if ((*jenv)->ExceptionCheck(jenv)) { 2173 WRAP_EXCEPTION(jenv); 2174 /* release per-consumer lock */ 2175 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2176 return (NULL); 2177 } 2178 2179 /* 2180 * Snap aggregations 2181 * 2182 * We need to record the snaptime here for the caller. Leaving it to 2183 * the caller to record the snaptime before calling getAggregate() may 2184 * be inaccurate because of the indeterminate delay waiting on the 2185 * consumer lock before calling dtrace_aggregate_snap(). 2186 */ 2187 snaptime = gethrtime(); 2188 if (dtrace_aggregate_snap(jc->dtjj_consumer->dtjc_dtp) != 0) { 2189 dtj_error_t e; 2190 2191 /* 2192 * The dataDropped() ConsumerListener method can throw an 2193 * exception in the getAggregate() thread if the drop handler is 2194 * invoked during dtrace_aggregate_snap(). 2195 */ 2196 if ((*jenv)->ExceptionCheck(jenv)) { 2197 /* Do not wrap exception thrown from ConsumerListener */ 2198 /* release per-consumer lock */ 2199 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2200 return (NULL); 2201 } 2202 2203 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2204 /* Do not wrap DTraceException */ 2205 dtj_throw_dtrace_exception(jc, e.dtje_message); 2206 } 2207 /* release per-consumer lock */ 2208 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2209 return (NULL); 2210 } 2211 2212 if ((*jenv)->ExceptionCheck(jenv)) { 2213 /* 2214 * Wrap the exception thrown from ConsumerListener in this case, 2215 * so we can see that it unexpectedly reached this spot in 2216 * native code (dtrace_aggregate_snap should have returned 2217 * non-zero). 2218 */ 2219 WRAP_EXCEPTION(jenv); 2220 /* release per-consumer lock */ 2221 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2222 return (NULL); 2223 } 2224 2225 /* Create the Java representation of the aggregate snapshot. */ 2226 aggregate = (*jenv)->NewObject(jenv, g_agg_jc, g_agginit_jm, 2227 snaptime); 2228 if ((*jenv)->ExceptionCheck(jenv)) { 2229 WRAP_EXCEPTION(jenv); 2230 /* release per-consumer lock */ 2231 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2232 return (NULL); 2233 } 2234 jc->dtjj_aggregate = aggregate; 2235 2236 /* 2237 * Walk the aggregate, converting the data into Java Objects. Traverse 2238 * in the order determined by libdtrace, respecting the various 2239 * "aggsort" options, just as dtrace_work does when generating 2240 * aggregations for the printa() action. libdtrace ordering is preserved 2241 * in the "ordinal" property of AggregationRecord, since it would 2242 * otherwise be lost when the records are hashed into the Aggregation's 2243 * map. Neither the consumer loop nor the competing getAggregate() 2244 * thread should depend on any particular record ordering (such as 2245 * ordering by tuple key) to process records correctly. 2246 * 2247 * It is impractical to hold the global lock around 2248 * dtrace_aggregate_print(), since it may take a long time (e.g. an 2249 * entire second) if it performs expensive conversions such as that 2250 * needed for user stack traces. Most libdtrace functions are not 2251 * guaranteed to be MT-safe, even when each thread has its own dtrace 2252 * handle; or even if they are safe, there is no guarantee that future 2253 * changes may not make them unsafe. Fortunately in this case, however, 2254 * only a per-consumer lock is necessary to avoid conflict with 2255 * dtrace_work() running in another thread (the consumer loop). 2256 */ 2257 rc = dtrace_aggregate_print(jc->dtjj_consumer->dtjc_dtp, NULL, NULL); 2258 if ((*jenv)->ExceptionCheck(jenv)) { 2259 WRAP_EXCEPTION(jenv); 2260 /* release per-consumer lock */ 2261 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2262 return (NULL); 2263 } 2264 if (rc != 0) { 2265 dtj_error_t e; 2266 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2267 /* release per-consumer lock */ 2268 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2269 return (NULL); 2270 } 2271 2272 if (e.dtje_number != EINTR) { 2273 /* Do not wrap DTraceException */ 2274 dtj_throw_dtrace_exception(jc, e.dtje_message); 2275 /* release per-consumer lock */ 2276 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2277 return (NULL); 2278 } 2279 } 2280 2281 dtj_aggwalk_init(jc); 2282 if ((*jenv)->ExceptionCheck(jenv)) { 2283 WRAP_EXCEPTION(jenv); 2284 /* release per-consumer lock */ 2285 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2286 return (NULL); 2287 } 2288 2289 /* 2290 * dtrace_aggregate_clear() clears all aggregations, and we need to 2291 * clear aggregations selectively. It also fails to preserve the 2292 * lquantize() range and step size; using aggregate_walk() to clear 2293 * aggregations does not have this problem. 2294 */ 2295 rc = dtrace_aggregate_walk(jc->dtjj_consumer->dtjc_dtp, dtj_clear, jc); 2296 if ((*jenv)->ExceptionCheck(jenv)) { 2297 WRAP_EXCEPTION(jenv); 2298 /* release per-consumer lock */ 2299 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2300 return (NULL); 2301 } 2302 if (rc != 0) { 2303 dtj_error_t e; 2304 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2305 /* Do not wrap DTraceException */ 2306 dtj_throw_dtrace_exception(jc, e.dtje_message); 2307 } 2308 /* release per-consumer lock */ 2309 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2310 return (NULL); 2311 } 2312 2313 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2314 if ((*jenv)->ExceptionCheck(jenv)) { 2315 WRAP_EXCEPTION(jenv); 2316 return (NULL); 2317 } 2318 2319 aggregate = jc->dtjj_aggregate; 2320 jc->dtjj_aggregate = NULL; 2321 2322 return (aggregate); 2323 } 2324 2325 /* 2326 * Process any requests, such as the setting of runtime options, enqueued during 2327 * dtrace_sleep(). A Java exception is pending if this function returns 2328 * DTJ_ERR. 2329 */ 2330 static dtj_status_t 2331 dtj_process_requests(dtj_java_consumer_t *jc) 2332 { 2333 dtj_request_t *r; 2334 uu_list_t *list = jc->dtjj_consumer->dtjc_request_list; 2335 pthread_mutex_t *list_lock = &jc->dtjj_consumer-> 2336 dtjc_request_list_lock; 2337 const char *opt; 2338 const char *val; 2339 2340 (void) pthread_mutex_lock(list_lock); 2341 while (!dtj_list_empty(list)) { 2342 r = uu_list_first(list); 2343 uu_list_remove(list, r); 2344 2345 switch (r->dtjr_type) { 2346 case DTJ_REQUEST_OPTION: 2347 opt = dtj_string_list_first(r->dtjr_args); 2348 val = dtj_string_list_last(r->dtjr_args); 2349 if (dtrace_setopt(jc->dtjj_consumer->dtjc_dtp, opt, 2350 val) == -1) { 2351 /* Do not wrap DTraceException */ 2352 dtj_throw_dtrace_exception(jc, 2353 "failed to set %s: %s", opt, 2354 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2355 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2356 dtj_request_destroy(r, NULL); 2357 (void) pthread_mutex_unlock(list_lock); 2358 return (DTJ_ERR); 2359 } 2360 break; 2361 } 2362 dtj_request_destroy(r, NULL); 2363 } 2364 (void) pthread_mutex_unlock(list_lock); 2365 return (DTJ_OK); 2366 } 2367 2368 /* 2369 * Return DTJ_OK if the consumer loop is stopped normally by either the exit() 2370 * action or the Consumer stop() method. Otherwise return DTJ_ERR if the 2371 * consumer loop terminates abnormally with an exception pending. 2372 */ 2373 dtj_status_t 2374 dtj_consume(dtj_java_consumer_t *jc) 2375 { 2376 JNIEnv *jenv = jc->dtjj_jenv; 2377 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 2378 boolean_t done = B_FALSE; 2379 dtj_error_t e; 2380 2381 do { 2382 if (!jc->dtjj_consumer->dtjc_interrupt) { 2383 dtrace_sleep(dtp); 2384 } 2385 2386 if (jc->dtjj_consumer->dtjc_interrupt) { 2387 done = B_TRUE; 2388 dtj_stop(jc); 2389 if ((*jenv)->ExceptionCheck(jenv)) { 2390 /* 2391 * Exception left pending by Consumer 2392 * getAggregate() method. 2393 */ 2394 return (DTJ_ERR); 2395 } 2396 } else if (jc->dtjj_consumer->dtjc_process_list != NULL) { 2397 int nprocs = uu_list_numnodes(jc->dtjj_consumer-> 2398 dtjc_process_list); 2399 if (jc->dtjj_consumer->dtjc_procs_ended == nprocs) { 2400 done = B_TRUE; 2401 dtj_stop(jc); 2402 } 2403 } 2404 2405 /* 2406 * Functions like dtrace_setopt() are not safe to call during 2407 * dtrace_sleep(). Check the request list every time we wake up 2408 * from dtrace_sleep(). 2409 */ 2410 if (!done) { 2411 if (dtj_process_requests(jc) != DTJ_OK) { 2412 /* Do not wrap DTraceException */ 2413 return (DTJ_ERR); 2414 } 2415 } 2416 2417 /* Must not call MonitorEnter with a pending exception */ 2418 if ((*jenv)->ExceptionCheck(jenv)) { 2419 WRAP_EXCEPTION(jenv); 2420 return (DTJ_ERR); 2421 } 2422 2423 /* 2424 * Use the per-consumer lock to avoid conflict with 2425 * get_aggregate() called from another thread. 2426 */ 2427 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2428 if ((*jenv)->ExceptionCheck(jenv)) { 2429 WRAP_EXCEPTION(jenv); 2430 return (DTJ_ERR); 2431 } 2432 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2433 g_interval_began_jm); 2434 if ((*jenv)->ExceptionCheck(jenv)) { 2435 /* Don't wrap exception thrown from ConsumerListener */ 2436 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2437 return (DTJ_ERR); 2438 } 2439 jc->dtjj_consumer->dtjc_printa_snaptime = gethrtime(); 2440 switch (dtrace_work(dtp, NULL, dtj_chew, dtj_chewrec, jc)) { 2441 case DTRACE_WORKSTATUS_DONE: 2442 done = B_TRUE; 2443 break; 2444 case DTRACE_WORKSTATUS_OKAY: 2445 break; 2446 default: 2447 /* 2448 * Check for a pending exception that got us to this 2449 * error workstatus case. 2450 */ 2451 if ((*jenv)->ExceptionCheck(jenv)) { 2452 /* 2453 * Ensure valid initial state before releasing 2454 * the consumer lock 2455 */ 2456 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2457 /* Do not wrap DTraceException */ 2458 /* Release per-consumer lock */ 2459 (*jenv)->MonitorExit(jenv, 2460 jc->dtjj_consumer_lock); 2461 return (DTJ_ERR); 2462 } 2463 2464 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2465 /* java exception pending */ 2466 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2467 /* Release per-consumer lock */ 2468 (*jenv)->MonitorExit(jenv, 2469 jc->dtjj_consumer_lock); 2470 return (DTJ_ERR); 2471 } 2472 2473 if (e.dtje_number != EINTR) { 2474 /* Do not wrap DTraceException */ 2475 dtj_throw_dtrace_exception(jc, e.dtje_message); 2476 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2477 /* Release per-consumer lock */ 2478 (*jenv)->MonitorExit(jenv, 2479 jc->dtjj_consumer_lock); 2480 return (DTJ_ERR); 2481 } 2482 } 2483 /* 2484 * Check for ConsumerException before doing anything else with 2485 * the JNIEnv. 2486 */ 2487 if ((*jenv)->ExceptionCheck(jenv)) { 2488 /* 2489 * Do not wrap exception thrown from ConsumerListener. 2490 */ 2491 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2492 /* Release per-consumer lock */ 2493 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2494 return (DTJ_ERR); 2495 } 2496 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2497 /* 2498 * Notify ConsumerListeners the the dtrace_work() interval ended 2499 * before releasing the lock. 2500 */ 2501 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2502 g_interval_ended_jm); 2503 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2504 if ((*jenv)->ExceptionCheck(jenv)) { 2505 /* Don't wrap exception thrown from ConsumerListener */ 2506 return (DTJ_ERR); 2507 } 2508 2509 /* 2510 * Check for a temporarily cleared exception set by a handler 2511 * that could not safely leave the exception pending because it 2512 * could not return an abort signal. Rethrow it now that it's 2513 * safe to do so (when it's possible to ensure that no JNI calls 2514 * will be made that are unsafe while an exception is pending). 2515 */ 2516 if (jc->dtjj_exception) { 2517 (*jenv)->Throw(jenv, jc->dtjj_exception); 2518 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_exception); 2519 jc->dtjj_exception = NULL; 2520 return (DTJ_ERR); 2521 } 2522 } while (!done); 2523 2524 return (DTJ_OK); 2525 } 2526