1*1449Stomee /* 2*1449Stomee * CDDL HEADER START 3*1449Stomee * 4*1449Stomee * The contents of this file are subject to the terms of the 5*1449Stomee * Common Development and Distribution License (the "License"). 6*1449Stomee * You may not use this file except in compliance with the License. 7*1449Stomee * 8*1449Stomee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1449Stomee * or http://www.opensolaris.org/os/licensing. 10*1449Stomee * See the License for the specific language governing permissions 11*1449Stomee * and limitations under the License. 12*1449Stomee * 13*1449Stomee * When distributing Covered Code, include this CDDL HEADER in each 14*1449Stomee * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1449Stomee * If applicable, add the following below this CDDL HEADER, with the 16*1449Stomee * fields enclosed by brackets "[]" replaced with your own identifying 17*1449Stomee * information: Portions Copyright [yyyy] [name of copyright owner] 18*1449Stomee * 19*1449Stomee * CDDL HEADER END 20*1449Stomee */ 21*1449Stomee 22*1449Stomee /* 23*1449Stomee * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1449Stomee * Use is subject to license terms. 25*1449Stomee */ 26*1449Stomee 27*1449Stomee #pragma ident "%Z%%M% %I% %E% SMI" 28*1449Stomee 29*1449Stomee #include <stdio.h> 30*1449Stomee #include <errno.h> 31*1449Stomee #include <string.h> 32*1449Stomee #include <stdlib.h> 33*1449Stomee #include <unistd.h> 34*1449Stomee #include <libgen.h> 35*1449Stomee #include <assert.h> 36*1449Stomee #include <strings.h> 37*1449Stomee #include <libproc.h> 38*1449Stomee #include <pthread.h> 39*1449Stomee #include <dtrace_jni.h> 40*1449Stomee /* generated by javah */ 41*1449Stomee #include <LocalConsumer.h> 42*1449Stomee 43*1449Stomee /* 44*1449Stomee * dtrace_jni.c defines all the native methods of the Java DTrace API. Every 45*1449Stomee * native method is declared in a single class, LocalConsumer.java. 46*1449Stomee * 47*1449Stomee * Notes: 48*1449Stomee * 49*1449Stomee * The data generating loop must explicitly release every object reference it 50*1449Stomee * obtains in order to avoid a memory leak. A local JNI object reference is not 51*1449Stomee * automatically released until control returns to java, which never happens as 52*1449Stomee * long as the data generating loop runs. This applies to any JNI function that 53*1449Stomee * obtains an object reference (such as CallObjectMethod() or NewObject()). A 54*1449Stomee * local reference is released by calling DeleteLocalRef(), which is safe to 55*1449Stomee * call with an exception pending. 56*1449Stomee * 57*1449Stomee * It is important to check for an exception after calling java code from native 58*1449Stomee * C, such as after notifying the java consumer of new data. Failure to do this 59*1449Stomee * makes it possible for users of the interface to crash the JVM by throwing an 60*1449Stomee * exception in java code. 61*1449Stomee * 62*1449Stomee * Some JNI functions, like GetIntField() or ReleaseStringUTFChars(), do not 63*1449Stomee * need to be checked for exceptions. 64*1449Stomee * 65*1449Stomee * GetStringUTFChars() returns NULL if and only if an exception was thrown. 66*1449Stomee * 67*1449Stomee * It is important to stop a DTrace consumer and remove it if an exception 68*1449Stomee * occurs. This API guarantees that a consumer is stopped automatically if it 69*1449Stomee * throws an exception. An application running multiple DTrace consumers 70*1449Stomee * simultaneously should be able to continue running the others normally if any 71*1449Stomee * fail. 72*1449Stomee * 73*1449Stomee * Calls to libdtrace are not guaranteed to be MT-safe. Even if they are 74*1449Stomee * currently MT-safe, they are not guaranteed to remain that way. To address 75*1449Stomee * this, a global lock (the LocalConsumer.class reference) is used around calls 76*1449Stomee * to libdtrace. In many cases, the locking is done in java, which should be 77*1449Stomee * indicated in this file by a comment above the function that assumes prior 78*1449Stomee * locking. To access the same global lock from native C code, the JNI function 79*1449Stomee * MonitorEnter() is used. Each MonitorEnter() must have a matching 80*1449Stomee * MonitorExit() or the application will hang (all consumer threads). The 81*1449Stomee * consumer loop and the getAggregate() method require a per-consumer lock 82*1449Stomee * rather than a global lock; in that case the argument to MonitorEnter() and 83*1449Stomee * MonitorExit() is the consumerLock member of the LocalConsumer, not the 84*1449Stomee * LocalConsumer itself. 85*1449Stomee */ 86*1449Stomee 87*1449Stomee #define DTRACE_JNI_VERSION 1 88*1449Stomee 89*1449Stomee #define FIRST_HANDLE 0 /* sequence-generated consumer ID */ 90*1449Stomee #define NO_HANDLE -1 91*1449Stomee #define INITIAL_CAPACITY 8 /* initial size of consumer array */ 92*1449Stomee #define MAX_CAPACITY_INCREMENT 1024 93*1449Stomee 94*1449Stomee static boolean_t g_dtj_load = B_FALSE; 95*1449Stomee static int g_handle_seq = NO_HANDLE; 96*1449Stomee /* 97*1449Stomee * key: caller's consumer handle (int) 98*1449Stomee * value: per-consumer data includes dtrace handle (consumer_t *) 99*1449Stomee */ 100*1449Stomee static dtj_consumer_t **g_consumer_table = NULL; 101*1449Stomee static size_t g_consumer_capacity = 0; 102*1449Stomee static size_t g_consumer_count = 0; 103*1449Stomee static size_t g_max_capacity_increment = MAX_CAPACITY_INCREMENT; 104*1449Stomee static size_t g_max_consumers = 0; /* no maximum */ 105*1449Stomee static boolean_t g_init = B_FALSE; 106*1449Stomee static pthread_mutex_t g_table_lock; 107*1449Stomee static pthread_mutexattr_t g_table_lock_attr; 108*1449Stomee pthread_key_t g_dtj_consumer_key; 109*1449Stomee 110*1449Stomee static int dtj_get_handle(JNIEnv *, jobject); 111*1449Stomee static dtj_status_t dtj_get_java_consumer(JNIEnv *, jobject, 112*1449Stomee dtj_java_consumer_t *); 113*1449Stomee static const char *dtj_getexecname(void); 114*1449Stomee static jobject dtj_get_program_info(dtj_java_consumer_t *, dtrace_proginfo_t *); 115*1449Stomee static jobject dtj_add_program(dtj_java_consumer_t *, dtj_program_t *); 116*1449Stomee static void dtj_flag(uint_t *, uint_t, boolean_t *, boolean_t *); 117*1449Stomee static boolean_t dtj_cflag(dtj_java_consumer_t *, const char *, boolean_t *, 118*1449Stomee boolean_t *); 119*1449Stomee static void dtj_list_probes(JNIEnv *, jobject, jobject, jobject, 120*1449Stomee dtrace_probe_f *); 121*1449Stomee static void dtj_list_compiled_probes(JNIEnv *, jobject, jobject, jobject, 122*1449Stomee dtrace_probe_f *); 123*1449Stomee static int dtj_list_probe(dtrace_hdl_t *, const dtrace_probedesc_t *, void *); 124*1449Stomee static int dtj_list_probe_detail(dtrace_hdl_t *, const dtrace_probedesc_t *, 125*1449Stomee void *); 126*1449Stomee static int dtj_list_stmt(dtrace_hdl_t *, dtrace_prog_t *, dtrace_stmtdesc_t *, 127*1449Stomee void *); 128*1449Stomee static boolean_t dtj_add_consumer(JNIEnv *, dtj_consumer_t *, int *); 129*1449Stomee static dtj_consumer_t *dtj_remove_consumer(JNIEnv *, jobject); 130*1449Stomee static dtj_consumer_t *dtj_remove_consumer_at(int); 131*1449Stomee 132*1449Stomee /* 133*1449Stomee * Gets a sequence-generated consumer ID, or NO_HANDLE if exception pending 134*1449Stomee */ 135*1449Stomee static int 136*1449Stomee dtj_get_handle(JNIEnv *jenv, jobject caller) 137*1449Stomee { 138*1449Stomee int handle; 139*1449Stomee 140*1449Stomee if (!g_dtj_load) { 141*1449Stomee dtj_throw_illegal_state(jenv, "JNI table not loaded"); 142*1449Stomee return (NO_HANDLE); 143*1449Stomee } 144*1449Stomee handle = (*jenv)->CallIntMethod(jenv, caller, g_gethandle_jm); 145*1449Stomee if ((*jenv)->ExceptionCheck(jenv)) { 146*1449Stomee return (NO_HANDLE); 147*1449Stomee } 148*1449Stomee if (handle == NO_HANDLE) { 149*1449Stomee dtj_throw_illegal_state(jenv, "no consumer handle"); 150*1449Stomee } 151*1449Stomee return (handle); 152*1449Stomee } 153*1449Stomee 154*1449Stomee /* 155*1449Stomee * Populates the given java consumer created for use in the current native 156*1449Stomee * method call. If the return value is DTJ_ERR, a java exception is pending. 157*1449Stomee * Throws IllegalStateException if the caller does not have a valid handle. 158*1449Stomee * Throws NoSuchElementException if the caller's handle is not in the global 159*1449Stomee * caller table. 160*1449Stomee */ 161*1449Stomee static dtj_status_t 162*1449Stomee dtj_get_java_consumer(JNIEnv *jenv, jobject caller, dtj_java_consumer_t *jc) 163*1449Stomee { 164*1449Stomee dtj_consumer_t *consumer; 165*1449Stomee int handle = dtj_get_handle(jenv, caller); 166*1449Stomee if (handle == NO_HANDLE) { 167*1449Stomee return (DTJ_ERR); /* java exception pending */ 168*1449Stomee } 169*1449Stomee (void) pthread_mutex_lock(&g_table_lock); 170*1449Stomee if (g_consumer_table) { 171*1449Stomee if ((handle >= 0) && (handle < g_consumer_capacity)) { 172*1449Stomee consumer = g_consumer_table[handle]; 173*1449Stomee } else { 174*1449Stomee consumer = NULL; 175*1449Stomee } 176*1449Stomee } else { 177*1449Stomee consumer = NULL; 178*1449Stomee } 179*1449Stomee (void) pthread_mutex_unlock(&g_table_lock); 180*1449Stomee if (consumer == NULL) { 181*1449Stomee dtj_throw_no_such_element(jenv, "consumer handle %d", handle); 182*1449Stomee return (DTJ_ERR); 183*1449Stomee } 184*1449Stomee 185*1449Stomee /* Initialize java consumer */ 186*1449Stomee bzero(jc, sizeof (dtj_java_consumer_t)); 187*1449Stomee 188*1449Stomee /* Attach per-consumer data */ 189*1449Stomee jc->dtjj_consumer = consumer; 190*1449Stomee 191*1449Stomee /* Attach per-JNI-invocation data */ 192*1449Stomee jc->dtjj_caller = caller; 193*1449Stomee jc->dtjj_jenv = jenv; 194*1449Stomee 195*1449Stomee return (DTJ_OK); 196*1449Stomee } 197*1449Stomee 198*1449Stomee /* 199*1449Stomee * Adds a consumer to the global consumer table. 200*1449Stomee * Returns B_TRUE if successful; a java exception is pending otherwise. 201*1449Stomee * Postcondition: if successful, g_handle_seq is the handle of the consumer just 202*1449Stomee * added. 203*1449Stomee */ 204*1449Stomee static boolean_t 205*1449Stomee dtj_add_consumer(JNIEnv *jenv, dtj_consumer_t *c, int *seq) 206*1449Stomee { 207*1449Stomee int start; 208*1449Stomee 209*1449Stomee if (!g_init) { 210*1449Stomee (void) pthread_key_create(&g_dtj_consumer_key, NULL); 211*1449Stomee (void) pthread_mutexattr_init(&g_table_lock_attr); 212*1449Stomee (void) pthread_mutexattr_settype(&g_table_lock_attr, 213*1449Stomee PTHREAD_MUTEX_RECURSIVE); 214*1449Stomee (void) pthread_mutex_init(&g_table_lock, 215*1449Stomee &g_table_lock_attr); 216*1449Stomee g_init = B_TRUE; 217*1449Stomee } 218*1449Stomee 219*1449Stomee *seq = NO_HANDLE; 220*1449Stomee (void) pthread_mutex_lock(&g_table_lock); 221*1449Stomee if (g_consumer_table == NULL) { 222*1449Stomee g_consumer_table = malloc(INITIAL_CAPACITY * 223*1449Stomee sizeof (dtj_consumer_t *)); 224*1449Stomee if (!g_consumer_table) { 225*1449Stomee g_handle_seq = NO_HANDLE; 226*1449Stomee dtj_throw_out_of_memory(jenv, 227*1449Stomee "could not allocate consumer table"); 228*1449Stomee (void) pthread_mutex_unlock(&g_table_lock); 229*1449Stomee return (B_FALSE); 230*1449Stomee } 231*1449Stomee bzero(g_consumer_table, (INITIAL_CAPACITY * 232*1449Stomee sizeof (dtj_consumer_t *))); 233*1449Stomee g_consumer_capacity = INITIAL_CAPACITY; 234*1449Stomee } else if (g_consumer_count >= g_consumer_capacity) { 235*1449Stomee dtj_consumer_t **t; 236*1449Stomee size_t new_capacity; 237*1449Stomee 238*1449Stomee if ((g_max_consumers > 0) && (g_consumer_count >= 239*1449Stomee g_max_consumers)) { 240*1449Stomee dtj_throw_resource_limit(jenv, "Too many consumers"); 241*1449Stomee (void) pthread_mutex_unlock(&g_table_lock); 242*1449Stomee return (B_FALSE); 243*1449Stomee } 244*1449Stomee 245*1449Stomee if (g_consumer_capacity <= g_max_capacity_increment) { 246*1449Stomee new_capacity = (g_consumer_capacity * 2); 247*1449Stomee } else { 248*1449Stomee new_capacity = (g_consumer_capacity + 249*1449Stomee g_max_capacity_increment); 250*1449Stomee } 251*1449Stomee 252*1449Stomee if ((g_max_consumers > 0) && (new_capacity > g_max_consumers)) { 253*1449Stomee new_capacity = g_max_consumers; 254*1449Stomee } 255*1449Stomee 256*1449Stomee t = realloc(g_consumer_table, 257*1449Stomee new_capacity * sizeof (dtj_consumer_t *)); 258*1449Stomee if (!t) { 259*1449Stomee dtj_throw_out_of_memory(jenv, 260*1449Stomee "could not reallocate consumer table"); 261*1449Stomee (void) pthread_mutex_unlock(&g_table_lock); 262*1449Stomee return (B_FALSE); 263*1449Stomee } 264*1449Stomee 265*1449Stomee g_consumer_table = t; 266*1449Stomee bzero(g_consumer_table + g_consumer_capacity, ((new_capacity - 267*1449Stomee g_consumer_capacity) * sizeof (dtj_consumer_t *))); 268*1449Stomee g_consumer_capacity = new_capacity; 269*1449Stomee } 270*1449Stomee 271*1449Stomee /* Look for an empty slot in the table */ 272*1449Stomee g_handle_seq = (g_handle_seq == NO_HANDLE 273*1449Stomee ? FIRST_HANDLE : g_handle_seq + 1); 274*1449Stomee if (g_handle_seq >= g_consumer_capacity) { 275*1449Stomee g_handle_seq = FIRST_HANDLE; 276*1449Stomee } 277*1449Stomee start = g_handle_seq; /* guard against infinite loop */ 278*1449Stomee while (g_consumer_table[g_handle_seq] != NULL) { 279*1449Stomee ++g_handle_seq; 280*1449Stomee if (g_handle_seq == start) { 281*1449Stomee dtj_throw_illegal_state(jenv, "consumer table full," 282*1449Stomee " but count %d < capacity %d", 283*1449Stomee g_consumer_count, g_consumer_capacity); 284*1449Stomee (void) pthread_mutex_unlock(&g_table_lock); 285*1449Stomee return (B_FALSE); 286*1449Stomee } else if (g_handle_seq >= g_consumer_capacity) { 287*1449Stomee g_handle_seq = FIRST_HANDLE; 288*1449Stomee } 289*1449Stomee } 290*1449Stomee g_consumer_table[g_handle_seq] = c; 291*1449Stomee *seq = g_handle_seq; 292*1449Stomee ++g_consumer_count; 293*1449Stomee (void) pthread_mutex_unlock(&g_table_lock); 294*1449Stomee return (B_TRUE); 295*1449Stomee } 296*1449Stomee 297*1449Stomee /* 298*1449Stomee * Removes a consumer from the global consumer table. The call may be initiated 299*1449Stomee * from Java code or from native code (because an exception has occurred). 300*1449Stomee * Precondition: no exception pending (any pending exception must be temporarily 301*1449Stomee * cleared) 302*1449Stomee * Returns NULL if the caller is not in the table or if this function throws an 303*1449Stomee * exception; either case leaves the global consumer table unchanged. 304*1449Stomee * Throws IllegalStateException if the caller does not have a valid handle. 305*1449Stomee */ 306*1449Stomee static dtj_consumer_t * 307*1449Stomee dtj_remove_consumer(JNIEnv *jenv, jobject caller) 308*1449Stomee { 309*1449Stomee dtj_consumer_t *consumer; 310*1449Stomee int handle = dtj_get_handle(jenv, caller); 311*1449Stomee if (handle == NO_HANDLE) { 312*1449Stomee return (NULL); /* java exception pending */ 313*1449Stomee } 314*1449Stomee consumer = dtj_remove_consumer_at(handle); 315*1449Stomee return (consumer); 316*1449Stomee } 317*1449Stomee 318*1449Stomee /* 319*1449Stomee * Returns NULL if there is no consumer with the given handle. Does not throw 320*1449Stomee * exceptions. 321*1449Stomee */ 322*1449Stomee static dtj_consumer_t * 323*1449Stomee dtj_remove_consumer_at(int handle) 324*1449Stomee { 325*1449Stomee dtj_consumer_t *consumer; 326*1449Stomee (void) pthread_mutex_lock(&g_table_lock); 327*1449Stomee if (g_consumer_table) { 328*1449Stomee if ((handle >= 0) && (handle < g_consumer_capacity)) { 329*1449Stomee consumer = g_consumer_table[handle]; 330*1449Stomee if (consumer != NULL) { 331*1449Stomee g_consumer_table[handle] = NULL; 332*1449Stomee --g_consumer_count; 333*1449Stomee if (g_consumer_count == 0) { 334*1449Stomee free(g_consumer_table); 335*1449Stomee g_consumer_table = NULL; 336*1449Stomee g_consumer_capacity = 0; 337*1449Stomee g_handle_seq = NO_HANDLE; 338*1449Stomee } 339*1449Stomee } 340*1449Stomee } else { 341*1449Stomee consumer = NULL; 342*1449Stomee } 343*1449Stomee } else { 344*1449Stomee consumer = NULL; 345*1449Stomee } 346*1449Stomee (void) pthread_mutex_unlock(&g_table_lock); 347*1449Stomee return (consumer); 348*1449Stomee } 349*1449Stomee 350*1449Stomee /* 351*1449Stomee * Gets the name of the executable in case it is an application with an embedded 352*1449Stomee * JVM and not "java". Implementation is copied from lib/mpss/common/mpss.c. 353*1449Stomee * The use of static auxv_t makes the MT-level unsafe. The caller is expected 354*1449Stomee * to use the global lock (LocalConsumer.class). 355*1449Stomee */ 356*1449Stomee static const char * 357*1449Stomee dtj_getexecname(void) 358*1449Stomee { 359*1449Stomee const char *execname = NULL; 360*1449Stomee static auxv_t auxb; 361*1449Stomee 362*1449Stomee /* 363*1449Stomee * The first time through, read the initial aux vector that was 364*1449Stomee * passed to the process at exec(2). Only do this once. 365*1449Stomee */ 366*1449Stomee int fd = open("/proc/self/auxv", O_RDONLY); 367*1449Stomee 368*1449Stomee if (fd >= 0) { 369*1449Stomee while (read(fd, &auxb, sizeof (auxv_t)) == sizeof (auxv_t)) { 370*1449Stomee if (auxb.a_type == AT_SUN_EXECNAME) { 371*1449Stomee execname = auxb.a_un.a_ptr; 372*1449Stomee break; 373*1449Stomee } 374*1449Stomee } 375*1449Stomee (void) close(fd); 376*1449Stomee } 377*1449Stomee return (execname); 378*1449Stomee } 379*1449Stomee 380*1449Stomee /* 381*1449Stomee * Add the compiled program to a list of programs the API expects to enable. 382*1449Stomee * Returns the Program instance identifying the listed program, or NULL if the 383*1449Stomee * Program constructor fails (exception pending in that case). 384*1449Stomee */ 385*1449Stomee static jobject 386*1449Stomee dtj_add_program(dtj_java_consumer_t *jc, dtj_program_t *p) 387*1449Stomee { 388*1449Stomee JNIEnv *jenv = jc->dtjj_jenv; 389*1449Stomee 390*1449Stomee jobject jprogram = NULL; 391*1449Stomee 392*1449Stomee switch (p->dtjp_type) { 393*1449Stomee case DTJ_PROGRAM_STRING: 394*1449Stomee jprogram = (*jenv)->NewObject(jenv, g_program_jc, 395*1449Stomee g_proginit_jm); 396*1449Stomee break; 397*1449Stomee case DTJ_PROGRAM_FILE: 398*1449Stomee jprogram = (*jenv)->NewObject(jenv, g_programfile_jc, 399*1449Stomee g_fproginit_jm); 400*1449Stomee break; 401*1449Stomee default: 402*1449Stomee dtj_throw_illegal_argument(jenv, "unexpected program type %d\n", 403*1449Stomee p->dtjp_type); 404*1449Stomee } 405*1449Stomee if ((*jenv)->ExceptionCheck(jenv)) { 406*1449Stomee return (NULL); 407*1449Stomee } 408*1449Stomee 409*1449Stomee /* Does not throw exceptions */ 410*1449Stomee (*jenv)->SetIntField(jenv, jprogram, g_progid_jf, 411*1449Stomee uu_list_numnodes(jc->dtjj_consumer->dtjc_program_list)); 412*1449Stomee 413*1449Stomee if (!dtj_list_add(jc->dtjj_consumer->dtjc_program_list, p)) { 414*1449Stomee (*jenv)->DeleteLocalRef(jenv, jprogram); 415*1449Stomee dtj_throw_out_of_memory(jenv, 416*1449Stomee "could not add program"); 417*1449Stomee return (NULL); 418*1449Stomee } 419*1449Stomee 420*1449Stomee return (jprogram); 421*1449Stomee } 422*1449Stomee 423*1449Stomee /* 424*1449Stomee * Returns a new ProgramInfo, or NULL if the constructor fails (java exception 425*1449Stomee * pending in that case). 426*1449Stomee */ 427*1449Stomee static jobject 428*1449Stomee dtj_get_program_info(dtj_java_consumer_t *jc, dtrace_proginfo_t *pinfo) 429*1449Stomee { 430*1449Stomee JNIEnv *jenv = jc->dtjj_jenv; 431*1449Stomee 432*1449Stomee jobject minProbeAttributes = NULL; 433*1449Stomee jobject minStatementAttributes = NULL; 434*1449Stomee jobject programInfo = NULL; /* return value */ 435*1449Stomee 436*1449Stomee minProbeAttributes = dtj_new_attribute(jc, &pinfo->dpi_descattr); 437*1449Stomee if (!minProbeAttributes) { 438*1449Stomee return (NULL); /* java exception pending */ 439*1449Stomee } 440*1449Stomee minStatementAttributes = dtj_new_attribute(jc, &pinfo->dpi_stmtattr); 441*1449Stomee if (!minStatementAttributes) { 442*1449Stomee (*jenv)->DeleteLocalRef(jenv, minProbeAttributes); 443*1449Stomee return (NULL); /* java exception pending */ 444*1449Stomee } 445*1449Stomee 446*1449Stomee programInfo = (*jenv)->NewObject(jenv, g_proginfo_jc, 447*1449Stomee g_proginfoinit_jm, minProbeAttributes, minStatementAttributes, 448*1449Stomee pinfo->dpi_matches); 449*1449Stomee (*jenv)->DeleteLocalRef(jenv, minProbeAttributes); 450*1449Stomee (*jenv)->DeleteLocalRef(jenv, minStatementAttributes); 451*1449Stomee 452*1449Stomee return (programInfo); 453*1449Stomee } 454*1449Stomee 455*1449Stomee /* 456*1449Stomee * Called by LocalConsumer static initializer. 457*1449Stomee */ 458*1449Stomee JNIEXPORT void JNICALL 459*1449Stomee /* ARGSUSED */ 460*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1checkVersion(JNIEnv *env, 461*1449Stomee jclass class, jint version) 462*1449Stomee { 463*1449Stomee if (version != DTRACE_JNI_VERSION) { 464*1449Stomee dtj_throw_illegal_state(env, 465*1449Stomee "LocalConsumer version %d incompatible with native " 466*1449Stomee "implementation version %d", version, DTRACE_JNI_VERSION); 467*1449Stomee } 468*1449Stomee } 469*1449Stomee 470*1449Stomee /* 471*1449Stomee * Called by LocalConsumer static initializer. 472*1449Stomee */ 473*1449Stomee JNIEXPORT void JNICALL 474*1449Stomee /* ARGSUSED */ 475*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1loadJniTable(JNIEnv *env, 476*1449Stomee jclass class) 477*1449Stomee { 478*1449Stomee if (g_dtj_load) { 479*1449Stomee /* 480*1449Stomee * JNI table includes a global reference to the LocalConsumer 481*1449Stomee * class, preventing the class from being unloaded. The 482*1449Stomee * LocalConsumer static initializer should never execute more 483*1449Stomee * than once. 484*1449Stomee */ 485*1449Stomee dtj_throw_illegal_state(env, "JNI table already loaded"); 486*1449Stomee return; 487*1449Stomee } 488*1449Stomee 489*1449Stomee /* If this fails, a Java Error (e.g. NoSuchMethodError) is pending */ 490*1449Stomee if (dtj_load(env) == DTJ_OK) { 491*1449Stomee g_dtj_load = B_TRUE; 492*1449Stomee } 493*1449Stomee } 494*1449Stomee 495*1449Stomee /* 496*1449Stomee * Protected by global lock (LocalConsumer.class) 497*1449Stomee */ 498*1449Stomee JNIEXPORT void JNICALL 499*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1open(JNIEnv *env, jobject obj, 500*1449Stomee jobjectArray flags) 501*1449Stomee { 502*1449Stomee dtrace_hdl_t *dtp; 503*1449Stomee dtj_consumer_t *c; 504*1449Stomee const char *f; /* flag name */ 505*1449Stomee int oflags = 0; 506*1449Stomee int i, len; 507*1449Stomee int id; 508*1449Stomee int err; 509*1449Stomee 510*1449Stomee jobject flag = NULL; 511*1449Stomee jstring flagname = NULL; 512*1449Stomee 513*1449Stomee if (!g_dtj_load) { 514*1449Stomee dtj_throw_illegal_state(env, "JNI table not loaded"); 515*1449Stomee return; 516*1449Stomee } 517*1449Stomee 518*1449Stomee c = dtj_consumer_create(env); 519*1449Stomee if (!c) { 520*1449Stomee return; /* java exception pending */ 521*1449Stomee } 522*1449Stomee 523*1449Stomee /* Get open flags */ 524*1449Stomee len = (flags ? (*env)->GetArrayLength(env, flags) : 0); 525*1449Stomee for (i = 0; i < len; ++i) { 526*1449Stomee flag = (*env)->GetObjectArrayElement(env, flags, i); 527*1449Stomee if ((*env)->ExceptionCheck(env)) { 528*1449Stomee dtj_consumer_destroy(c); 529*1449Stomee return; 530*1449Stomee } 531*1449Stomee 532*1449Stomee flagname = (*env)->CallObjectMethod(env, flag, g_enumname_jm); 533*1449Stomee (*env)->DeleteLocalRef(env, flag); 534*1449Stomee if ((*env)->ExceptionCheck(env)) { 535*1449Stomee dtj_consumer_destroy(c); 536*1449Stomee return; 537*1449Stomee } 538*1449Stomee f = (*env)->GetStringUTFChars(env, flagname, NULL); 539*1449Stomee if ((*env)->ExceptionCheck(env)) { 540*1449Stomee (*env)->DeleteLocalRef(env, flagname); 541*1449Stomee dtj_consumer_destroy(c); 542*1449Stomee return; 543*1449Stomee } 544*1449Stomee if (strcmp(f, "ILP32") == 0) { 545*1449Stomee oflags |= DTRACE_O_ILP32; 546*1449Stomee } else if (strcmp(f, "LP64") == 0) { 547*1449Stomee oflags |= DTRACE_O_LP64; 548*1449Stomee } 549*1449Stomee (*env)->ReleaseStringUTFChars(env, flagname, f); 550*1449Stomee (*env)->DeleteLocalRef(env, flagname); 551*1449Stomee } 552*1449Stomee 553*1449Stomee /* Check for mutually exclusive flags */ 554*1449Stomee if ((oflags & DTRACE_O_ILP32) && (oflags & DTRACE_O_LP64)) { 555*1449Stomee dtj_throw_illegal_argument(env, 556*1449Stomee "Cannot set both ILP32 and LP64"); 557*1449Stomee dtj_consumer_destroy(c); 558*1449Stomee return; 559*1449Stomee } 560*1449Stomee 561*1449Stomee /* 562*1449Stomee * Make sure we can add the consumer before calling dtrace_open(). 563*1449Stomee * Repeated calls to open() when the consumer table is maxed out should 564*1449Stomee * avoid calling dtrace_open(). (Normally there is no limit to the size 565*1449Stomee * of the consumer table, but the undocumented JAVA_DTRACE_MAX_CONSUMERS 566*1449Stomee * system property lets you set a limit after which 567*1449Stomee * ResourceLimitException is thrown.) 568*1449Stomee */ 569*1449Stomee if (!dtj_add_consumer(env, c, &id)) { 570*1449Stomee dtj_consumer_destroy(c); 571*1449Stomee return; /* java exception pending */ 572*1449Stomee } 573*1449Stomee 574*1449Stomee (*env)->CallVoidMethod(env, obj, g_sethandle_jm, id); 575*1449Stomee if ((*env)->ExceptionCheck(env)) { 576*1449Stomee (void) dtj_remove_consumer_at(id); 577*1449Stomee dtj_consumer_destroy(c); 578*1449Stomee return; 579*1449Stomee } 580*1449Stomee 581*1449Stomee if ((dtp = dtrace_open(DTRACE_VERSION, oflags, &err)) == NULL) { 582*1449Stomee dtj_java_consumer_t jc; 583*1449Stomee jc.dtjj_jenv = env; 584*1449Stomee dtj_throw_dtrace_exception(&jc, dtrace_errmsg(NULL, err)); 585*1449Stomee (void) dtj_remove_consumer_at(id); 586*1449Stomee dtj_consumer_destroy(c); 587*1449Stomee return; 588*1449Stomee } 589*1449Stomee c->dtjc_dtp = dtp; /* set consumer handle to native DTrace library */ 590*1449Stomee } 591*1449Stomee 592*1449Stomee static void 593*1449Stomee dtj_flag(uint_t *flags, uint_t flag, boolean_t *get, boolean_t *set) 594*1449Stomee { 595*1449Stomee assert((get && !set) || (set && !get)); 596*1449Stomee 597*1449Stomee if (get) { 598*1449Stomee *get = (*flags & flag); 599*1449Stomee } else { 600*1449Stomee if (*set) { 601*1449Stomee *flags |= flag; 602*1449Stomee } else { 603*1449Stomee *flags &= ~flag; 604*1449Stomee } 605*1449Stomee } 606*1449Stomee } 607*1449Stomee 608*1449Stomee /* 609*1449Stomee * Returns B_TRUE if opt is a recognized compile flag, B_FALSE otherwise. 610*1449Stomee */ 611*1449Stomee static boolean_t 612*1449Stomee dtj_cflag(dtj_java_consumer_t *jc, const char *opt, boolean_t *get, 613*1449Stomee boolean_t *set) 614*1449Stomee { 615*1449Stomee boolean_t is_cflag = B_TRUE; 616*1449Stomee uint_t *flags = &jc->dtjj_consumer->dtjc_cflags; 617*1449Stomee 618*1449Stomee /* see lib/libdtrace/common/dt_option.c */ 619*1449Stomee if (strcmp(opt, "argref") == 0) { 620*1449Stomee dtj_flag(flags, DTRACE_C_ARGREF, get, set); 621*1449Stomee } else if (strcmp(opt, "cpp") == 0) { 622*1449Stomee dtj_flag(flags, DTRACE_C_CPP, get, set); 623*1449Stomee } else if (strcmp(opt, "defaultargs") == 0) { 624*1449Stomee dtj_flag(flags, DTRACE_C_DEFARG, get, set); 625*1449Stomee } else if (strcmp(opt, "empty") == 0) { 626*1449Stomee dtj_flag(flags, DTRACE_C_EMPTY, get, set); 627*1449Stomee } else if (strcmp(opt, "errtags") == 0) { 628*1449Stomee dtj_flag(flags, DTRACE_C_ETAGS, get, set); 629*1449Stomee } else if (strcmp(opt, "knodefs") == 0) { 630*1449Stomee dtj_flag(flags, DTRACE_C_KNODEF, get, set); 631*1449Stomee } else if (strcmp(opt, "nolibs") == 0) { 632*1449Stomee dtj_flag(flags, DTRACE_C_NOLIBS, get, set); 633*1449Stomee } else if (strcmp(opt, "pspec") == 0) { 634*1449Stomee dtj_flag(flags, DTRACE_C_PSPEC, get, set); 635*1449Stomee } else if (strcmp(opt, "unodefs") == 0) { 636*1449Stomee dtj_flag(flags, DTRACE_C_UNODEF, get, set); 637*1449Stomee } else if (strcmp(opt, "verbose") == 0) { 638*1449Stomee dtj_flag(flags, DTRACE_C_DIFV, get, set); 639*1449Stomee } else if (strcmp(opt, "zdefs") == 0) { 640*1449Stomee dtj_flag(flags, DTRACE_C_ZDEFS, get, set); 641*1449Stomee } else { 642*1449Stomee is_cflag = B_FALSE; 643*1449Stomee } 644*1449Stomee 645*1449Stomee if (is_cflag && set && 646*1449Stomee (jc->dtjj_consumer->dtjc_state != DTJ_CONSUMER_INIT)) { 647*1449Stomee dtj_throw_illegal_state(jc->dtjj_jenv, 648*1449Stomee "cannot set compile time option \"%s\" after calling go()", 649*1449Stomee opt); 650*1449Stomee return (is_cflag); 651*1449Stomee } 652*1449Stomee 653*1449Stomee return (is_cflag); 654*1449Stomee } 655*1449Stomee 656*1449Stomee /* 657*1449Stomee * Protected by global lock (LocalConsumer.class) 658*1449Stomee */ 659*1449Stomee JNIEXPORT jobject JNICALL 660*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1compileString(JNIEnv *env, 661*1449Stomee jobject obj, jstring program, jobjectArray args) 662*1449Stomee { 663*1449Stomee const char *prog; 664*1449Stomee dtj_java_consumer_t jc; 665*1449Stomee dtrace_hdl_t *dtp; 666*1449Stomee dtj_program_t *p; 667*1449Stomee int argc = 0; 668*1449Stomee char **argv = NULL; 669*1449Stomee 670*1449Stomee jstring jprogram = NULL; 671*1449Stomee 672*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 673*1449Stomee return (NULL); /* java exception pending */ 674*1449Stomee } 675*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 676*1449Stomee 677*1449Stomee prog = (*env)->GetStringUTFChars(env, program, 0); 678*1449Stomee if ((*env)->ExceptionCheck(env)) { 679*1449Stomee return (NULL); 680*1449Stomee } 681*1449Stomee 682*1449Stomee p = dtj_program_create(env, DTJ_PROGRAM_STRING, prog); 683*1449Stomee if (!p) { 684*1449Stomee (*env)->ReleaseStringUTFChars(env, program, prog); 685*1449Stomee return (NULL); /* java exception pending */ 686*1449Stomee } 687*1449Stomee 688*1449Stomee if (args) { 689*1449Stomee argv = dtj_get_argv(env, args, &argc); 690*1449Stomee if ((*env)->ExceptionCheck(env)) { 691*1449Stomee (*env)->ReleaseStringUTFChars(env, program, prog); 692*1449Stomee dtj_program_destroy(p, NULL); 693*1449Stomee return (NULL); 694*1449Stomee } 695*1449Stomee } 696*1449Stomee 697*1449Stomee if ((p->dtjp_program = dtrace_program_strcompile(dtp, 698*1449Stomee prog, DTRACE_PROBESPEC_NAME, jc.dtjj_consumer->dtjc_cflags, 699*1449Stomee argc, argv)) == NULL) { 700*1449Stomee dtj_throw_dtrace_exception(&jc, 701*1449Stomee "invalid probe specifier %s: %s", 702*1449Stomee prog, dtrace_errmsg(dtp, dtrace_errno(dtp))); 703*1449Stomee (*env)->ReleaseStringUTFChars(env, program, prog); 704*1449Stomee dtj_program_destroy(p, NULL); 705*1449Stomee dtj_free_argv(argv); 706*1449Stomee return (NULL); 707*1449Stomee } 708*1449Stomee (*env)->ReleaseStringUTFChars(env, program, prog); 709*1449Stomee dtj_free_argv(argv); 710*1449Stomee 711*1449Stomee jprogram = dtj_add_program(&jc, p); 712*1449Stomee return (jprogram); /* NULL if exception pending */ 713*1449Stomee } 714*1449Stomee 715*1449Stomee /* 716*1449Stomee * Protected by global lock (LocalConsumer.class) 717*1449Stomee */ 718*1449Stomee JNIEXPORT jobject JNICALL 719*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1compileFile(JNIEnv *env, 720*1449Stomee jobject obj, jstring filename, jobjectArray args) 721*1449Stomee { 722*1449Stomee FILE *fp; 723*1449Stomee const char *file; 724*1449Stomee dtj_java_consumer_t jc; 725*1449Stomee dtrace_hdl_t *dtp; 726*1449Stomee dtj_program_t *p; 727*1449Stomee int argc = 0; 728*1449Stomee char **argv = NULL; 729*1449Stomee 730*1449Stomee jstring jprogram = NULL; 731*1449Stomee 732*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 733*1449Stomee return (NULL); /* java exception pending */ 734*1449Stomee } 735*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 736*1449Stomee 737*1449Stomee file = dtj_GetStringNativeChars(env, filename); 738*1449Stomee if ((fp = fopen(file, "r")) == NULL) { 739*1449Stomee dtj_throw_dtrace_exception(&jc, "failed to open %s", file); 740*1449Stomee dtj_ReleaseStringNativeChars(env, filename, file); 741*1449Stomee return (NULL); 742*1449Stomee } 743*1449Stomee 744*1449Stomee p = dtj_program_create(env, DTJ_PROGRAM_FILE, file); 745*1449Stomee if (!p) { 746*1449Stomee (void) fclose(fp); 747*1449Stomee dtj_ReleaseStringNativeChars(env, filename, file); 748*1449Stomee return (NULL); /* java exception pending */ 749*1449Stomee } 750*1449Stomee 751*1449Stomee if (args) { 752*1449Stomee argv = dtj_get_argv(env, args, &argc); 753*1449Stomee if ((*env)->ExceptionCheck(env)) { 754*1449Stomee (void) fclose(fp); 755*1449Stomee dtj_ReleaseStringNativeChars(env, filename, file); 756*1449Stomee dtj_program_destroy(p, NULL); 757*1449Stomee return (NULL); 758*1449Stomee } 759*1449Stomee } 760*1449Stomee 761*1449Stomee if ((p->dtjp_program = dtrace_program_fcompile(dtp, 762*1449Stomee fp, jc.dtjj_consumer->dtjc_cflags, argc, argv)) == NULL) { 763*1449Stomee dtj_throw_dtrace_exception(&jc, 764*1449Stomee "failed to compile script %s: %s", file, 765*1449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp))); 766*1449Stomee (void) fclose(fp); 767*1449Stomee dtj_ReleaseStringNativeChars(env, filename, file); 768*1449Stomee dtj_program_destroy(p, NULL); 769*1449Stomee dtj_free_argv(argv); 770*1449Stomee return (NULL); 771*1449Stomee } 772*1449Stomee (void) fclose(fp); 773*1449Stomee dtj_ReleaseStringNativeChars(env, filename, file); 774*1449Stomee dtj_free_argv(argv); 775*1449Stomee 776*1449Stomee jprogram = dtj_add_program(&jc, p); 777*1449Stomee return (jprogram); /* NULL if exception pending */ 778*1449Stomee } 779*1449Stomee 780*1449Stomee /* 781*1449Stomee * Protected by global lock (LocalConsumer.class) 782*1449Stomee */ 783*1449Stomee JNIEXPORT void JNICALL 784*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1exec(JNIEnv *env, jobject obj, 785*1449Stomee jobject program) 786*1449Stomee { 787*1449Stomee dtj_java_consumer_t jc; 788*1449Stomee dtrace_hdl_t *dtp; 789*1449Stomee int progid = -1; 790*1449Stomee uu_list_walk_t *itr; 791*1449Stomee dtj_program_t *p; 792*1449Stomee dtrace_proginfo_t *pinfo = NULL; 793*1449Stomee int i; 794*1449Stomee 795*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 796*1449Stomee return; /* java exception pending */ 797*1449Stomee } 798*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 799*1449Stomee 800*1449Stomee if (program) { 801*1449Stomee progid = (*env)->GetIntField(env, program, g_progid_jf); 802*1449Stomee } 803*1449Stomee 804*1449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) { 805*1449Stomee dtj_throw_illegal_state(env, "no program compiled"); 806*1449Stomee return; 807*1449Stomee } 808*1449Stomee 809*1449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0); 810*1449Stomee for (i = 0; (p = uu_list_walk_next(itr)) != NULL; ++i) { 811*1449Stomee /* enable all probes or those of given program only */ 812*1449Stomee if ((progid != -1) && (progid != i)) { 813*1449Stomee continue; 814*1449Stomee } 815*1449Stomee 816*1449Stomee if (p->dtjp_enabled) { 817*1449Stomee dtj_throw_illegal_state(env, "program already enabled"); 818*1449Stomee uu_list_walk_end(itr); 819*1449Stomee return; 820*1449Stomee } 821*1449Stomee 822*1449Stomee pinfo = &p->dtjp_info; 823*1449Stomee if (dtrace_program_exec(dtp, p->dtjp_program, pinfo) == -1) { 824*1449Stomee dtj_throw_dtrace_exception(&jc, 825*1449Stomee "failed to enable %s: %s", p->dtjp_name, 826*1449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp))); 827*1449Stomee uu_list_walk_end(itr); 828*1449Stomee return; 829*1449Stomee } 830*1449Stomee p->dtjp_enabled = B_TRUE; 831*1449Stomee } 832*1449Stomee uu_list_walk_end(itr); 833*1449Stomee 834*1449Stomee if (program) { 835*1449Stomee jobject programInfo = NULL; 836*1449Stomee 837*1449Stomee if (!pinfo) { 838*1449Stomee /* 839*1449Stomee * Consumer.enable() has already checked that the 840*1449Stomee * program was compiled by this consumer. This is an 841*1449Stomee * implementation error, not a user error. 842*1449Stomee */ 843*1449Stomee dtj_throw_illegal_state(env, "program not found"); 844*1449Stomee return; 845*1449Stomee } 846*1449Stomee 847*1449Stomee programInfo = dtj_get_program_info(&jc, pinfo); 848*1449Stomee if (!programInfo) { 849*1449Stomee return; /* java exception pending */ 850*1449Stomee } 851*1449Stomee 852*1449Stomee (*env)->SetObjectField(env, program, g_proginfo_jf, 853*1449Stomee programInfo); 854*1449Stomee (*env)->DeleteLocalRef(env, programInfo); 855*1449Stomee } 856*1449Stomee } 857*1449Stomee 858*1449Stomee /* 859*1449Stomee * Protected by global lock (LocalConsumer.class) 860*1449Stomee */ 861*1449Stomee JNIEXPORT void JNICALL 862*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getProgramInfo(JNIEnv *env, 863*1449Stomee jobject obj, jobject program) 864*1449Stomee { 865*1449Stomee dtj_java_consumer_t jc; 866*1449Stomee dtrace_hdl_t *dtp; 867*1449Stomee int progid; 868*1449Stomee uu_list_walk_t *itr; 869*1449Stomee dtj_program_t *p; 870*1449Stomee dtrace_proginfo_t *pinfo = NULL; 871*1449Stomee int i; 872*1449Stomee 873*1449Stomee jobject programInfo = NULL; 874*1449Stomee 875*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 876*1449Stomee return; /* java exception pending */ 877*1449Stomee } 878*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 879*1449Stomee 880*1449Stomee progid = (*env)->GetIntField(env, program, g_progid_jf); 881*1449Stomee 882*1449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) { 883*1449Stomee dtj_throw_illegal_state(env, "no program compiled"); 884*1449Stomee return; 885*1449Stomee } 886*1449Stomee 887*1449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0); 888*1449Stomee for (i = 0; ((p = uu_list_walk_next(itr)) != NULL) && !pinfo; ++i) { 889*1449Stomee if (progid != i) { 890*1449Stomee /* get info of given program only */ 891*1449Stomee continue; 892*1449Stomee } 893*1449Stomee 894*1449Stomee pinfo = &p->dtjp_info; 895*1449Stomee dtrace_program_info(dtp, p->dtjp_program, pinfo); 896*1449Stomee } 897*1449Stomee uu_list_walk_end(itr); 898*1449Stomee 899*1449Stomee programInfo = dtj_get_program_info(&jc, pinfo); 900*1449Stomee if (!programInfo) { 901*1449Stomee return; /* java exception pending */ 902*1449Stomee } 903*1449Stomee 904*1449Stomee (*env)->SetObjectField(env, program, g_proginfo_jf, 905*1449Stomee programInfo); 906*1449Stomee (*env)->DeleteLocalRef(env, programInfo); 907*1449Stomee } 908*1449Stomee 909*1449Stomee /* 910*1449Stomee * Protected by global lock (LocalConsumer.class) 911*1449Stomee */ 912*1449Stomee JNIEXPORT void JNICALL 913*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1setOption(JNIEnv *env, 914*1449Stomee jobject obj, jstring option, jstring value) 915*1449Stomee { 916*1449Stomee dtj_java_consumer_t jc; 917*1449Stomee const char *opt; 918*1449Stomee const char *val; 919*1449Stomee boolean_t on; 920*1449Stomee 921*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 922*1449Stomee return; /* java exception pending */ 923*1449Stomee } 924*1449Stomee 925*1449Stomee opt = (*env)->GetStringUTFChars(env, option, 0); 926*1449Stomee if (!opt) { 927*1449Stomee dtj_throw_out_of_memory(env, 928*1449Stomee "could not allocate option string"); 929*1449Stomee return; 930*1449Stomee } 931*1449Stomee 932*1449Stomee if (value) { 933*1449Stomee val = (*env)->GetStringUTFChars(env, value, 0); 934*1449Stomee if (!val) { 935*1449Stomee dtj_throw_out_of_memory(env, 936*1449Stomee "could not allocate option value string"); 937*1449Stomee (*env)->ReleaseStringUTFChars(env, option, opt); 938*1449Stomee return; 939*1449Stomee } 940*1449Stomee } else { 941*1449Stomee /* 942*1449Stomee * dtrace_setopt() sets option to 0 if value is NULL. That's 943*1449Stomee * not the same thing as unsetting a boolean option, since 944*1449Stomee * libdtrace uses -2 to mean unset. We'll leave it to 945*1449Stomee * LocalConsumer.java to disallow null or not. 946*1449Stomee */ 947*1449Stomee val = NULL; 948*1449Stomee } 949*1449Stomee 950*1449Stomee /* 951*1449Stomee * Check for boolean compile-time options not handled by 952*1449Stomee * dtrace_setopt(). 953*1449Stomee */ 954*1449Stomee on = (!val || (strcmp(val, "unset") != 0)); 955*1449Stomee if (dtj_cflag(&jc, opt, NULL, &on)) { 956*1449Stomee (*env)->ReleaseStringUTFChars(env, option, opt); 957*1449Stomee if (value) { 958*1449Stomee (*env)->ReleaseStringUTFChars(env, value, val); 959*1449Stomee } 960*1449Stomee return; 961*1449Stomee } 962*1449Stomee 963*1449Stomee /* 964*1449Stomee * The transition from INIT to GO is protected by synchronization 965*1449Stomee * (a per-consumer lock) in LocalConsumer.java, ensuring that go() and 966*1449Stomee * setOption() execute sequentially. 967*1449Stomee */ 968*1449Stomee if (jc.dtjj_consumer->dtjc_state != DTJ_CONSUMER_INIT) { 969*1449Stomee /* 970*1449Stomee * If the consumer is already running, defer setting the option 971*1449Stomee * until we wake up from dtrace_sleep. 972*1449Stomee */ 973*1449Stomee dtj_request_t *request; 974*1449Stomee 975*1449Stomee 976*1449Stomee (void) pthread_mutex_lock( 977*1449Stomee &jc.dtjj_consumer->dtjc_request_list_lock); 978*1449Stomee request = dtj_request_create(env, DTJ_REQUEST_OPTION, opt, val); 979*1449Stomee if (request) { 980*1449Stomee if (!dtj_list_add(jc.dtjj_consumer->dtjc_request_list, 981*1449Stomee request)) { 982*1449Stomee dtj_throw_out_of_memory(env, 983*1449Stomee "Failed to add setOption request"); 984*1449Stomee } 985*1449Stomee } /* else java exception pending */ 986*1449Stomee (void) pthread_mutex_unlock( 987*1449Stomee &jc.dtjj_consumer->dtjc_request_list_lock); 988*1449Stomee } else { 989*1449Stomee dtrace_hdl_t *dtp = jc.dtjj_consumer->dtjc_dtp; 990*1449Stomee if (dtrace_setopt(dtp, opt, val) == -1) { 991*1449Stomee dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp, 992*1449Stomee dtrace_errno(dtp))); 993*1449Stomee } 994*1449Stomee } 995*1449Stomee 996*1449Stomee (*env)->ReleaseStringUTFChars(env, option, opt); 997*1449Stomee if (value) { 998*1449Stomee (*env)->ReleaseStringUTFChars(env, value, val); 999*1449Stomee } 1000*1449Stomee } 1001*1449Stomee 1002*1449Stomee /* 1003*1449Stomee * Protected by global lock (LocalConsumer.class) 1004*1449Stomee */ 1005*1449Stomee JNIEXPORT jlong JNICALL 1006*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getOption(JNIEnv *env, 1007*1449Stomee jobject obj, jstring option) 1008*1449Stomee { 1009*1449Stomee dtj_java_consumer_t jc; 1010*1449Stomee dtrace_hdl_t *dtp; 1011*1449Stomee const char *opt; 1012*1449Stomee dtrace_optval_t optval; 1013*1449Stomee boolean_t cflag; 1014*1449Stomee 1015*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1016*1449Stomee return (0); /* java exception pending */ 1017*1449Stomee } 1018*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1019*1449Stomee 1020*1449Stomee opt = (*env)->GetStringUTFChars(env, option, 0); 1021*1449Stomee if (!opt) { 1022*1449Stomee dtj_throw_out_of_memory(env, 1023*1449Stomee "could not allocate option string"); 1024*1449Stomee return (0); 1025*1449Stomee } 1026*1449Stomee 1027*1449Stomee /* 1028*1449Stomee * Check for boolean compile-time options not handled by 1029*1449Stomee * dtrace_setopt(). 1030*1449Stomee */ 1031*1449Stomee if (dtj_cflag(&jc, opt, &cflag, NULL)) { 1032*1449Stomee (*env)->ReleaseStringUTFChars(env, option, opt); 1033*1449Stomee return (cflag ? 1 : DTRACEOPT_UNSET); 1034*1449Stomee } 1035*1449Stomee 1036*1449Stomee if (dtrace_getopt(dtp, opt, &optval) == -1) { 1037*1449Stomee dtj_throw_dtrace_exception(&jc, 1038*1449Stomee "couldn't get option %s: %s", opt, 1039*1449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp))); 1040*1449Stomee (*env)->ReleaseStringUTFChars(env, option, opt); 1041*1449Stomee return (0); 1042*1449Stomee } 1043*1449Stomee (*env)->ReleaseStringUTFChars(env, option, opt); 1044*1449Stomee return (optval); 1045*1449Stomee } 1046*1449Stomee 1047*1449Stomee /* 1048*1449Stomee * Throws IllegalStateException if not all compiled programs are enabled. 1049*1449Stomee */ 1050*1449Stomee JNIEXPORT void JNICALL 1051*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1checkProgramEnabling(JNIEnv *env, 1052*1449Stomee jobject obj) 1053*1449Stomee { 1054*1449Stomee dtj_java_consumer_t jc; 1055*1449Stomee dtj_program_t *p; 1056*1449Stomee uu_list_walk_t *itr; 1057*1449Stomee 1058*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1059*1449Stomee return; /* java exception pending */ 1060*1449Stomee } 1061*1449Stomee 1062*1449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) { 1063*1449Stomee dtj_throw_illegal_state(env, "no program compiled"); 1064*1449Stomee return; 1065*1449Stomee } 1066*1449Stomee 1067*1449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0); 1068*1449Stomee while ((p = uu_list_walk_next(itr)) != NULL) { 1069*1449Stomee if (!p->dtjp_enabled) { 1070*1449Stomee const char *type; 1071*1449Stomee switch (p->dtjp_type) { 1072*1449Stomee case DTJ_PROGRAM_STRING: 1073*1449Stomee type = "description"; 1074*1449Stomee break; 1075*1449Stomee case DTJ_PROGRAM_FILE: 1076*1449Stomee type = "script"; 1077*1449Stomee break; 1078*1449Stomee default: 1079*1449Stomee assert(p->dtjp_type == DTJ_PROGRAM_STRING || 1080*1449Stomee p->dtjp_type == DTJ_PROGRAM_FILE); 1081*1449Stomee } 1082*1449Stomee dtj_throw_illegal_state(env, 1083*1449Stomee "Not all compiled probes are enabled. " 1084*1449Stomee "Compiled %s %s not enabled.", 1085*1449Stomee type, p->dtjp_name); 1086*1449Stomee uu_list_walk_end(itr); 1087*1449Stomee return; 1088*1449Stomee } 1089*1449Stomee } 1090*1449Stomee uu_list_walk_end(itr); 1091*1449Stomee } 1092*1449Stomee 1093*1449Stomee JNIEXPORT jboolean JNICALL 1094*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1isEnabled(JNIEnv *env, 1095*1449Stomee jobject obj) 1096*1449Stomee { 1097*1449Stomee dtj_java_consumer_t jc; 1098*1449Stomee dtj_program_t *p; 1099*1449Stomee uu_list_walk_t *itr; 1100*1449Stomee 1101*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1102*1449Stomee return (JNI_FALSE); /* java exception pending */ 1103*1449Stomee } 1104*1449Stomee 1105*1449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) { 1106*1449Stomee return (JNI_FALSE); /* no program compiled */ 1107*1449Stomee } 1108*1449Stomee 1109*1449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0); 1110*1449Stomee while ((p = uu_list_walk_next(itr)) != NULL) { 1111*1449Stomee if (!p->dtjp_enabled) { 1112*1449Stomee uu_list_walk_end(itr); 1113*1449Stomee return (JNI_FALSE); 1114*1449Stomee } 1115*1449Stomee } 1116*1449Stomee uu_list_walk_end(itr); 1117*1449Stomee 1118*1449Stomee return (JNI_TRUE); 1119*1449Stomee } 1120*1449Stomee 1121*1449Stomee /* 1122*1449Stomee * Protected by global lock (LocalConsumer.class) 1123*1449Stomee */ 1124*1449Stomee JNIEXPORT void JNICALL 1125*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1go(JNIEnv *env, jobject obj) 1126*1449Stomee { 1127*1449Stomee dtj_java_consumer_t jc; 1128*1449Stomee dtrace_hdl_t *dtp; 1129*1449Stomee 1130*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1131*1449Stomee return; /* java exception pending */ 1132*1449Stomee } 1133*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1134*1449Stomee 1135*1449Stomee if (dtj_set_callback_handlers(&jc) != DTJ_OK) { 1136*1449Stomee return; /* java exception pending */ 1137*1449Stomee } 1138*1449Stomee 1139*1449Stomee if (dtrace_go(dtp) != 0) { 1140*1449Stomee dtj_throw_dtrace_exception(&jc, 1141*1449Stomee "could not enable tracing: %s", 1142*1449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp))); 1143*1449Stomee return; 1144*1449Stomee } 1145*1449Stomee 1146*1449Stomee jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_GO; 1147*1449Stomee } 1148*1449Stomee 1149*1449Stomee /* 1150*1449Stomee * Protected by global lock (LocalConsumer.class). Called when aborting the 1151*1449Stomee * consumer loop before it starts. 1152*1449Stomee */ 1153*1449Stomee JNIEXPORT void JNICALL 1154*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1stop(JNIEnv *env, 1155*1449Stomee jobject obj) 1156*1449Stomee { 1157*1449Stomee dtj_java_consumer_t jc; 1158*1449Stomee dtrace_hdl_t *dtp; 1159*1449Stomee 1160*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1161*1449Stomee return; /* java exception pending */ 1162*1449Stomee } 1163*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1164*1449Stomee 1165*1449Stomee if (dtrace_stop(dtp) == -1) { 1166*1449Stomee dtj_throw_dtrace_exception(&jc, 1167*1449Stomee "couldn't stop tracing: %s", 1168*1449Stomee dtrace_errmsg(jc.dtjj_consumer->dtjc_dtp, 1169*1449Stomee dtrace_errno(jc.dtjj_consumer->dtjc_dtp))); 1170*1449Stomee } else { 1171*1449Stomee jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_STOP; 1172*1449Stomee } 1173*1449Stomee } 1174*1449Stomee 1175*1449Stomee JNIEXPORT void JNICALL 1176*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1consume(JNIEnv *env, 1177*1449Stomee jobject obj) 1178*1449Stomee { 1179*1449Stomee dtj_java_consumer_t jc; 1180*1449Stomee dtrace_hdl_t *dtp; 1181*1449Stomee 1182*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1183*1449Stomee return; /* java exception pending */ 1184*1449Stomee } 1185*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1186*1449Stomee jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_START; 1187*1449Stomee 1188*1449Stomee if (dtj_java_consumer_init(env, &jc) != DTJ_OK) { 1189*1449Stomee return; /* java exception pending */ 1190*1449Stomee } 1191*1449Stomee 1192*1449Stomee /* 1193*1449Stomee * Must set the thread-specific java consumer before starting the 1194*1449Stomee * dtrace_work() loop because the bufhandler can also be invoked by 1195*1449Stomee * getAggregate() from another thread. The bufhandler needs access to 1196*1449Stomee * the correct JNI state specific to either the consumer loop or the 1197*1449Stomee * getAggregate() call. 1198*1449Stomee */ 1199*1449Stomee (void) pthread_setspecific(g_dtj_consumer_key, &jc); 1200*1449Stomee 1201*1449Stomee if (jc.dtjj_consumer->dtjc_process_list != NULL) { 1202*1449Stomee struct ps_prochandle *P; 1203*1449Stomee uu_list_walk_t *itr; 1204*1449Stomee 1205*1449Stomee (*env)->MonitorEnter(env, g_caller_jc); 1206*1449Stomee if ((*env)->ExceptionCheck(env)) { 1207*1449Stomee dtj_java_consumer_fini(env, &jc); 1208*1449Stomee return; /* java exception pending */ 1209*1449Stomee } 1210*1449Stomee 1211*1449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_process_list, 1212*1449Stomee 0); 1213*1449Stomee while ((P = dtj_pointer_list_walk_next(itr)) != 1214*1449Stomee DTJ_INVALID_PTR) { 1215*1449Stomee dtrace_proc_continue(dtp, P); 1216*1449Stomee } 1217*1449Stomee uu_list_walk_end(itr); 1218*1449Stomee 1219*1449Stomee (*env)->MonitorExit(env, g_caller_jc); 1220*1449Stomee if ((*env)->ExceptionCheck(env)) { 1221*1449Stomee dtj_java_consumer_fini(env, &jc); 1222*1449Stomee return; /* java exception pending */ 1223*1449Stomee } 1224*1449Stomee } 1225*1449Stomee 1226*1449Stomee /* 1227*1449Stomee * Blocking call starts consumer loop. 1228*1449Stomee */ 1229*1449Stomee (void) dtj_consume(&jc); 1230*1449Stomee 1231*1449Stomee dtj_java_consumer_fini(env, &jc); 1232*1449Stomee /* 1233*1449Stomee * Stop the consumer after the consumer loop terminates, whether 1234*1449Stomee * normally because of the exit() action or LocalConsumer.stop(), or 1235*1449Stomee * abnormally because of an exception. The call is ignored if the 1236*1449Stomee * consumer is already stopped. It is safe to call dtj_stop() with a 1237*1449Stomee * pending exception. 1238*1449Stomee */ 1239*1449Stomee dtj_stop(&jc); 1240*1449Stomee } 1241*1449Stomee 1242*1449Stomee /* 1243*1449Stomee * Interrupts a running consumer. May be called from any thread. 1244*1449Stomee */ 1245*1449Stomee JNIEXPORT void JNICALL 1246*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1interrupt(JNIEnv *env, 1247*1449Stomee jobject obj) 1248*1449Stomee { 1249*1449Stomee dtj_java_consumer_t jc; 1250*1449Stomee 1251*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1252*1449Stomee return; /* java exception pending */ 1253*1449Stomee } 1254*1449Stomee 1255*1449Stomee jc.dtjj_consumer->dtjc_interrupt = B_TRUE; 1256*1449Stomee } 1257*1449Stomee 1258*1449Stomee /* 1259*1449Stomee * Protected by global lock (LocalConsumer.class) 1260*1449Stomee */ 1261*1449Stomee JNIEXPORT void JNICALL 1262*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1close(JNIEnv *env, jobject obj) 1263*1449Stomee { 1264*1449Stomee dtj_java_consumer_t jc; 1265*1449Stomee dtrace_hdl_t *dtp; 1266*1449Stomee 1267*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1268*1449Stomee return; /* java exception pending */ 1269*1449Stomee } 1270*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1271*1449Stomee 1272*1449Stomee /* 1273*1449Stomee * Need to release any created procs here, since the consumer_t 1274*1449Stomee * destructor (called by _destroy) will not have access to the dtrace 1275*1449Stomee * handle needed to release them (this function closes the dtrace 1276*1449Stomee * handle). 1277*1449Stomee */ 1278*1449Stomee if (jc.dtjj_consumer->dtjc_process_list != NULL) { 1279*1449Stomee struct ps_prochandle *P; 1280*1449Stomee uu_list_walk_t *itr; 1281*1449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_process_list, 1282*1449Stomee 0); 1283*1449Stomee while ((P = dtj_pointer_list_walk_next(itr)) != 1284*1449Stomee DTJ_INVALID_PTR) { 1285*1449Stomee dtrace_proc_release(dtp, P); 1286*1449Stomee } 1287*1449Stomee uu_list_walk_end(itr); 1288*1449Stomee } 1289*1449Stomee 1290*1449Stomee dtrace_close(dtp); 1291*1449Stomee } 1292*1449Stomee 1293*1449Stomee /* 1294*1449Stomee * Static Consumer.java method 1295*1449Stomee */ 1296*1449Stomee JNIEXPORT jint JNICALL 1297*1449Stomee /* ARGSUSED */ 1298*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1openCount(JNIEnv *env, jclass c) 1299*1449Stomee { 1300*1449Stomee int open; 1301*1449Stomee (void) pthread_mutex_lock(&g_table_lock); 1302*1449Stomee if (g_consumer_table == NULL) { 1303*1449Stomee open = 0; 1304*1449Stomee } else { 1305*1449Stomee open = g_consumer_count; 1306*1449Stomee } 1307*1449Stomee (void) pthread_mutex_unlock(&g_table_lock); 1308*1449Stomee return (open); 1309*1449Stomee } 1310*1449Stomee 1311*1449Stomee /* 1312*1449Stomee * Static Consumer.java method 1313*1449Stomee */ 1314*1449Stomee JNIEXPORT jlong JNICALL 1315*1449Stomee /* ARGSUSED */ 1316*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1quantizeBucket(JNIEnv *env, 1317*1449Stomee jclass c, jint bucket) 1318*1449Stomee { 1319*1449Stomee return (DTRACE_QUANTIZE_BUCKETVAL(bucket)); 1320*1449Stomee } 1321*1449Stomee 1322*1449Stomee /* 1323*1449Stomee * Protected by global lock (LocalConsumer.class) 1324*1449Stomee */ 1325*1449Stomee JNIEXPORT jstring JNICALL 1326*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupKernelFunction( 1327*1449Stomee JNIEnv *jenv, jobject caller, jobject address) 1328*1449Stomee { 1329*1449Stomee dtj_java_consumer_t jc; 1330*1449Stomee dtrace_hdl_t *dtp; 1331*1449Stomee 1332*1449Stomee jstring jfunc; /* return value */ 1333*1449Stomee 1334*1449Stomee GElf_Addr addr; 1335*1449Stomee char dummy; 1336*1449Stomee char *s; 1337*1449Stomee int rc; 1338*1449Stomee 1339*1449Stomee if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) { 1340*1449Stomee return (NULL); /* java exception pending */ 1341*1449Stomee } 1342*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1343*1449Stomee 1344*1449Stomee /* Does not throw exceptions */ 1345*1449Stomee if ((*jenv)->IsInstanceOf(jenv, address, g_int_jc)) { 1346*1449Stomee /* intValue() of class Number does not throw exceptions */ 1347*1449Stomee addr = (GElf_Addr)(uint32_t)(*jenv)->CallIntMethod(jenv, 1348*1449Stomee address, g_intval_jm); 1349*1449Stomee } else if ((*jenv)->IsInstanceOf(jenv, address, g_number_jc)) { 1350*1449Stomee /* longValue() of class Number does not throw exceptions */ 1351*1449Stomee addr = (GElf_Addr)(*jenv)->CallLongMethod(jenv, 1352*1449Stomee address, g_longval_jm); 1353*1449Stomee } else { 1354*1449Stomee dtj_throw_class_cast(jenv, "Expected Number address"); 1355*1449Stomee return (NULL); 1356*1449Stomee } 1357*1449Stomee 1358*1449Stomee rc = dtrace_addr2str(dtp, addr, &dummy, 1); 1359*1449Stomee s = malloc(rc); 1360*1449Stomee if (!s) { 1361*1449Stomee dtj_throw_out_of_memory(jenv, 1362*1449Stomee "Failed to allocate kernel function name"); 1363*1449Stomee return (NULL); 1364*1449Stomee } 1365*1449Stomee (void) dtrace_addr2str(dtp, addr, s, rc); 1366*1449Stomee 1367*1449Stomee jfunc = (*jenv)->NewStringUTF(jenv, s); 1368*1449Stomee free(s); 1369*1449Stomee return (jfunc); 1370*1449Stomee } 1371*1449Stomee 1372*1449Stomee /* 1373*1449Stomee * Protected by global lock in Consumer.java 1374*1449Stomee */ 1375*1449Stomee JNIEXPORT jstring JNICALL 1376*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupUserFunction(JNIEnv *jenv, 1377*1449Stomee jobject caller, jint pid, jobject address) 1378*1449Stomee { 1379*1449Stomee dtj_java_consumer_t jc; 1380*1449Stomee dtrace_hdl_t *dtp; 1381*1449Stomee 1382*1449Stomee jstring jfunc; /* return value */ 1383*1449Stomee 1384*1449Stomee GElf_Addr addr; 1385*1449Stomee char dummy; 1386*1449Stomee char *s; 1387*1449Stomee int rc; 1388*1449Stomee 1389*1449Stomee if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) { 1390*1449Stomee return (NULL); /* java exception pending */ 1391*1449Stomee } 1392*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1393*1449Stomee 1394*1449Stomee /* Does not throw exceptions */ 1395*1449Stomee if ((*jenv)->IsInstanceOf(jenv, address, g_int_jc)) { 1396*1449Stomee /* intValue() of class Number does not throw exceptions */ 1397*1449Stomee addr = (GElf_Addr)(uint32_t)(*jenv)->CallIntMethod(jenv, 1398*1449Stomee address, g_intval_jm); 1399*1449Stomee } else if ((*jenv)->IsInstanceOf(jenv, address, g_number_jc)) { 1400*1449Stomee /* longValue() of class Number does not throw exceptions */ 1401*1449Stomee addr = (GElf_Addr)(*jenv)->CallLongMethod(jenv, 1402*1449Stomee address, g_longval_jm); 1403*1449Stomee } else { 1404*1449Stomee dtj_throw_class_cast(jenv, "Expected Number address"); 1405*1449Stomee return (NULL); 1406*1449Stomee } 1407*1449Stomee 1408*1449Stomee rc = dtrace_uaddr2str(dtp, pid, addr, &dummy, 1); 1409*1449Stomee s = malloc(rc); 1410*1449Stomee if (!s) { 1411*1449Stomee dtj_throw_out_of_memory(jenv, 1412*1449Stomee "Failed to allocate user function name"); 1413*1449Stomee return (NULL); 1414*1449Stomee } 1415*1449Stomee (void) dtrace_uaddr2str(dtp, pid, addr, s, rc); 1416*1449Stomee 1417*1449Stomee jfunc = (*jenv)->NewStringUTF(jenv, s); 1418*1449Stomee free(s); 1419*1449Stomee return (jfunc); 1420*1449Stomee } 1421*1449Stomee 1422*1449Stomee JNIEXPORT jobject JNICALL 1423*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getAggregate(JNIEnv *env, 1424*1449Stomee jobject obj, jobject spec) 1425*1449Stomee { 1426*1449Stomee dtj_java_consumer_t jc; 1427*1449Stomee 1428*1449Stomee jobject aggregate = NULL; 1429*1449Stomee 1430*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1431*1449Stomee return (NULL); /* java exception pending */ 1432*1449Stomee } 1433*1449Stomee 1434*1449Stomee if (dtj_java_consumer_init(env, &jc) != DTJ_OK) { 1435*1449Stomee return (NULL); /* java exception pending */ 1436*1449Stomee } 1437*1449Stomee jc.dtjj_aggregate_spec = spec; 1438*1449Stomee 1439*1449Stomee /* 1440*1449Stomee * Must set the thread-specific java consumer before calling any 1441*1449Stomee * function that triggers callbacks to the bufhandler set by 1442*1449Stomee * dtrace_handle_buffered(). The bufhandler needs access to the correct 1443*1449Stomee * JNI state specific to either the consumer loop or the 1444*1449Stomee * getAggregate() call. 1445*1449Stomee */ 1446*1449Stomee (void) pthread_setspecific(g_dtj_consumer_key, &jc); 1447*1449Stomee aggregate = dtj_get_aggregate(&jc); 1448*1449Stomee if (!aggregate) { 1449*1449Stomee /* java exception pending */ 1450*1449Stomee jc.dtjj_consumer->dtjc_interrupt = B_TRUE; 1451*1449Stomee } 1452*1449Stomee /* 1453*1449Stomee * Cleans up only references created by this JNI invocation. Leaves 1454*1449Stomee * cached per-consumer state untouched. 1455*1449Stomee */ 1456*1449Stomee dtj_java_consumer_fini(env, &jc); 1457*1449Stomee return (aggregate); 1458*1449Stomee } 1459*1449Stomee 1460*1449Stomee /* 1461*1449Stomee * Returns the pid of the created process, or -1 in case of an error (java 1462*1449Stomee * exception pending). 1463*1449Stomee * Protected by global lock (LocalConsumer.class) 1464*1449Stomee */ 1465*1449Stomee JNIEXPORT int JNICALL 1466*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1createProcess(JNIEnv *jenv, 1467*1449Stomee jobject caller, jstring command) 1468*1449Stomee { 1469*1449Stomee dtj_java_consumer_t jc; 1470*1449Stomee dtrace_hdl_t *dtp; 1471*1449Stomee struct ps_prochandle *P; 1472*1449Stomee char **argv; 1473*1449Stomee int argc; 1474*1449Stomee 1475*1449Stomee if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) { 1476*1449Stomee return (-1); /* java exception pending */ 1477*1449Stomee } 1478*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1479*1449Stomee 1480*1449Stomee if (jc.dtjj_consumer->dtjc_process_list == NULL) { 1481*1449Stomee jc.dtjj_consumer->dtjc_process_list = dtj_pointer_list_create(); 1482*1449Stomee if (!jc.dtjj_consumer->dtjc_process_list) { 1483*1449Stomee dtj_throw_out_of_memory(jenv, 1484*1449Stomee "Could not allocate process list"); 1485*1449Stomee return (-1); 1486*1449Stomee } 1487*1449Stomee } 1488*1449Stomee 1489*1449Stomee argv = dtj_make_argv(jenv, command, &argc); 1490*1449Stomee if ((*jenv)->ExceptionCheck(jenv)) { 1491*1449Stomee return (-1); 1492*1449Stomee } 1493*1449Stomee 1494*1449Stomee P = dtrace_proc_create(dtp, argv[0], argv); 1495*1449Stomee dtj_free_argv(argv); 1496*1449Stomee 1497*1449Stomee if (!P) { 1498*1449Stomee dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp, 1499*1449Stomee dtrace_errno(dtp))); 1500*1449Stomee return (-1); 1501*1449Stomee } 1502*1449Stomee 1503*1449Stomee if (!dtj_pointer_list_add(jc.dtjj_consumer->dtjc_process_list, P)) { 1504*1449Stomee dtj_throw_out_of_memory(jenv, 1505*1449Stomee "Failed to add process to process list"); 1506*1449Stomee dtrace_proc_release(dtp, P); 1507*1449Stomee return (-1); 1508*1449Stomee } 1509*1449Stomee return (Pstatus(P)->pr_pid); 1510*1449Stomee } 1511*1449Stomee 1512*1449Stomee /* 1513*1449Stomee * Protected by global lock (LocalConsumer.class) 1514*1449Stomee */ 1515*1449Stomee JNIEXPORT void JNICALL 1516*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1grabProcess(JNIEnv *jenv, 1517*1449Stomee jobject caller, jint pid) 1518*1449Stomee { 1519*1449Stomee dtj_java_consumer_t jc; 1520*1449Stomee dtrace_hdl_t *dtp; 1521*1449Stomee struct ps_prochandle *P; 1522*1449Stomee 1523*1449Stomee if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) { 1524*1449Stomee return; /* java exception pending */ 1525*1449Stomee } 1526*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1527*1449Stomee 1528*1449Stomee if (jc.dtjj_consumer->dtjc_process_list == NULL) { 1529*1449Stomee jc.dtjj_consumer->dtjc_process_list = dtj_pointer_list_create(); 1530*1449Stomee if (jc.dtjj_consumer->dtjc_process_list == NULL) { 1531*1449Stomee dtj_throw_out_of_memory(jenv, 1532*1449Stomee "Could not allocate process list"); 1533*1449Stomee return; 1534*1449Stomee } 1535*1449Stomee } 1536*1449Stomee 1537*1449Stomee P = dtrace_proc_grab(dtp, (pid_t)pid, 0); 1538*1449Stomee if (!P) { 1539*1449Stomee dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp, 1540*1449Stomee dtrace_errno(dtp))); 1541*1449Stomee return; 1542*1449Stomee } 1543*1449Stomee 1544*1449Stomee if (!dtj_pointer_list_add(jc.dtjj_consumer->dtjc_process_list, P)) { 1545*1449Stomee dtj_throw_out_of_memory(jenv, 1546*1449Stomee "Failed to add process to process list"); 1547*1449Stomee dtrace_proc_release(dtp, P); 1548*1449Stomee return; 1549*1449Stomee } 1550*1449Stomee } 1551*1449Stomee 1552*1449Stomee /* 1553*1449Stomee * Lists all probes, or lists matching probes (using the matching rules from 1554*1449Stomee * Table 4-1 of the DTrace manual). 1555*1449Stomee * 1556*1449Stomee * In the future it may be desirable to support an array of probe filters rather 1557*1449Stomee * than a single filter. It could be that if a probe matched any of the given 1558*1449Stomee * filters, it would be included (implied logical OR). 1559*1449Stomee * 1560*1449Stomee * Protected by global lock (LocalConsumer.class) 1561*1449Stomee * param list: an empty list to populate (this function empties the list if it 1562*1449Stomee * is not empty already) 1563*1449Stomee * param filter: a ProbeDescription instance; the list will include only probes 1564*1449Stomee * that match the filter (match all probes if filter is null) 1565*1449Stomee */ 1566*1449Stomee JNIEXPORT void JNICALL 1567*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbes(JNIEnv *env, 1568*1449Stomee jobject obj, jobject list, jobject filter) 1569*1449Stomee { 1570*1449Stomee dtj_list_probes(env, obj, list, filter, dtj_list_probe); 1571*1449Stomee } 1572*1449Stomee 1573*1449Stomee JNIEXPORT void JNICALL 1574*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbeDetail(JNIEnv *env, 1575*1449Stomee jobject obj, jobject list, jobject filter) 1576*1449Stomee { 1577*1449Stomee dtj_list_probes(env, obj, list, filter, dtj_list_probe_detail); 1578*1449Stomee } 1579*1449Stomee 1580*1449Stomee static void 1581*1449Stomee dtj_list_probes(JNIEnv *env, jobject obj, jobject list, jobject filter, 1582*1449Stomee dtrace_probe_f *func) 1583*1449Stomee { 1584*1449Stomee dtj_java_consumer_t jc; 1585*1449Stomee dtrace_hdl_t *dtp; 1586*1449Stomee dtrace_probedesc_t probe; 1587*1449Stomee dtrace_probedesc_t *pdp = NULL; 1588*1449Stomee const char *probestr; 1589*1449Stomee int rc; 1590*1449Stomee 1591*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1592*1449Stomee return; /* java exception pending */ 1593*1449Stomee } 1594*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1595*1449Stomee 1596*1449Stomee jc.dtjj_probelist = list; 1597*1449Stomee 1598*1449Stomee /* clear in-out list parameter */ 1599*1449Stomee (*env)->CallVoidMethod(env, list, g_listclear_jm); 1600*1449Stomee if ((*env)->ExceptionCheck(env)) { 1601*1449Stomee return; 1602*1449Stomee } 1603*1449Stomee 1604*1449Stomee if (filter) { 1605*1449Stomee jstring jprobestr = NULL; 1606*1449Stomee 1607*1449Stomee jprobestr = (*env)->CallObjectMethod(env, filter, 1608*1449Stomee g_tostring_jm); 1609*1449Stomee if ((*env)->ExceptionCheck(env)) { 1610*1449Stomee return; 1611*1449Stomee } 1612*1449Stomee probestr = (*env)->GetStringUTFChars(env, jprobestr, NULL); 1613*1449Stomee if (!probestr) { 1614*1449Stomee (*env)->DeleteLocalRef(env, jprobestr); 1615*1449Stomee return; /* java exception pending */ 1616*1449Stomee } 1617*1449Stomee 1618*1449Stomee bzero(&probe, sizeof (probe)); 1619*1449Stomee rc = dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, probestr, 1620*1449Stomee &probe); 1621*1449Stomee (*env)->ReleaseStringUTFChars(env, jprobestr, probestr); 1622*1449Stomee (*env)->DeleteLocalRef(env, jprobestr); 1623*1449Stomee if (rc == -1) { 1624*1449Stomee dtj_throw_dtrace_exception(&jc, 1625*1449Stomee "%s is not a valid probe description: %s", 1626*1449Stomee probestr, dtrace_errmsg(dtp, 1627*1449Stomee dtrace_errno(dtp))); 1628*1449Stomee return; 1629*1449Stomee } 1630*1449Stomee 1631*1449Stomee pdp = &probe; 1632*1449Stomee } 1633*1449Stomee 1634*1449Stomee (void) dtrace_probe_iter(dtp, pdp, func, &jc); 1635*1449Stomee } 1636*1449Stomee 1637*1449Stomee /* 1638*1449Stomee * Returns 0 to indicate success, or -1 to cause dtrace_probe_iter() to return a 1639*1449Stomee * negative value prematurely (indicating no match or failure). 1640*1449Stomee */ 1641*1449Stomee static int 1642*1449Stomee /* ARGSUSED */ 1643*1449Stomee dtj_list_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg) 1644*1449Stomee { 1645*1449Stomee dtj_java_consumer_t *jc = arg; 1646*1449Stomee JNIEnv *jenv = jc->dtjj_jenv; 1647*1449Stomee 1648*1449Stomee jobject jprobedesc = NULL; 1649*1449Stomee 1650*1449Stomee jprobedesc = dtj_new_probedesc(jc, pdp); 1651*1449Stomee if (!jprobedesc) { 1652*1449Stomee return (-1); /* java exception pending */ 1653*1449Stomee } 1654*1449Stomee 1655*1449Stomee /* add probe to list */ 1656*1449Stomee (*jenv)->CallVoidMethod(jenv, jc->dtjj_probelist, g_listadd_jm, 1657*1449Stomee jprobedesc); 1658*1449Stomee (*jenv)->DeleteLocalRef(jenv, jprobedesc); 1659*1449Stomee if ((*jenv)->ExceptionCheck(jenv)) { 1660*1449Stomee return (-1); 1661*1449Stomee } 1662*1449Stomee 1663*1449Stomee return (0); 1664*1449Stomee } 1665*1449Stomee 1666*1449Stomee /*ARGSUSED*/ 1667*1449Stomee static int 1668*1449Stomee dtj_list_probe_detail(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, 1669*1449Stomee void *arg) 1670*1449Stomee { 1671*1449Stomee dtj_java_consumer_t *jc = arg; 1672*1449Stomee JNIEnv *jenv = jc->dtjj_jenv; 1673*1449Stomee dtrace_probeinfo_t p; 1674*1449Stomee 1675*1449Stomee jobject jprobedesc = NULL; 1676*1449Stomee jobject jprobeinfo = NULL; 1677*1449Stomee jobject jprobe = NULL; 1678*1449Stomee 1679*1449Stomee jprobedesc = dtj_new_probedesc(jc, pdp); 1680*1449Stomee if (!jprobedesc) { 1681*1449Stomee return (-1); /* java exception pending */ 1682*1449Stomee } 1683*1449Stomee 1684*1449Stomee /* 1685*1449Stomee * If dtrace_probe_info() returns a non-zero value, dtrace_errno is set 1686*1449Stomee * for us. In that case, ignore the dtrace error and simply omit probe 1687*1449Stomee * info. That error is implicitly cleared the next time a call is made 1688*1449Stomee * using the same dtrace handle. 1689*1449Stomee */ 1690*1449Stomee if (dtrace_probe_info(dtp, pdp, &p) == 0) { 1691*1449Stomee /* create probe info instance */ 1692*1449Stomee jprobeinfo = dtj_new_probeinfo(jc, &p); 1693*1449Stomee if (!jprobeinfo) { 1694*1449Stomee (*jenv)->DeleteLocalRef(jenv, jprobedesc); 1695*1449Stomee return (-1); /* java exception pending */ 1696*1449Stomee } 1697*1449Stomee } 1698*1449Stomee 1699*1449Stomee /* create listed probe instance */ 1700*1449Stomee jprobe = (*jenv)->NewObject(jenv, g_probe_jc, g_probeinit_jm, 1701*1449Stomee jprobedesc, jprobeinfo); 1702*1449Stomee (*jenv)->DeleteLocalRef(jenv, jprobedesc); 1703*1449Stomee (*jenv)->DeleteLocalRef(jenv, jprobeinfo); 1704*1449Stomee if (!jprobe) { 1705*1449Stomee return (-1); /* java exception pending */ 1706*1449Stomee } 1707*1449Stomee 1708*1449Stomee /* add probe to list */ 1709*1449Stomee (*jenv)->CallVoidMethod(jenv, jc->dtjj_probelist, g_listadd_jm, 1710*1449Stomee jprobe); 1711*1449Stomee (*jenv)->DeleteLocalRef(jenv, jprobe); 1712*1449Stomee if ((*jenv)->ExceptionCheck(jenv)) { 1713*1449Stomee return (-1); 1714*1449Stomee } 1715*1449Stomee 1716*1449Stomee return (0); 1717*1449Stomee } 1718*1449Stomee 1719*1449Stomee /*ARGSUSED*/ 1720*1449Stomee static int 1721*1449Stomee dtj_list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 1722*1449Stomee dtrace_stmtdesc_t *stp, void *arg) 1723*1449Stomee { 1724*1449Stomee dtj_java_consumer_t *jc = arg; 1725*1449Stomee dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc; 1726*1449Stomee 1727*1449Stomee if (edp == jc->dtjj_consumer->dtjc_last_probe) { 1728*1449Stomee return (0); 1729*1449Stomee } 1730*1449Stomee 1731*1449Stomee if (dtrace_probe_iter(dtp, &edp->dted_probe, 1732*1449Stomee jc->dtjj_consumer->dtjc_plistfunc, arg) != 0) { 1733*1449Stomee dtj_throw_dtrace_exception(jc, 1734*1449Stomee "failed to match %s:%s:%s:%s: %s", 1735*1449Stomee edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod, 1736*1449Stomee edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name, 1737*1449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp))); 1738*1449Stomee return (1); 1739*1449Stomee } 1740*1449Stomee 1741*1449Stomee jc->dtjj_consumer->dtjc_last_probe = edp; 1742*1449Stomee return (0); 1743*1449Stomee } 1744*1449Stomee 1745*1449Stomee /* 1746*1449Stomee * Protected by global lock in Consumer.java 1747*1449Stomee */ 1748*1449Stomee JNIEXPORT void JNICALL 1749*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbes(JNIEnv *env, 1750*1449Stomee jobject obj, jobject list, jobject program) 1751*1449Stomee { 1752*1449Stomee dtj_list_compiled_probes(env, obj, list, program, dtj_list_probe); 1753*1449Stomee } 1754*1449Stomee 1755*1449Stomee JNIEXPORT void JNICALL 1756*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbeDetail( 1757*1449Stomee JNIEnv *env, jobject obj, jobject list, jobject program) 1758*1449Stomee { 1759*1449Stomee dtj_list_compiled_probes(env, obj, list, program, 1760*1449Stomee dtj_list_probe_detail); 1761*1449Stomee } 1762*1449Stomee 1763*1449Stomee static void 1764*1449Stomee dtj_list_compiled_probes(JNIEnv *env, jobject obj, jobject list, 1765*1449Stomee jobject program, dtrace_probe_f *func) 1766*1449Stomee { 1767*1449Stomee dtj_java_consumer_t jc; 1768*1449Stomee dtrace_hdl_t *dtp; 1769*1449Stomee uu_list_walk_t *itr; 1770*1449Stomee dtj_program_t *p; 1771*1449Stomee boolean_t found; 1772*1449Stomee int progid = -1; 1773*1449Stomee int i; 1774*1449Stomee 1775*1449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) { 1776*1449Stomee return; /* java exception pending */ 1777*1449Stomee } 1778*1449Stomee dtp = jc.dtjj_consumer->dtjc_dtp; 1779*1449Stomee jc.dtjj_probelist = list; 1780*1449Stomee 1781*1449Stomee (*env)->CallVoidMethod(env, list, g_listclear_jm); 1782*1449Stomee if ((*env)->ExceptionCheck(env)) { 1783*1449Stomee return; 1784*1449Stomee } 1785*1449Stomee 1786*1449Stomee if (program) { 1787*1449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) { 1788*1449Stomee dtj_throw_no_such_element(env, "no compiled program"); 1789*1449Stomee return; 1790*1449Stomee } 1791*1449Stomee progid = (*env)->GetIntField(env, program, g_progid_jf); 1792*1449Stomee if (progid == -1) { 1793*1449Stomee dtj_throw_illegal_argument(env, "invalid program"); 1794*1449Stomee return; 1795*1449Stomee } 1796*1449Stomee } 1797*1449Stomee 1798*1449Stomee jc.dtjj_consumer->dtjc_plistfunc = func; 1799*1449Stomee found = B_FALSE; 1800*1449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0); 1801*1449Stomee for (i = 0; (p = uu_list_walk_next(itr)) != NULL; ++i) { 1802*1449Stomee if ((progid != -1) && (progid != i)) { 1803*1449Stomee continue; 1804*1449Stomee } 1805*1449Stomee 1806*1449Stomee found = B_TRUE; 1807*1449Stomee (void) dtrace_stmt_iter(dtp, p->dtjp_program, 1808*1449Stomee (dtrace_stmt_f *)dtj_list_stmt, &jc); 1809*1449Stomee } 1810*1449Stomee uu_list_walk_end(itr); 1811*1449Stomee 1812*1449Stomee if (program && !found) { 1813*1449Stomee dtj_throw_no_such_element(env, "program not found"); 1814*1449Stomee } 1815*1449Stomee } 1816*1449Stomee 1817*1449Stomee /* 1818*1449Stomee * Static LocalConsumer.java method 1819*1449Stomee * Protected by global lock (LocalConsumer.class) 1820*1449Stomee */ 1821*1449Stomee JNIEXPORT jstring JNICALL 1822*1449Stomee /* ARGSUSED */ 1823*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getVersion(JNIEnv *env, 1824*1449Stomee jclass class) 1825*1449Stomee { 1826*1449Stomee /* 1827*1449Stomee * Handles the case of locale-specific encoding of the user-visible 1828*1449Stomee * version string containing non-ASCII characters. 1829*1449Stomee */ 1830*1449Stomee return (dtj_NewStringNative(env, _dtrace_version)); 1831*1449Stomee } 1832*1449Stomee 1833*1449Stomee /* 1834*1449Stomee * Static LocalConsumer.java method 1835*1449Stomee * Protected by global lock (LocalConsumer.class) 1836*1449Stomee */ 1837*1449Stomee JNIEXPORT jstring JNICALL 1838*1449Stomee /* ARGSUSED */ 1839*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getExecutableName(JNIEnv *env, 1840*1449Stomee jclass class) 1841*1449Stomee { 1842*1449Stomee jstring jname = NULL; 1843*1449Stomee const char *name = NULL; 1844*1449Stomee char *s; 1845*1449Stomee int len; 1846*1449Stomee 1847*1449Stomee name = dtj_getexecname(); 1848*1449Stomee len = strlen(name); 1849*1449Stomee s = malloc(len + 1); 1850*1449Stomee if (!s) { 1851*1449Stomee dtj_throw_out_of_memory(env, "Failed to allocate execname"); 1852*1449Stomee return (NULL); 1853*1449Stomee } 1854*1449Stomee (void) strcpy(s, name); 1855*1449Stomee name = basename(s); 1856*1449Stomee free(s); 1857*1449Stomee jname = (*env)->NewStringUTF(env, name); 1858*1449Stomee return (jname); 1859*1449Stomee } 1860*1449Stomee 1861*1449Stomee /* 1862*1449Stomee * Static LocalConsumer.java method 1863*1449Stomee */ 1864*1449Stomee JNIEXPORT void JNICALL 1865*1449Stomee /* ARGSUSED */ 1866*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1setMaximumConsumers(JNIEnv *env, 1867*1449Stomee jclass class, jint max) 1868*1449Stomee { 1869*1449Stomee g_max_consumers = max; 1870*1449Stomee } 1871*1449Stomee 1872*1449Stomee /* 1873*1449Stomee * Static LocalConsumer.java method 1874*1449Stomee */ 1875*1449Stomee JNIEXPORT void JNICALL 1876*1449Stomee /* ARGSUSED */ 1877*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1setDebug(JNIEnv *env, 1878*1449Stomee jclass class, jboolean debug) 1879*1449Stomee { 1880*1449Stomee g_dtj_util_debug = debug; 1881*1449Stomee } 1882*1449Stomee 1883*1449Stomee JNIEXPORT void JNICALL 1884*1449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1destroy(JNIEnv *env, jobject obj) 1885*1449Stomee { 1886*1449Stomee dtj_consumer_t *c; 1887*1449Stomee 1888*1449Stomee c = dtj_remove_consumer(env, obj); 1889*1449Stomee if (c == NULL) { 1890*1449Stomee return; /* java exception pending */ 1891*1449Stomee } 1892*1449Stomee dtj_consumer_destroy(c); 1893*1449Stomee } 1894