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 if (rec->dtrd_size == 0) { 735 /* 736 * The current record is not a D action, but a program 737 * statement such as a variable assignment, not to be 738 * confused with the trace() action. 739 */ 740 break; 741 } 742 /* 743 * Add a Record for the trace() action that references the 744 * native probedata element listed at the current index. 745 */ 746 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 747 g_pdataadd_trace_jm, 748 jc->dtjj_consumer->dtjc_probedata_rec_i); 749 if ((*jenv)->ExceptionCheck(jenv)) { 750 WRAP_EXCEPTION(jenv); 751 return (DTRACE_CONSUME_ABORT); 752 } 753 break; 754 case DTRACEACT_PRINTF: 755 /* 756 * Just add an empty PrintfRecord for now. We'll attach the 757 * unformatted elements in a subsequent call to this function. 758 * (We don't know how many there will be.) 759 */ 760 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 761 g_pdataadd_printf_jm); 762 if ((*jenv)->ExceptionCheck(jenv)) { 763 WRAP_EXCEPTION(jenv); 764 return (DTRACE_CONSUME_ABORT); 765 } 766 /* defer formatted string to dtj_bufhandler() */ 767 break; 768 case DTRACEACT_PRINTA: { 769 jobject jbuf = NULL; 770 771 dtj_aggwalk_init(jc); 772 if ((*jenv)->ExceptionCheck(jenv)) { 773 WRAP_EXCEPTION(jenv); 774 return (DTRACE_CONSUME_ABORT); 775 } 776 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 777 g_pdataadd_printa_jm, 778 jc->dtjj_consumer->dtjc_printa_snaptime, 779 (rec->dtrd_format != 0)); 780 if ((*jenv)->ExceptionCheck(jenv)) { 781 WRAP_EXCEPTION(jenv); 782 return (DTRACE_CONSUME_ABORT); 783 } 784 if (jc->dtjj_printa_buffer == NULL) { 785 /* 786 * Create a StringBuilder to collect the pieces of 787 * formatted output into a single String. 788 */ 789 jbuf = (*jenv)->NewObject(jenv, g_buf_jc, 790 g_bufinit_jm); 791 if (!jbuf) { 792 /* OutOfMemoryError pending */ 793 return (DTRACE_CONSUME_ABORT); 794 } 795 jc->dtjj_printa_buffer = jbuf; 796 } 797 /* defer aggregation records to dtj_bufhandler() */ 798 break; 799 } 800 case DTRACEACT_EXIT: 801 /* 802 * Add a Record for the exit() action that references the native 803 * probedata element listed at the current index. 804 */ 805 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 806 g_pdataadd_exit_jm, 807 jc->dtjj_consumer->dtjc_probedata_rec_i); 808 if ((*jenv)->ExceptionCheck(jenv)) { 809 WRAP_EXCEPTION(jenv); 810 return (DTRACE_CONSUME_ABORT); 811 } 812 return (DTRACE_CONSUME_NEXT); 813 } 814 815 return (DTRACE_CONSUME_THIS); 816 } 817 818 /* 819 * This is the probe handling function passed to dtrace_work(). It is is called 820 * once every time a probe fires. It is the first of all the callbacks for the 821 * current probe. It is followed by multiple callbacks to dtj_chewrec(), one 822 * for each probedata record. Each call to dtj_chewrec() is followed by zero or 823 * more callbacks to the bufhandler, one for each output-producing action or 824 * aggregation record. 825 */ 826 static int 827 dtj_chew(const dtrace_probedata_t *data, void *arg) 828 { 829 dtj_java_consumer_t *jc = arg; 830 JNIEnv *jenv = jc->dtjj_jenv; 831 832 dtrace_eprobedesc_t *edesc; 833 dtrace_probedesc_t *pdesc; 834 dtrace_recdesc_t *rec; 835 int epid; 836 int cpu; 837 int nrecs; 838 int i; 839 840 jobject jpdata = NULL; 841 jobject jprobe = NULL; 842 jobject jflow = NULL; 843 jstring jflowkind = NULL; 844 jobject jobj = NULL; 845 846 edesc = data->dtpda_edesc; 847 epid = (int)edesc->dtepd_epid; 848 pdesc = data->dtpda_pdesc; 849 cpu = (int)data->dtpda_cpu; 850 if ((jprobe = dtj_new_probedesc(jc, pdesc)) == NULL) { 851 /* java exception pending */ 852 return (DTRACE_CONSUME_ABORT); 853 } 854 nrecs = edesc->dtepd_nrecs; 855 856 if (jc->dtjj_consumer->dtjc_flow) { 857 const char *kind; 858 switch (data->dtpda_flow) { 859 case DTRACEFLOW_ENTRY: 860 kind = "ENTRY"; 861 break; 862 case DTRACEFLOW_RETURN: 863 kind = "RETURN"; 864 break; 865 case DTRACEFLOW_NONE: 866 kind = "NONE"; 867 break; 868 default: 869 kind = NULL; 870 } 871 if (kind != NULL) { 872 int depth; 873 jflowkind = (*jenv)->NewStringUTF(jenv, kind); 874 if ((*jenv)->ExceptionCheck(jenv)) { 875 WRAP_EXCEPTION(jenv); 876 (*jenv)->DeleteLocalRef(jenv, jprobe); 877 return (DTRACE_CONSUME_ABORT); 878 } 879 /* 880 * Use the knowledge that libdtrace indents 2 spaces per 881 * level in the call stack to calculate the depth. 882 */ 883 depth = (data->dtpda_indent / 2); 884 jflow = (*jenv)->NewObject(jenv, g_flow_jc, 885 g_flowinit_jm, jflowkind, depth); 886 (*jenv)->DeleteLocalRef(jenv, jflowkind); 887 if ((*jenv)->ExceptionCheck(jenv)) { 888 WRAP_EXCEPTION(jenv); 889 (*jenv)->DeleteLocalRef(jenv, jprobe); 890 return (DTRACE_CONSUME_ABORT); 891 } 892 } 893 } 894 895 /* Create ProbeData instance */ 896 jpdata = (*jenv)->NewObject(jenv, g_pdata_jc, g_pdatainit_jm, 897 epid, cpu, jprobe, jflow, nrecs); 898 (*jenv)->DeleteLocalRef(jenv, jprobe); 899 (*jenv)->DeleteLocalRef(jenv, jflow); 900 if ((*jenv)->ExceptionCheck(jenv)) { 901 WRAP_EXCEPTION(jenv); 902 return (DTRACE_CONSUME_ABORT); 903 } 904 905 /* 906 * Populate the ProbeData list of Java data elements in advance so we 907 * don't need to peek back in the record handler at libdtrace records 908 * that have already been consumed. In the Java API, each ProbeData 909 * Record is generated by one D action, while in the native libdtrace 910 * there may be more than one probedata record (each a single data 911 * element) per D action. For example PrintfRecord has multiple 912 * unformatted elements, each represented by a native probedata record, 913 * but combined by the API into a single PrintfRecord. 914 */ 915 for (i = 0; i < nrecs; ++i) { 916 rec = &edesc->dtepd_rec[i]; 917 /* 918 * A statement that is not a D action, such as assignment to a 919 * variable, has no size. Add a NULL placeholder to the scratch 920 * list of Java probedata elements in that case. 921 */ 922 jobj = NULL; /* initialize object reference to null */ 923 if (rec->dtrd_size > 0) { 924 if (dtj_is_stack_action(rec->dtrd_action)) { 925 jobj = dtj_new_probedata_stack_record(data, 926 rec, jc); 927 } else if (dtj_is_symbol_action(rec->dtrd_action)) { 928 jobj = dtj_new_probedata_symbol_record(data, 929 rec, jc); 930 } else { 931 jobj = dtj_recdata(jc, rec->dtrd_size, 932 (data->dtpda_data + rec->dtrd_offset)); 933 } 934 if ((*jenv)->ExceptionCheck(jenv)) { 935 WRAP_EXCEPTION(jenv); 936 (*jenv)->DeleteLocalRef(jenv, jpdata); 937 return (DTRACE_CONSUME_ABORT); 938 } 939 } 940 941 (*jenv)->CallVoidMethod(jenv, jpdata, g_pdataadd_jm, jobj); 942 (*jenv)->DeleteLocalRef(jenv, jobj); 943 if ((*jenv)->ExceptionCheck(jenv)) { 944 WRAP_EXCEPTION(jenv); 945 (*jenv)->DeleteLocalRef(jenv, jpdata); 946 return (DTRACE_CONSUME_ABORT); 947 } 948 } 949 950 if (jc->dtjj_probedata != NULL) { 951 dtj_throw_illegal_state(jenv, "unfinished probedata"); 952 WRAP_EXCEPTION(jenv); 953 (*jenv)->DeleteLocalRef(jenv, jpdata); 954 return (DTRACE_CONSUME_ABORT); 955 } 956 jc->dtjj_probedata = jpdata; 957 958 /* Initialize per-consumer probedata fields */ 959 jc->dtjj_consumer->dtjc_probedata_rec_i = 0; 960 jc->dtjj_consumer->dtjc_probedata_act = DTRACEACT_NONE; 961 dtj_aggwalk_init(jc); 962 if ((*jenv)->ExceptionCheck(jenv)) { 963 WRAP_EXCEPTION(jenv); 964 return (DTRACE_CONSUME_ABORT); 965 } 966 967 return (DTRACE_CONSUME_THIS); 968 } 969 970 /* 971 * This is the buffered output handler registered with dtrace_handle_buffered(). 972 * It's purpose is to make the output of the libdtrace print routines available 973 * to this API, without writing any of it to a file (such as stdout). This is 974 * needed for the stack(), ustack(), and jstack() actions to get human-readable 975 * stack values, since there is no public function in libdtrace to convert stack 976 * values to strings. It is also used to get the formatted output of the D 977 * printf() and printa() actions. 978 * 979 * The bufhandler is called once for each output-producing, non-aggregating D 980 * action, such as trace() or printf(), and once for each libdtrace aggregation 981 * record (whether in response to the D printa() action, or the Consumer 982 * getAggregate() method). In the simple printa() case that takes one 983 * aggregation and does not specify a format string, there is one libdtrace 984 * record per tuple element plus one for the corresponding value. The complete 985 * tuple/value pair becomes a single AggregationRecord exported by the API. 986 * When multiple aggregations are passed to printa(), each tuple is associated 987 * with a list of values, one from each aggregation. If a printa() format 988 * string does not specify placeholders for every aggregation value and tuple 989 * member, callbacks for those values and tuple members are omitted (and the 990 * data is omitted from the resulting PrintaRecord). 991 * 992 * Notes to characterize some non-obvious bufhandler behavior: 993 * 994 * 1. dtj_bufhandler() is never called with bufdata->dtbda_recdesc->dtrd_action 995 * DTRACEACT_PRINTA. That action only appears in the probedata consumer 996 * functions dtj_chew() and dtj_chewrec() before the bufhandler is called with 997 * subsequent aggregation records. 998 * 999 * 2. If printa() specifies a format string argument, then the bufhandler is 1000 * called only for those elements of the tuple/value pair that are included in 1001 * the format string. If a stack() tuple member is omitted from the format 1002 * string, its human-readable representation will not be available to this API, 1003 * so the stack frame array is also omitted from the resulting 1004 * AggregationRecord. The bufhandler is also called once for each string of 1005 * characters surrounding printa() format string placeholders. For example, 1006 * " %@d %d stack%k\n" results in the following callbacks: 1007 * - two spaces 1008 * - the aggregation value 1009 * - a single space 1010 * - the first tuple member (an integer) 1011 * - " stack" 1012 * - the second tuple member (a stack) 1013 * - a newline 1014 * A NULL record (NULL dtbda_recdesc) distinguishes a callback with interstitial 1015 * format string characters from a callback with a tuple member or aggregation 1016 * value (which has a non-NULL recdesc). The contents are also distinguished by 1017 * the following flags: 1018 * DTRACE_BUFDATA_AGGKEY 1019 * DTRACE_BUFDATA_AGGVAL 1020 * DTRACE_BUFDATA_AGGFORMAT 1021 * DTRACE_BUFDATA_AGGLAST 1022 * 1023 * There is no final callback with the complete formatted string, so that must 1024 * be concatenated across multiple callbacks to the bufhandler. 1025 * 1026 * 3. bufdata->dtbda_probe->dtpda_data may be overwritten by libdtrace print 1027 * routines. The address is cached in the dtj_chew() function in case it is 1028 * needed in the bufhandler. 1029 */ 1030 static int 1031 /* ARGSUSED */ 1032 dtj_bufhandler(const dtrace_bufdata_t *bufdata, void *arg) 1033 { 1034 dtj_java_consumer_t *jc; 1035 JNIEnv *jenv; 1036 const dtrace_recdesc_t *rec; 1037 dtrace_actkind_t act = DTRACEACT_NONE; 1038 const char *s; 1039 1040 jobject jstr = NULL; 1041 1042 /* 1043 * Get the thread-specific java consumer. The bufhandler needs access 1044 * to the correct JNI state specific to either the consumer loop or the 1045 * getAggregate() call (aggregation snapshots can be requested 1046 * asynchronously while the consumer loop generates PrintaRecords in 1047 * dtrace_work() for ConsumerListeners). 1048 */ 1049 jc = pthread_getspecific(g_dtj_consumer_key); 1050 jenv = jc->dtjj_jenv; 1051 1052 /* 1053 * In at least one corner case (printa with multiple aggregations and a 1054 * format string that does not completely specify the tuple), returning 1055 * DTRACE_HANDLE_ABORT does not prevent a subsequent callback to this 1056 * bufhandler. This check ensures that the invalid call is ignored. 1057 */ 1058 if ((*jenv)->ExceptionCheck(jenv)) { 1059 return (DTRACE_HANDLE_ABORT); 1060 } 1061 1062 if (bufdata->dtbda_aggdata) { 1063 return (dtj_agghandler(bufdata, jc)); 1064 } 1065 1066 s = bufdata->dtbda_buffered; 1067 if (s == NULL) { 1068 return (DTRACE_HANDLE_OK); 1069 } 1070 1071 rec = bufdata->dtbda_recdesc; 1072 if (rec) { 1073 act = rec->dtrd_action; 1074 } 1075 1076 switch (act) { 1077 case DTRACEACT_DIFEXPR: 1078 /* trace() action */ 1079 break; 1080 case DTRACEACT_PRINTF: 1081 /* 1082 * Only the formatted string was not available to dtj_chewrec(), 1083 * so we attach that now. 1084 */ 1085 jstr = dtj_NewStringNative(jenv, s); 1086 if ((*jenv)->ExceptionCheck(jenv)) { 1087 WRAP_EXCEPTION(jenv); 1088 return (DTRACE_HANDLE_ABORT); 1089 } 1090 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1091 g_pdataset_formatted_jm, jstr); 1092 (*jenv)->DeleteLocalRef(jenv, jstr); 1093 if ((*jenv)->ExceptionCheck(jenv)) { 1094 WRAP_EXCEPTION(jenv); 1095 return (DTRACE_HANDLE_ABORT); 1096 } 1097 break; 1098 case DTRACEACT_STACK: 1099 case DTRACEACT_USTACK: 1100 case DTRACEACT_JSTACK: 1101 /* stand-alone stack(), ustack(), or jstack() action */ 1102 jstr = (*jenv)->NewStringUTF(jenv, s); 1103 if (!jstr) { 1104 /* OutOfMemoryError pending */ 1105 return (DTRACE_HANDLE_ABORT); 1106 } 1107 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1108 g_pdataadd_stack_jm, 1109 jc->dtjj_consumer->dtjc_probedata_rec_i, jstr); 1110 (*jenv)->DeleteLocalRef(jenv, jstr); 1111 if ((*jenv)->ExceptionCheck(jenv)) { 1112 WRAP_EXCEPTION(jenv); 1113 return (DTRACE_HANDLE_ABORT); 1114 } 1115 break; 1116 case DTRACEACT_USYM: 1117 case DTRACEACT_UADDR: 1118 case DTRACEACT_UMOD: 1119 case DTRACEACT_SYM: 1120 case DTRACEACT_MOD: 1121 /* stand-alone symbol lookup action */ 1122 jstr = (*jenv)->NewStringUTF(jenv, s); 1123 if (!jstr) { 1124 /* OutOfMemoryError pending */ 1125 return (DTRACE_HANDLE_ABORT); 1126 } 1127 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1128 g_pdataadd_symbol_jm, 1129 jc->dtjj_consumer->dtjc_probedata_rec_i, jstr); 1130 (*jenv)->DeleteLocalRef(jenv, jstr); 1131 if ((*jenv)->ExceptionCheck(jenv)) { 1132 WRAP_EXCEPTION(jenv); 1133 return (DTRACE_HANDLE_ABORT); 1134 } 1135 break; 1136 default: 1137 /* 1138 * The record handler dtj_chewrec() defers nothing else to this 1139 * bufhandler. 1140 */ 1141 break; 1142 } 1143 1144 return (DTRACE_HANDLE_OK); 1145 } 1146 1147 static boolean_t 1148 dtj_is_stack_action(dtrace_actkind_t act) 1149 { 1150 boolean_t stack_action; 1151 switch (act) { 1152 case DTRACEACT_STACK: 1153 case DTRACEACT_USTACK: 1154 case DTRACEACT_JSTACK: 1155 stack_action = B_TRUE; 1156 break; 1157 default: 1158 stack_action = B_FALSE; 1159 } 1160 return (stack_action); 1161 } 1162 1163 static boolean_t 1164 dtj_is_symbol_action(dtrace_actkind_t act) 1165 { 1166 boolean_t symbol_action; 1167 switch (act) { 1168 case DTRACEACT_USYM: 1169 case DTRACEACT_UADDR: 1170 case DTRACEACT_UMOD: 1171 case DTRACEACT_SYM: 1172 case DTRACEACT_MOD: 1173 symbol_action = B_TRUE; 1174 break; 1175 default: 1176 symbol_action = B_FALSE; 1177 } 1178 return (symbol_action); 1179 } 1180 1181 /* 1182 * Called by get_aggregate() to clear only those aggregations specified by the 1183 * caller. 1184 */ 1185 static int 1186 dtj_clear(const dtrace_aggdata_t *data, void *arg) 1187 { 1188 dtj_java_consumer_t *jc = arg; 1189 jboolean cleared = JNI_FALSE; 1190 1191 jstring jname = NULL; 1192 1193 if (jc->dtjj_aggregate_spec) { 1194 JNIEnv *jenv = jc->dtjj_jenv; 1195 1196 dtrace_aggdesc_t *aggdesc = data->dtada_desc; 1197 1198 jname = (*jenv)->NewStringUTF(jenv, aggdesc->dtagd_name); 1199 if (!jname) { 1200 /* java exception pending */ 1201 return (DTRACE_AGGWALK_ABORT); 1202 } 1203 1204 cleared = (*jenv)->CallBooleanMethod(jenv, 1205 jc->dtjj_aggregate_spec, g_aggspec_cleared_jm, jname); 1206 (*jenv)->DeleteLocalRef(jenv, jname); 1207 if ((*jenv)->ExceptionCheck(jenv)) { 1208 WRAP_EXCEPTION(jenv); 1209 return (DTRACE_AGGWALK_ABORT); 1210 } 1211 } 1212 1213 return (cleared ? DTRACE_AGGWALK_CLEAR : DTRACE_AGGWALK_NEXT); 1214 } 1215 1216 static int64_t 1217 dtj_average(caddr_t addr, uint64_t normal) 1218 { 1219 /* LINTED - alignment */ 1220 int64_t *data = (int64_t *)addr; 1221 1222 return (data[0] ? 1223 (data[1] / (int64_t)normal / data[0]) : 0); 1224 } 1225 1226 static int64_t 1227 dtj_avg_total(caddr_t addr, uint64_t normal) 1228 { 1229 /* LINTED - alignment */ 1230 int64_t *data = (int64_t *)addr; 1231 1232 return (data[1] / (int64_t)normal); 1233 } 1234 1235 static int64_t 1236 dtj_avg_count(caddr_t addr) 1237 { 1238 /* LINTED - alignment */ 1239 int64_t *data = (int64_t *)addr; 1240 1241 return (data[0]); 1242 } 1243 1244 static jobject 1245 dtj_stddev_total_squares(JNIEnv *jenv, caddr_t addr, uint64_t normal) 1246 { 1247 jobject val128; 1248 1249 /* LINTED - alignment */ 1250 uint64_t *data = (uint64_t *)addr; 1251 1252 if (data[0] == 0) { 1253 val128 = (*jenv)->CallStaticObjectMethod(jenv, g_bigint_jc, 1254 g_bigint_val_jsm, (uint64_t)0); 1255 } else { 1256 val128 = dtj_int128(jenv, data[3], data[2]); 1257 1258 if (normal != 1) { 1259 jobject divisor; 1260 jobject tmp; 1261 1262 divisor = (*jenv)->CallStaticObjectMethod(jenv, 1263 g_bigint_jc, g_bigint_val_jsm, normal); 1264 tmp = val128; 1265 val128 = (*jenv)->CallObjectMethod(jenv, tmp, 1266 g_bigint_div_jm, divisor); 1267 (*jenv)->DeleteLocalRef(jenv, tmp); 1268 (*jenv)->DeleteLocalRef(jenv, divisor); 1269 } 1270 } 1271 1272 return (val128); 1273 } 1274 1275 /* 1276 * Return NULL if a java exception is pending, otherwise return a new 1277 * StddevValue instance. 1278 */ 1279 static jobject 1280 dtj_stddev(JNIEnv *jenv, caddr_t addr, uint64_t normal) 1281 { 1282 jobject total_squares; 1283 jobject stddev; 1284 1285 total_squares = dtj_stddev_total_squares(jenv, addr, normal); 1286 stddev = (*jenv)->NewObject(jenv, g_aggstddev_jc, g_aggstddevinit_jm, 1287 dtj_avg_count(addr), dtj_avg_total(addr, normal), total_squares); 1288 (*jenv)->DeleteLocalRef(jenv, total_squares); 1289 1290 return (stddev); 1291 } 1292 1293 static jobject 1294 dtj_new_probedata_stack_record(const dtrace_probedata_t *data, 1295 const dtrace_recdesc_t *rec, dtj_java_consumer_t *jc) 1296 { 1297 caddr_t addr; 1298 1299 /* Get raw stack data */ 1300 addr = data->dtpda_data + rec->dtrd_offset; 1301 return (dtj_new_stack_record(addr, rec, jc)); 1302 } 1303 1304 static jobject 1305 dtj_new_tuple_stack_record(const dtrace_aggdata_t *data, 1306 const dtrace_recdesc_t *rec, const char *s, dtj_java_consumer_t *jc) 1307 { 1308 caddr_t addr; 1309 JNIEnv *jenv = jc->dtjj_jenv; 1310 1311 jobjectArray frames = NULL; 1312 jobject jobj = NULL; /* tuple element */ 1313 jstring jstr = NULL; 1314 1315 /* Get raw stack data */ 1316 addr = data->dtada_data + rec->dtrd_offset; 1317 jobj = dtj_new_stack_record(addr, rec, jc); 1318 if (!jobj) { 1319 return (NULL); /* java exception pending */ 1320 } 1321 1322 jstr = dtj_NewStringNative(jenv, s); 1323 if ((*jenv)->ExceptionCheck(jenv)) { 1324 (*jenv)->DeleteLocalRef(jenv, jobj); 1325 return (NULL); 1326 } 1327 frames = (*jenv)->CallStaticObjectMethod(jenv, g_stack_jc, 1328 g_parsestack_jsm, jstr); 1329 (*jenv)->DeleteLocalRef(jenv, jstr); 1330 if ((*jenv)->ExceptionCheck(jenv)) { 1331 (*jenv)->DeleteLocalRef(jenv, jobj); 1332 return (NULL); 1333 } 1334 dtj_attach_frames(jc, jobj, frames); 1335 (*jenv)->DeleteLocalRef(jenv, frames); 1336 if ((*jenv)->ExceptionCheck(jenv)) { 1337 WRAP_EXCEPTION(jenv); 1338 return (NULL); 1339 } 1340 1341 return (jobj); 1342 } 1343 1344 static jobject 1345 dtj_new_probedata_symbol_record(const dtrace_probedata_t *data, 1346 const dtrace_recdesc_t *rec, dtj_java_consumer_t *jc) 1347 { 1348 caddr_t addr; 1349 1350 addr = data->dtpda_data + rec->dtrd_offset; 1351 return (dtj_new_symbol_record(addr, rec, jc)); 1352 } 1353 1354 static jobject 1355 dtj_new_tuple_symbol_record(const dtrace_aggdata_t *data, 1356 const dtrace_recdesc_t *rec, const char *s, dtj_java_consumer_t *jc) 1357 { 1358 caddr_t addr; 1359 JNIEnv *jenv = jc->dtjj_jenv; 1360 1361 jobject jobj = NULL; /* tuple element */ 1362 jstring jstr = NULL; /* lookup value */ 1363 jstring tstr = NULL; /* trimmed lookup value */ 1364 1365 addr = data->dtada_data + rec->dtrd_offset; 1366 jobj = dtj_new_symbol_record(addr, rec, jc); 1367 if (!jobj) { 1368 return (NULL); /* java exception pending */ 1369 } 1370 1371 /* Get symbol lookup */ 1372 jstr = (*jenv)->NewStringUTF(jenv, s); 1373 if (!jstr) { 1374 /* OutOfMemoryError pending */ 1375 (*jenv)->DeleteLocalRef(jenv, jobj); 1376 return (NULL); 1377 } 1378 /* Trim leading and trailing whitespace */ 1379 tstr = (*jenv)->CallObjectMethod(jenv, jstr, g_trim_jm); 1380 /* trim() returns a new string; don't leak the old one */ 1381 (*jenv)->DeleteLocalRef(jenv, jstr); 1382 jstr = tstr; 1383 tstr = NULL; 1384 1385 dtj_attach_name(jc, jobj, jstr); 1386 (*jenv)->DeleteLocalRef(jenv, jstr); 1387 if ((*jenv)->ExceptionCheck(jenv)) { 1388 WRAP_EXCEPTION(jenv); 1389 return (NULL); 1390 } 1391 1392 return (jobj); 1393 } 1394 1395 /* Caller must be holding per-consumer lock */ 1396 static void 1397 dtj_aggwalk_init(dtj_java_consumer_t *jc) 1398 { 1399 jc->dtjj_consumer->dtjc_aggid = -1; 1400 jc->dtjj_consumer->dtjc_expected = -1; 1401 if (jc->dtjj_tuple != NULL) { 1402 /* assert without crashing */ 1403 dtj_throw_illegal_state(jc->dtjj_jenv, 1404 "stale aggregation tuple"); 1405 } 1406 } 1407 1408 static jobject 1409 dtj_new_stack_record(const caddr_t addr, const dtrace_recdesc_t *rec, 1410 dtj_java_consumer_t *jc) 1411 { 1412 JNIEnv *jenv = jc->dtjj_jenv; 1413 1414 dtrace_actkind_t act; 1415 uint64_t *pc; 1416 pid_t pid = -1; 1417 int size; /* size of raw bytes not including trailing zeros */ 1418 int i; /* index of last non-zero byte */ 1419 1420 jbyteArray raw = NULL; 1421 jobject stack = NULL; /* return value */ 1422 1423 /* trim trailing zeros */ 1424 for (i = rec->dtrd_size - 1; (i >= 0) && !addr[i]; --i) { 1425 } 1426 size = (i + 1); 1427 raw = (*jenv)->NewByteArray(jenv, size); 1428 if (!raw) { 1429 return (NULL); /* OutOfMemoryError pending */ 1430 } 1431 (*jenv)->SetByteArrayRegion(jenv, raw, 0, size, 1432 (const jbyte *)addr); 1433 if ((*jenv)->ExceptionCheck(jenv)) { 1434 WRAP_EXCEPTION(jenv); 1435 (*jenv)->DeleteLocalRef(jenv, raw); 1436 return (NULL); 1437 } 1438 1439 /* Create StackValueRecord instance from raw stack data */ 1440 act = rec->dtrd_action; 1441 switch (act) { 1442 case DTRACEACT_STACK: 1443 stack = (*jenv)->NewObject(jenv, g_stack_jc, 1444 g_stackinit_jm, raw); 1445 break; 1446 case DTRACEACT_USTACK: 1447 case DTRACEACT_JSTACK: 1448 /* Get pid of user process */ 1449 pc = (uint64_t *)(uintptr_t)addr; 1450 pid = (pid_t)*pc; 1451 stack = (*jenv)->NewObject(jenv, g_ustack_jc, 1452 g_ustackinit_jm, pid, raw); 1453 break; 1454 default: 1455 dtj_throw_illegal_argument(jenv, 1456 "Expected stack action, got %d\n", act); 1457 } 1458 (*jenv)->DeleteLocalRef(jenv, raw); 1459 if ((*jenv)->ExceptionCheck(jenv)) { 1460 WRAP_EXCEPTION(jenv); 1461 return (NULL); 1462 } 1463 return (stack); 1464 } 1465 1466 static jobject 1467 dtj_new_symbol_record(const caddr_t addr, const dtrace_recdesc_t *rec, 1468 dtj_java_consumer_t *jc) 1469 { 1470 JNIEnv *jenv = jc->dtjj_jenv; 1471 1472 dtrace_actkind_t act; 1473 uint64_t *pc; 1474 pid_t pid = -1; 1475 1476 jobject symbol = NULL; /* return value */ 1477 1478 act = rec->dtrd_action; 1479 switch (act) { 1480 case DTRACEACT_SYM: 1481 case DTRACEACT_MOD: 1482 /* LINTED - alignment */ 1483 pc = (uint64_t *)addr; 1484 symbol = (*jenv)->NewObject(jenv, g_symbol_jc, 1485 g_symbolinit_jm, *pc); 1486 break; 1487 case DTRACEACT_USYM: 1488 case DTRACEACT_UADDR: 1489 case DTRACEACT_UMOD: 1490 /* Get pid of user process */ 1491 pc = (uint64_t *)(uintptr_t)addr; 1492 pid = (pid_t)*pc; 1493 ++pc; 1494 symbol = (*jenv)->NewObject(jenv, g_usymbol_jc, 1495 g_usymbolinit_jm, pid, *pc); 1496 break; 1497 default: 1498 dtj_throw_illegal_argument(jenv, 1499 "Expected stack action, got %d\n", act); 1500 } 1501 if ((*jenv)->ExceptionCheck(jenv)) { 1502 WRAP_EXCEPTION(jenv); 1503 return (NULL); 1504 } 1505 return (symbol); 1506 } 1507 1508 /* 1509 * Return NULL if java exception pending, otherwise return Distribution value. 1510 */ 1511 static jobject 1512 dtj_new_distribution(const dtrace_aggdata_t *data, const dtrace_recdesc_t *rec, 1513 dtj_java_consumer_t *jc) 1514 { 1515 JNIEnv *jenv = jc->dtjj_jenv; 1516 1517 jlongArray jbuckets = NULL; 1518 jobject jdist = NULL; /* return value */ 1519 1520 dtrace_actkind_t act = rec->dtrd_action; 1521 /* LINTED - alignment */ 1522 int64_t *aggbuckets = (int64_t *) 1523 (data->dtada_data + rec->dtrd_offset); 1524 size_t size = rec->dtrd_size; 1525 int64_t value; 1526 uint64_t normal = data->dtada_normal; 1527 int64_t base, step; 1528 int levels; 1529 int n; /* number of buckets */ 1530 1531 /* distribution */ 1532 switch (act) { 1533 case DTRACEAGG_LQUANTIZE: 1534 /* first "bucket" used for range and step */ 1535 value = *aggbuckets++; 1536 base = DTRACE_LQUANTIZE_BASE(value); 1537 step = DTRACE_LQUANTIZE_STEP(value); 1538 levels = DTRACE_LQUANTIZE_LEVELS(value); 1539 size -= sizeof (int64_t); /* exclude non-bucket */ 1540 /* 1541 * Add one for the base bucket and one for the bucket of values 1542 * less than the base. 1543 */ 1544 n = levels + 2; 1545 break; 1546 case DTRACEAGG_LLQUANTIZE: 1547 value = *aggbuckets++; 1548 size -= sizeof (int64_t); 1549 levels = size / sizeof (int64_t); 1550 n = levels; 1551 break; 1552 case DTRACEAGG_QUANTIZE: 1553 n = DTRACE_QUANTIZE_NBUCKETS; 1554 levels = n - 1; /* levels excludes base */ 1555 break; 1556 } 1557 1558 if (size != (n * sizeof (uint64_t)) || n < 1) { 1559 dtj_throw_illegal_state(jenv, 1560 "size mismatch: record %d, buckets %d", size, 1561 (n * sizeof (uint64_t))); 1562 WRAP_EXCEPTION(jenv); 1563 return (NULL); 1564 } 1565 1566 jbuckets = (*jenv)->NewLongArray(jenv, n); 1567 if (!jbuckets) { 1568 return (NULL); /* exception pending */ 1569 } 1570 1571 if (n > 0) { 1572 (*jenv)->SetLongArrayRegion(jenv, jbuckets, 0, n, aggbuckets); 1573 /* check for ArrayIndexOutOfBounds */ 1574 if ((*jenv)->ExceptionCheck(jenv)) { 1575 WRAP_EXCEPTION(jenv); 1576 (*jenv)->DeleteLocalRef(jenv, jbuckets); 1577 return (NULL); 1578 } 1579 } 1580 1581 switch (act) { 1582 case DTRACEAGG_LQUANTIZE: 1583 /* Must pass 64-bit base and step or constructor gets junk. */ 1584 jdist = (*jenv)->NewObject(jenv, g_ldist_jc, g_ldistinit_jm, 1585 base, step, jbuckets); 1586 break; 1587 case DTRACEAGG_QUANTIZE: 1588 jdist = (*jenv)->NewObject(jenv, g_dist_jc, g_distinit_jm, 1589 jbuckets); 1590 break; 1591 case DTRACEAGG_LLQUANTIZE: 1592 jdist = (*jenv)->NewObject(jenv, g_lldist_jc, g_lldistinit_jm, 1593 value, jbuckets); 1594 break; 1595 } 1596 1597 (*jenv)->DeleteLocalRef(jenv, jbuckets); 1598 if (!jdist) { 1599 return (NULL); /* exception pending */ 1600 } 1601 1602 if (normal != 1) { 1603 (*jenv)->CallVoidMethod(jenv, jdist, g_dist_normal_jm, normal); 1604 if ((*jenv)->ExceptionCheck(jenv)) { 1605 WRAP_EXCEPTION(jenv); 1606 (*jenv)->DeleteLocalRef(jenv, jdist); 1607 return (NULL); 1608 } 1609 } 1610 return (jdist); 1611 } 1612 1613 static void 1614 dtj_attach_frames(dtj_java_consumer_t *jc, jobject stack, 1615 jobjectArray frames) 1616 { 1617 JNIEnv *jenv = jc->dtjj_jenv; 1618 1619 if ((*jenv)->IsInstanceOf(jenv, stack, g_stack_jc)) { 1620 (*jenv)->CallVoidMethod(jenv, stack, g_stackset_frames_jm, 1621 frames); 1622 } else if ((*jenv)->IsInstanceOf(jenv, stack, g_ustack_jc)) { 1623 (*jenv)->CallVoidMethod(jenv, stack, g_ustackset_frames_jm, 1624 frames); 1625 } 1626 } 1627 1628 static void 1629 dtj_attach_name(dtj_java_consumer_t *jc, jobject symbol, jstring s) 1630 { 1631 JNIEnv *jenv = jc->dtjj_jenv; 1632 1633 if ((*jenv)->IsInstanceOf(jenv, symbol, g_symbol_jc)) { 1634 (*jenv)->CallVoidMethod(jenv, symbol, g_symbolset_name_jm, s); 1635 } else if ((*jenv)->IsInstanceOf(jenv, symbol, g_usymbol_jc)) { 1636 (*jenv)->CallVoidMethod(jenv, symbol, g_usymbolset_name_jm, s); 1637 } 1638 } 1639 1640 /* 1641 * Note: It is not valid to look outside the current libdtrace record in the 1642 * given aggdata (except to get the aggregation ID from the first record). 1643 * 1644 * Return DTRACE_HANDLE_ABORT if java exception pending, otherwise 1645 * DTRACE_HANDLE_OK. 1646 */ 1647 static int 1648 dtj_agghandler(const dtrace_bufdata_t *bufdata, dtj_java_consumer_t *jc) 1649 { 1650 JNIEnv *jenv = jc->dtjj_jenv; 1651 1652 const dtrace_aggdata_t *aggdata = bufdata->dtbda_aggdata; 1653 const dtrace_aggdesc_t *aggdesc; 1654 const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc; 1655 const char *s = bufdata->dtbda_buffered; 1656 dtrace_actkind_t act = DTRACEACT_NONE; 1657 int64_t aggid; 1658 1659 jobject jobj = NULL; 1660 1661 if (aggdata == NULL) { 1662 /* Assert without crashing */ 1663 dtj_throw_illegal_state(jenv, "null aggdata"); 1664 WRAP_EXCEPTION(jenv); 1665 return (DTRACE_HANDLE_ABORT); 1666 } 1667 aggdesc = aggdata->dtada_desc; 1668 1669 /* 1670 * Get the aggregation ID from the first record. 1671 */ 1672 /* LINTED - alignment */ 1673 aggid = *((int64_t *)(aggdata->dtada_data + 1674 aggdesc->dtagd_rec[0].dtrd_offset)); 1675 if (aggid < 0) { 1676 /* Assert without crashing */ 1677 dtj_throw_illegal_argument(jenv, "negative aggregation ID"); 1678 WRAP_EXCEPTION(jenv); 1679 return (DTRACE_HANDLE_ABORT); 1680 } 1681 1682 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1683 /* Append buffered output if this is a printa() callback. */ 1684 jstring jstr = dtj_NewStringNative(jenv, s); 1685 if ((*jenv)->ExceptionCheck(jenv)) { 1686 WRAP_EXCEPTION(jenv); 1687 return (DTRACE_HANDLE_ABORT); 1688 } 1689 /* 1690 * StringBuilder append() returns a reference to the 1691 * StringBuilder; must not leak the returned reference. 1692 */ 1693 jobj = (*jenv)->CallObjectMethod(jenv, 1694 jc->dtjj_printa_buffer, g_buf_append_str_jm, jstr); 1695 (*jenv)->DeleteLocalRef(jenv, jstr); 1696 (*jenv)->DeleteLocalRef(jenv, jobj); 1697 if ((*jenv)->ExceptionCheck(jenv)) { 1698 WRAP_EXCEPTION(jenv); 1699 return (DTRACE_HANDLE_ABORT); 1700 } 1701 } else { 1702 /* 1703 * Test whether to include the aggregation if this is a 1704 * getAggregate() call. Optimization: perform the inclusion 1705 * test only when the aggregation has changed. 1706 */ 1707 if (aggid != jc->dtjj_consumer->dtjc_aggid) { 1708 jc->dtjj_consumer->dtjc_included = 1709 dtj_is_included(aggdata, jc); 1710 if ((*jenv)->ExceptionCheck(jenv)) { 1711 WRAP_EXCEPTION(jenv); 1712 return (DTRACE_HANDLE_ABORT); 1713 } 1714 } 1715 if (!jc->dtjj_consumer->dtjc_included) { 1716 return (DTRACE_HANDLE_OK); 1717 } 1718 } 1719 jc->dtjj_consumer->dtjc_aggid = aggid; 1720 1721 /* 1722 * Determine the expected number of tuple members. While it is not 1723 * technically valid to look outside the current record in the current 1724 * aggdata, this implementation does so without a known failure case. 1725 * Any method relying only on the current callback record makes riskier 1726 * assumptions and still does not cover every corner case (for example, 1727 * counting the records from index 1 up to and not including the index 1728 * of the current DTRACE_BUFDATA_AGGVAL record, which fails when a 1729 * format string specifies the value ahead of one or more tuple 1730 * elements). Knowing that the calculation of the expected tuple size 1731 * is technically invalid (because it looks outside the current record), 1732 * we make the calculation at the earliest opportunity, before anything 1733 * might happen to invalidate any part of the aggdata. It ought to be 1734 * safe in any case: dtrd_action and dtrd_size do not appear ever to be 1735 * overwritten, and dtrd_offset is not used outside the current record. 1736 * 1737 * It is possible (if the assumptions here ever prove untrue) that the 1738 * libdtrace buffered output handler may need to be enhanced to provide 1739 * the expected number of tuple members. 1740 */ 1741 if (jc->dtjj_consumer->dtjc_expected < 0) { 1742 int r; 1743 for (r = 1; r < aggdesc->dtagd_nrecs; ++r) { 1744 act = aggdesc->dtagd_rec[r].dtrd_action; 1745 if (DTRACEACT_ISAGG(act) || 1746 aggdesc->dtagd_rec[r].dtrd_size == 0) { 1747 break; 1748 } 1749 } 1750 jc->dtjj_consumer->dtjc_expected = r - 1; 1751 } 1752 1753 if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGKEY) { 1754 /* record value is a tuple member */ 1755 1756 if (jc->dtjj_tuple == NULL) { 1757 jc->dtjj_tuple = (*jenv)->NewObject(jenv, 1758 g_tuple_jc, g_tupleinit_jm); 1759 if (!jc->dtjj_tuple) { 1760 /* java exception pending */ 1761 return (DTRACE_HANDLE_ABORT); 1762 } 1763 } 1764 1765 act = rec->dtrd_action; 1766 1767 switch (act) { 1768 case DTRACEACT_STACK: 1769 case DTRACEACT_USTACK: 1770 case DTRACEACT_JSTACK: 1771 jobj = dtj_new_tuple_stack_record(aggdata, rec, s, jc); 1772 break; 1773 case DTRACEACT_USYM: 1774 case DTRACEACT_UADDR: 1775 case DTRACEACT_UMOD: 1776 case DTRACEACT_SYM: 1777 case DTRACEACT_MOD: 1778 jobj = dtj_new_tuple_symbol_record(aggdata, rec, s, jc); 1779 break; 1780 default: 1781 jobj = dtj_recdata(jc, rec->dtrd_size, 1782 (aggdata->dtada_data + rec->dtrd_offset)); 1783 } 1784 1785 if (!jobj) { 1786 /* java exception pending */ 1787 return (DTRACE_HANDLE_ABORT); 1788 } 1789 1790 (*jenv)->CallVoidMethod(jenv, jc->dtjj_tuple, 1791 g_tupleadd_jm, jobj); 1792 (*jenv)->DeleteLocalRef(jenv, jobj); 1793 if ((*jenv)->ExceptionCheck(jenv)) { 1794 WRAP_EXCEPTION(jenv); 1795 return (DTRACE_HANDLE_ABORT); 1796 } 1797 } else if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGVAL) { 1798 /* 1799 * Record value is that of an aggregating action. The printa() 1800 * format string may place the tuple ahead of the aggregation 1801 * value(s), so we can't be sure we have the tuple until we get 1802 * the AGGLAST flag indicating the last callback associated with 1803 * the current tuple. Save the aggregation value or values 1804 * (multiple values if more than one aggregation is passed to 1805 * printa()) until then. 1806 */ 1807 dtj_aggval_t *aggval; 1808 1809 jstring jvalue = NULL; 1810 1811 jvalue = dtj_new_aggval(jc, aggdata, rec); 1812 if (!jvalue) { 1813 /* java exception pending */ 1814 WRAP_EXCEPTION(jenv); 1815 return (DTRACE_HANDLE_ABORT); 1816 } 1817 aggval = dtj_aggval_create(jenv, jvalue, aggdesc->dtagd_name, 1818 aggid); 1819 if (!aggval) { 1820 /* OutOfMemoryError pending */ 1821 (*jenv)->DeleteLocalRef(jenv, jvalue); 1822 return (DTRACE_HANDLE_ABORT); 1823 } 1824 if (!dtj_list_add(jc->dtjj_aggval_list, aggval)) { 1825 /* deletes jvalue reference */ 1826 dtj_aggval_destroy(aggval, jenv); 1827 dtj_throw_out_of_memory(jenv, "Failed to add aggval"); 1828 return (DTRACE_HANDLE_ABORT); 1829 } 1830 } 1831 1832 if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGLAST) { 1833 /* No more values associated with the current tuple. */ 1834 1835 dtj_aggval_t *aggval; 1836 uu_list_walk_t *itr; 1837 int tuple_member_count; 1838 1839 jobject jrec = NULL; 1840 jstring jname = NULL; 1841 1842 if (jc->dtjj_consumer->dtjc_expected == 0) { 1843 /* 1844 * singleton aggregation declared in D with no square 1845 * brackets 1846 */ 1847 jc->dtjj_tuple = (*jenv)->GetStaticObjectField(jenv, 1848 g_tuple_jc, g_tuple_EMPTY_jsf); 1849 if (jc->dtjj_tuple == NULL) { 1850 dtj_throw_out_of_memory(jenv, 1851 "Failed to reference Tuple.EMPTY"); 1852 return (DTRACE_HANDLE_ABORT); 1853 } 1854 } 1855 1856 if (jc->dtjj_tuple == NULL) { 1857 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1858 g_pdatainvalidate_printa_jm); 1859 goto printa_output; 1860 } 1861 1862 tuple_member_count = (*jenv)->CallIntMethod(jenv, 1863 jc->dtjj_tuple, g_tuplesize_jm); 1864 if (tuple_member_count < 1865 jc->dtjj_consumer->dtjc_expected) { 1866 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1867 g_pdatainvalidate_printa_jm); 1868 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1869 jc->dtjj_tuple = NULL; 1870 goto printa_output; 1871 } 1872 1873 itr = uu_list_walk_start(jc->dtjj_aggval_list, 0); 1874 while ((aggval = uu_list_walk_next(itr)) != NULL) { 1875 /* 1876 * new AggregationRecord: Combine the aggregation value 1877 * with the saved tuple and add it to the current 1878 * Aggregate or PrintaRecord. 1879 */ 1880 jrec = (*jenv)->NewObject(jenv, g_aggrec_jc, 1881 g_aggrecinit_jm, jc->dtjj_tuple, 1882 aggval->dtja_value); 1883 (*jenv)->DeleteLocalRef(jenv, aggval->dtja_value); 1884 aggval->dtja_value = NULL; 1885 if (!jrec) { 1886 /* java exception pending */ 1887 WRAP_EXCEPTION(jenv); 1888 return (DTRACE_HANDLE_ABORT); 1889 } 1890 1891 /* aggregation name */ 1892 jname = (*jenv)->NewStringUTF(jenv, 1893 aggval->dtja_aggname); 1894 if (!jname) { 1895 /* OutOfMemoryError pending */ 1896 (*jenv)->DeleteLocalRef(jenv, jrec); 1897 return (DTRACE_HANDLE_ABORT); 1898 } 1899 1900 /* 1901 * If the printa() format string specifies the value of 1902 * the aggregating action multiple times, PrintaRecord 1903 * ignores the attempt to add the duplicate record. 1904 */ 1905 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1906 /* add to PrintaRecord */ 1907 (*jenv)->CallVoidMethod(jenv, 1908 jc->dtjj_probedata, 1909 g_pdataadd_aggrec_jm, 1910 jname, aggval->dtja_aggid, jrec); 1911 } else { 1912 /* add to Aggregate */ 1913 (*jenv)->CallVoidMethod(jenv, 1914 jc->dtjj_aggregate, g_aggaddrec_jm, 1915 jname, aggval->dtja_aggid, jrec); 1916 } 1917 1918 (*jenv)->DeleteLocalRef(jenv, jrec); 1919 (*jenv)->DeleteLocalRef(jenv, jname); 1920 if ((*jenv)->ExceptionCheck(jenv)) { 1921 WRAP_EXCEPTION(jenv); 1922 return (DTRACE_HANDLE_ABORT); 1923 } 1924 } 1925 uu_list_walk_end(itr); 1926 dtj_list_clear(jc->dtjj_aggval_list, dtj_aggval_destroy, 1927 jenv); 1928 1929 printa_output: 1930 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1931 /* 1932 * Get the formatted string associated with the current 1933 * tuple if this is a printa() callback. 1934 */ 1935 jstring jstr = (*jenv)->CallObjectMethod(jenv, 1936 jc->dtjj_printa_buffer, g_tostring_jm); 1937 if ((*jenv)->ExceptionCheck(jenv)) { 1938 WRAP_EXCEPTION(jenv); 1939 return (DTRACE_HANDLE_ABORT); 1940 } 1941 /* 1942 * Clear the StringBuilder: this does not throw 1943 * exceptions. Reuse the StringBuilder until the end of 1944 * the current probedata then dispose of it. 1945 */ 1946 (*jenv)->CallVoidMethod(jenv, jc->dtjj_printa_buffer, 1947 g_bufsetlen_jm, 0); 1948 /* Add formatted string to PrintaRecord */ 1949 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1950 g_pdataadd_printa_str_jm, jc->dtjj_tuple, jstr); 1951 (*jenv)->DeleteLocalRef(jenv, jstr); 1952 if ((*jenv)->ExceptionCheck(jenv)) { 1953 WRAP_EXCEPTION(jenv); 1954 return (DTRACE_HANDLE_ABORT); 1955 } 1956 } 1957 1958 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1959 jc->dtjj_tuple = NULL; 1960 jc->dtjj_consumer->dtjc_expected = -1; 1961 } 1962 1963 return (DTRACE_HANDLE_OK); 1964 } 1965 1966 /* 1967 * Return B_TRUE if the aggregation is included, B_FALSE otherwise. Only in the 1968 * latter case might there be an exception pending. 1969 */ 1970 static boolean_t 1971 dtj_is_included(const dtrace_aggdata_t *data, dtj_java_consumer_t *jc) 1972 { 1973 JNIEnv *jenv = jc->dtjj_jenv; 1974 1975 if (jc->dtjj_aggregate_spec) { 1976 jboolean included; 1977 jstring aggname = NULL; 1978 1979 const dtrace_aggdesc_t *aggdesc = data->dtada_desc; 1980 aggname = (*jenv)->NewStringUTF(jenv, aggdesc->dtagd_name); 1981 if (!aggname) { 1982 /* java exception pending */ 1983 return (B_FALSE); 1984 } 1985 1986 included = (*jenv)->CallBooleanMethod(jenv, 1987 jc->dtjj_aggregate_spec, g_aggspec_included_jm, 1988 aggname); 1989 (*jenv)->DeleteLocalRef(jenv, aggname); 1990 if ((*jenv)->ExceptionCheck(jenv)) { 1991 WRAP_EXCEPTION(jenv); 1992 return (B_FALSE); 1993 } 1994 1995 return (included); 1996 } 1997 1998 return (B_TRUE); 1999 } 2000 2001 /* 2002 * Return NULL if a java exception is pending, otherwise return a new 2003 * AggregationValue instance. 2004 */ 2005 static jobject 2006 dtj_new_aggval(dtj_java_consumer_t *jc, const dtrace_aggdata_t *data, 2007 const dtrace_recdesc_t *rec) 2008 { 2009 JNIEnv *jenv = jc->dtjj_jenv; 2010 2011 jobject jvalue = NULL; /* return value */ 2012 2013 dtrace_actkind_t act; 2014 uint64_t normal; 2015 caddr_t addr; 2016 int64_t value; 2017 2018 act = rec->dtrd_action; 2019 normal = data->dtada_normal; 2020 addr = data->dtada_data + rec->dtrd_offset; 2021 if (act == DTRACEAGG_AVG) { 2022 value = dtj_average(addr, normal); 2023 } else { 2024 /* LINTED - alignment */ 2025 value = (*((int64_t *)addr)) / normal; 2026 } 2027 2028 if ((act == DTRACEAGG_QUANTIZE) || (act == DTRACEAGG_LQUANTIZE) || 2029 (act == DTRACEAGG_LLQUANTIZE)) { 2030 jvalue = dtj_new_distribution(data, rec, jc); 2031 } else { 2032 switch (act) { 2033 case DTRACEAGG_COUNT: 2034 jvalue = (*jenv)->NewObject(jenv, g_aggcount_jc, 2035 g_aggcountinit_jm, value); 2036 break; 2037 case DTRACEAGG_SUM: 2038 jvalue = (*jenv)->NewObject(jenv, g_aggsum_jc, 2039 g_aggsuminit_jm, value); 2040 break; 2041 case DTRACEAGG_AVG: 2042 jvalue = (*jenv)->NewObject(jenv, g_aggavg_jc, 2043 g_aggavginit_jm, value, dtj_avg_total(addr, 2044 normal), dtj_avg_count(addr)); 2045 break; 2046 case DTRACEAGG_MIN: 2047 jvalue = (*jenv)->NewObject(jenv, g_aggmin_jc, 2048 g_aggmininit_jm, value); 2049 break; 2050 case DTRACEAGG_MAX: 2051 jvalue = (*jenv)->NewObject(jenv, g_aggmax_jc, 2052 g_aggmaxinit_jm, value); 2053 break; 2054 case DTRACEAGG_STDDEV: 2055 jvalue = dtj_stddev(jenv, addr, normal); 2056 break; 2057 default: 2058 jvalue = NULL; 2059 dtj_throw_illegal_argument(jenv, 2060 "unexpected aggregation action: %d", act); 2061 } 2062 } 2063 2064 return (jvalue); 2065 } 2066 2067 /* 2068 * Stops the given consumer if it is running. Throws DTraceException if 2069 * dtrace_stop() fails and no other exception is already pending. Clears and 2070 * rethrows any pending exception in order to grab the global lock safely. 2071 */ 2072 void 2073 dtj_stop(dtj_java_consumer_t *jc) 2074 { 2075 JNIEnv *jenv; 2076 int rc; 2077 jthrowable e; 2078 2079 switch (jc->dtjj_consumer->dtjc_state) { 2080 case DTJ_CONSUMER_GO: 2081 case DTJ_CONSUMER_START: 2082 break; 2083 default: 2084 return; 2085 } 2086 2087 jenv = jc->dtjj_jenv; 2088 e = (*jenv)->ExceptionOccurred(jenv); 2089 if (e) { 2090 (*jenv)->ExceptionClear(jenv); 2091 } 2092 2093 (*jenv)->MonitorEnter(jenv, g_caller_jc); 2094 if ((*jenv)->ExceptionCheck(jenv)) { 2095 goto rethrow; 2096 } 2097 2098 rc = dtrace_status(jc->dtjj_consumer->dtjc_dtp); 2099 if (rc != DTRACE_STATUS_STOPPED) { 2100 rc = dtrace_stop(jc->dtjj_consumer->dtjc_dtp); 2101 } 2102 2103 (*jenv)->MonitorExit(jenv, g_caller_jc); 2104 if ((*jenv)->ExceptionCheck(jenv)) { 2105 goto rethrow; 2106 } 2107 2108 if (rc == -1) { 2109 (*jenv)->MonitorEnter(jenv, g_caller_jc); 2110 if ((*jenv)->ExceptionCheck(jenv)) { 2111 goto rethrow; 2112 } 2113 /* Do not wrap DTraceException */ 2114 dtj_throw_dtrace_exception(jc, 2115 "couldn't stop tracing: %s", 2116 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2117 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2118 /* safe to call with pending exception */ 2119 (*jenv)->MonitorExit(jenv, g_caller_jc); 2120 } else { 2121 jc->dtjj_consumer->dtjc_state = DTJ_CONSUMER_STOP; 2122 } 2123 2124 rethrow: 2125 if (e) { 2126 if ((*jenv)->ExceptionCheck(jenv)) { 2127 /* 2128 * Favor earlier pending exception over 2129 * exception thrown in this function. 2130 */ 2131 (*jenv)->ExceptionClear(jenv); 2132 } 2133 (*jenv)->Throw(jenv, e); 2134 (*jenv)->DeleteLocalRef(jenv, e); 2135 } 2136 } 2137 2138 /* 2139 * Return Aggregate instance, or null if java exception pending. 2140 */ 2141 jobject 2142 dtj_get_aggregate(dtj_java_consumer_t *jc) 2143 { 2144 JNIEnv *jenv = jc->dtjj_jenv; 2145 hrtime_t snaptime; 2146 int rc; 2147 2148 jobject aggregate = NULL; 2149 2150 /* Must not call MonitorEnter with a pending exception */ 2151 if ((*jenv)->ExceptionCheck(jenv)) { 2152 WRAP_EXCEPTION(jenv); 2153 return (NULL); 2154 } 2155 2156 /* 2157 * Aggregations must be snapped, walked, and cleared atomically, 2158 * otherwise clearing loses data accumulated since the most recent snap. 2159 * This per-consumer lock prevents dtrace_work() from snapping or 2160 * clearing aggregations while we're in the middle of this atomic 2161 * operation, so we continue to hold it until done clearing. 2162 */ 2163 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2164 if ((*jenv)->ExceptionCheck(jenv)) { 2165 WRAP_EXCEPTION(jenv); 2166 return (NULL); 2167 } 2168 2169 dtj_aggwalk_init(jc); 2170 if ((*jenv)->ExceptionCheck(jenv)) { 2171 WRAP_EXCEPTION(jenv); 2172 /* release per-consumer lock */ 2173 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2174 return (NULL); 2175 } 2176 2177 /* 2178 * Snap aggregations 2179 * 2180 * We need to record the snaptime here for the caller. Leaving it to 2181 * the caller to record the snaptime before calling getAggregate() may 2182 * be inaccurate because of the indeterminate delay waiting on the 2183 * consumer lock before calling dtrace_aggregate_snap(). 2184 */ 2185 snaptime = gethrtime(); 2186 if (dtrace_aggregate_snap(jc->dtjj_consumer->dtjc_dtp) != 0) { 2187 dtj_error_t e; 2188 2189 /* 2190 * The dataDropped() ConsumerListener method can throw an 2191 * exception in the getAggregate() thread if the drop handler is 2192 * invoked during dtrace_aggregate_snap(). 2193 */ 2194 if ((*jenv)->ExceptionCheck(jenv)) { 2195 /* Do not wrap exception thrown from ConsumerListener */ 2196 /* release per-consumer lock */ 2197 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2198 return (NULL); 2199 } 2200 2201 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2202 /* Do not wrap DTraceException */ 2203 dtj_throw_dtrace_exception(jc, e.dtje_message); 2204 } 2205 /* release per-consumer lock */ 2206 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2207 return (NULL); 2208 } 2209 2210 if ((*jenv)->ExceptionCheck(jenv)) { 2211 /* 2212 * Wrap the exception thrown from ConsumerListener in this case, 2213 * so we can see that it unexpectedly reached this spot in 2214 * native code (dtrace_aggregate_snap should have returned 2215 * non-zero). 2216 */ 2217 WRAP_EXCEPTION(jenv); 2218 /* release per-consumer lock */ 2219 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2220 return (NULL); 2221 } 2222 2223 /* Create the Java representation of the aggregate snapshot. */ 2224 aggregate = (*jenv)->NewObject(jenv, g_agg_jc, g_agginit_jm, 2225 snaptime); 2226 if ((*jenv)->ExceptionCheck(jenv)) { 2227 WRAP_EXCEPTION(jenv); 2228 /* release per-consumer lock */ 2229 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2230 return (NULL); 2231 } 2232 jc->dtjj_aggregate = aggregate; 2233 2234 /* 2235 * Walk the aggregate, converting the data into Java Objects. Traverse 2236 * in the order determined by libdtrace, respecting the various 2237 * "aggsort" options, just as dtrace_work does when generating 2238 * aggregations for the printa() action. libdtrace ordering is preserved 2239 * in the "ordinal" property of AggregationRecord, since it would 2240 * otherwise be lost when the records are hashed into the Aggregation's 2241 * map. Neither the consumer loop nor the competing getAggregate() 2242 * thread should depend on any particular record ordering (such as 2243 * ordering by tuple key) to process records correctly. 2244 * 2245 * It is impractical to hold the global lock around 2246 * dtrace_aggregate_print(), since it may take a long time (e.g. an 2247 * entire second) if it performs expensive conversions such as that 2248 * needed for user stack traces. Most libdtrace functions are not 2249 * guaranteed to be MT-safe, even when each thread has its own dtrace 2250 * handle; or even if they are safe, there is no guarantee that future 2251 * changes may not make them unsafe. Fortunately in this case, however, 2252 * only a per-consumer lock is necessary to avoid conflict with 2253 * dtrace_work() running in another thread (the consumer loop). 2254 */ 2255 rc = dtrace_aggregate_print(jc->dtjj_consumer->dtjc_dtp, NULL, NULL); 2256 if ((*jenv)->ExceptionCheck(jenv)) { 2257 WRAP_EXCEPTION(jenv); 2258 /* release per-consumer lock */ 2259 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2260 return (NULL); 2261 } 2262 if (rc != 0) { 2263 dtj_error_t e; 2264 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2265 /* release per-consumer lock */ 2266 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2267 return (NULL); 2268 } 2269 2270 if (e.dtje_number != EINTR) { 2271 /* Do not wrap DTraceException */ 2272 dtj_throw_dtrace_exception(jc, e.dtje_message); 2273 /* release per-consumer lock */ 2274 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2275 return (NULL); 2276 } 2277 } 2278 2279 dtj_aggwalk_init(jc); 2280 if ((*jenv)->ExceptionCheck(jenv)) { 2281 WRAP_EXCEPTION(jenv); 2282 /* release per-consumer lock */ 2283 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2284 return (NULL); 2285 } 2286 2287 /* 2288 * dtrace_aggregate_clear() clears all aggregations, and we need to 2289 * clear aggregations selectively. It also fails to preserve the 2290 * lquantize() range and step size; using aggregate_walk() to clear 2291 * aggregations does not have this problem. 2292 */ 2293 rc = dtrace_aggregate_walk(jc->dtjj_consumer->dtjc_dtp, dtj_clear, jc); 2294 if ((*jenv)->ExceptionCheck(jenv)) { 2295 WRAP_EXCEPTION(jenv); 2296 /* release per-consumer lock */ 2297 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2298 return (NULL); 2299 } 2300 if (rc != 0) { 2301 dtj_error_t e; 2302 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2303 /* Do not wrap DTraceException */ 2304 dtj_throw_dtrace_exception(jc, e.dtje_message); 2305 } 2306 /* release per-consumer lock */ 2307 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2308 return (NULL); 2309 } 2310 2311 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2312 if ((*jenv)->ExceptionCheck(jenv)) { 2313 WRAP_EXCEPTION(jenv); 2314 return (NULL); 2315 } 2316 2317 aggregate = jc->dtjj_aggregate; 2318 jc->dtjj_aggregate = NULL; 2319 2320 return (aggregate); 2321 } 2322 2323 /* 2324 * Process any requests, such as the setting of runtime options, enqueued during 2325 * dtrace_sleep(). A Java exception is pending if this function returns 2326 * DTJ_ERR. 2327 */ 2328 static dtj_status_t 2329 dtj_process_requests(dtj_java_consumer_t *jc) 2330 { 2331 dtj_request_t *r; 2332 uu_list_t *list = jc->dtjj_consumer->dtjc_request_list; 2333 pthread_mutex_t *list_lock = &jc->dtjj_consumer-> 2334 dtjc_request_list_lock; 2335 const char *opt; 2336 const char *val; 2337 2338 (void) pthread_mutex_lock(list_lock); 2339 while (!dtj_list_empty(list)) { 2340 r = uu_list_first(list); 2341 uu_list_remove(list, r); 2342 2343 switch (r->dtjr_type) { 2344 case DTJ_REQUEST_OPTION: 2345 opt = dtj_string_list_first(r->dtjr_args); 2346 val = dtj_string_list_last(r->dtjr_args); 2347 if (dtrace_setopt(jc->dtjj_consumer->dtjc_dtp, opt, 2348 val) == -1) { 2349 /* Do not wrap DTraceException */ 2350 dtj_throw_dtrace_exception(jc, 2351 "failed to set %s: %s", opt, 2352 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2353 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2354 dtj_request_destroy(r, NULL); 2355 (void) pthread_mutex_unlock(list_lock); 2356 return (DTJ_ERR); 2357 } 2358 break; 2359 } 2360 dtj_request_destroy(r, NULL); 2361 } 2362 (void) pthread_mutex_unlock(list_lock); 2363 return (DTJ_OK); 2364 } 2365 2366 /* 2367 * Return DTJ_OK if the consumer loop is stopped normally by either the exit() 2368 * action or the Consumer stop() method. Otherwise return DTJ_ERR if the 2369 * consumer loop terminates abnormally with an exception pending. 2370 */ 2371 dtj_status_t 2372 dtj_consume(dtj_java_consumer_t *jc) 2373 { 2374 JNIEnv *jenv = jc->dtjj_jenv; 2375 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 2376 boolean_t done = B_FALSE; 2377 dtj_error_t e; 2378 2379 do { 2380 if (!jc->dtjj_consumer->dtjc_interrupt) { 2381 dtrace_sleep(dtp); 2382 } 2383 2384 if (jc->dtjj_consumer->dtjc_interrupt) { 2385 done = B_TRUE; 2386 dtj_stop(jc); 2387 if ((*jenv)->ExceptionCheck(jenv)) { 2388 /* 2389 * Exception left pending by Consumer 2390 * getAggregate() method. 2391 */ 2392 return (DTJ_ERR); 2393 } 2394 } else if (jc->dtjj_consumer->dtjc_process_list != NULL) { 2395 int nprocs = uu_list_numnodes(jc->dtjj_consumer-> 2396 dtjc_process_list); 2397 if (jc->dtjj_consumer->dtjc_procs_ended == nprocs) { 2398 done = B_TRUE; 2399 dtj_stop(jc); 2400 } 2401 } 2402 2403 /* 2404 * Functions like dtrace_setopt() are not safe to call during 2405 * dtrace_sleep(). Check the request list every time we wake up 2406 * from dtrace_sleep(). 2407 */ 2408 if (!done) { 2409 if (dtj_process_requests(jc) != DTJ_OK) { 2410 /* Do not wrap DTraceException */ 2411 return (DTJ_ERR); 2412 } 2413 } 2414 2415 /* Must not call MonitorEnter with a pending exception */ 2416 if ((*jenv)->ExceptionCheck(jenv)) { 2417 WRAP_EXCEPTION(jenv); 2418 return (DTJ_ERR); 2419 } 2420 2421 /* 2422 * Use the per-consumer lock to avoid conflict with 2423 * get_aggregate() called from another thread. 2424 */ 2425 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2426 if ((*jenv)->ExceptionCheck(jenv)) { 2427 WRAP_EXCEPTION(jenv); 2428 return (DTJ_ERR); 2429 } 2430 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2431 g_interval_began_jm); 2432 if ((*jenv)->ExceptionCheck(jenv)) { 2433 /* Don't wrap exception thrown from ConsumerListener */ 2434 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2435 return (DTJ_ERR); 2436 } 2437 jc->dtjj_consumer->dtjc_printa_snaptime = gethrtime(); 2438 switch (dtrace_work(dtp, NULL, dtj_chew, dtj_chewrec, jc)) { 2439 case DTRACE_WORKSTATUS_DONE: 2440 done = B_TRUE; 2441 break; 2442 case DTRACE_WORKSTATUS_OKAY: 2443 break; 2444 default: 2445 /* 2446 * Check for a pending exception that got us to this 2447 * error workstatus case. 2448 */ 2449 if ((*jenv)->ExceptionCheck(jenv)) { 2450 /* 2451 * Ensure valid initial state before releasing 2452 * the consumer lock 2453 */ 2454 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2455 /* Do not wrap DTraceException */ 2456 /* Release per-consumer lock */ 2457 (*jenv)->MonitorExit(jenv, 2458 jc->dtjj_consumer_lock); 2459 return (DTJ_ERR); 2460 } 2461 2462 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2463 /* java exception pending */ 2464 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2465 /* Release per-consumer lock */ 2466 (*jenv)->MonitorExit(jenv, 2467 jc->dtjj_consumer_lock); 2468 return (DTJ_ERR); 2469 } 2470 2471 if (e.dtje_number != EINTR) { 2472 /* Do not wrap DTraceException */ 2473 dtj_throw_dtrace_exception(jc, e.dtje_message); 2474 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2475 /* Release per-consumer lock */ 2476 (*jenv)->MonitorExit(jenv, 2477 jc->dtjj_consumer_lock); 2478 return (DTJ_ERR); 2479 } 2480 } 2481 /* 2482 * Check for ConsumerException before doing anything else with 2483 * the JNIEnv. 2484 */ 2485 if ((*jenv)->ExceptionCheck(jenv)) { 2486 /* 2487 * Do not wrap exception thrown from ConsumerListener. 2488 */ 2489 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2490 /* Release per-consumer lock */ 2491 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2492 return (DTJ_ERR); 2493 } 2494 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2495 /* 2496 * Notify ConsumerListeners the the dtrace_work() interval ended 2497 * before releasing the lock. 2498 */ 2499 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2500 g_interval_ended_jm); 2501 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2502 if ((*jenv)->ExceptionCheck(jenv)) { 2503 /* Don't wrap exception thrown from ConsumerListener */ 2504 return (DTJ_ERR); 2505 } 2506 2507 /* 2508 * Check for a temporarily cleared exception set by a handler 2509 * that could not safely leave the exception pending because it 2510 * could not return an abort signal. Rethrow it now that it's 2511 * safe to do so (when it's possible to ensure that no JNI calls 2512 * will be made that are unsafe while an exception is pending). 2513 */ 2514 if (jc->dtjj_exception) { 2515 (*jenv)->Throw(jenv, jc->dtjj_exception); 2516 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_exception); 2517 jc->dtjj_exception = NULL; 2518 return (DTJ_ERR); 2519 } 2520 } while (!done); 2521 2522 return (DTJ_OK); 2523 } 2524