11449Stomee /*
21449Stomee * CDDL HEADER START
31449Stomee *
41449Stomee * The contents of this file are subject to the terms of the
51449Stomee * Common Development and Distribution License (the "License").
61449Stomee * You may not use this file except in compliance with the License.
71449Stomee *
81449Stomee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91449Stomee * or http://www.opensolaris.org/os/licensing.
101449Stomee * See the License for the specific language governing permissions
111449Stomee * and limitations under the License.
121449Stomee *
131449Stomee * When distributing Covered Code, include this CDDL HEADER in each
141449Stomee * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151449Stomee * If applicable, add the following below this CDDL HEADER, with the
161449Stomee * fields enclosed by brackets "[]" replaced with your own identifying
171449Stomee * information: Portions Copyright [yyyy] [name of copyright owner]
181449Stomee *
191449Stomee * CDDL HEADER END
201449Stomee */
211449Stomee
221449Stomee /*
23*6136Stomee * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
241449Stomee * Use is subject to license terms.
251449Stomee */
261449Stomee
271449Stomee #pragma ident "%Z%%M% %I% %E% SMI"
281449Stomee
291449Stomee #include <stdio.h>
301449Stomee #include <errno.h>
311449Stomee #include <string.h>
321449Stomee #include <stdlib.h>
331449Stomee #include <unistd.h>
341449Stomee #include <libgen.h>
351449Stomee #include <assert.h>
361449Stomee #include <strings.h>
371449Stomee #include <libproc.h>
381449Stomee #include <pthread.h>
391449Stomee #include <dtrace_jni.h>
401449Stomee /* generated by javah */
411449Stomee #include <LocalConsumer.h>
421449Stomee
431449Stomee /*
441449Stomee * dtrace_jni.c defines all the native methods of the Java DTrace API. Every
451449Stomee * native method is declared in a single class, LocalConsumer.java.
461449Stomee *
471449Stomee * Notes:
481449Stomee *
491449Stomee * The data generating loop must explicitly release every object reference it
501449Stomee * obtains in order to avoid a memory leak. A local JNI object reference is not
511449Stomee * automatically released until control returns to java, which never happens as
521449Stomee * long as the data generating loop runs. This applies to any JNI function that
531449Stomee * obtains an object reference (such as CallObjectMethod() or NewObject()). A
541449Stomee * local reference is released by calling DeleteLocalRef(), which is safe to
551449Stomee * call with an exception pending.
561449Stomee *
571449Stomee * It is important to check for an exception after calling java code from native
581449Stomee * C, such as after notifying the java consumer of new data. Failure to do this
591449Stomee * makes it possible for users of the interface to crash the JVM by throwing an
601449Stomee * exception in java code.
611449Stomee *
621449Stomee * Some JNI functions, like GetIntField() or ReleaseStringUTFChars(), do not
631449Stomee * need to be checked for exceptions.
641449Stomee *
651449Stomee * GetStringUTFChars() returns NULL if and only if an exception was thrown.
661449Stomee *
671449Stomee * It is important to stop a DTrace consumer and remove it if an exception
681449Stomee * occurs. This API guarantees that a consumer is stopped automatically if it
691449Stomee * throws an exception. An application running multiple DTrace consumers
701449Stomee * simultaneously should be able to continue running the others normally if any
711449Stomee * fail.
721449Stomee *
731449Stomee * Calls to libdtrace are not guaranteed to be MT-safe. Even if they are
741449Stomee * currently MT-safe, they are not guaranteed to remain that way. To address
751449Stomee * this, a global lock (the LocalConsumer.class reference) is used around calls
761449Stomee * to libdtrace. In many cases, the locking is done in java, which should be
771449Stomee * indicated in this file by a comment above the function that assumes prior
781449Stomee * locking. To access the same global lock from native C code, the JNI function
791449Stomee * MonitorEnter() is used. Each MonitorEnter() must have a matching
801449Stomee * MonitorExit() or the application will hang (all consumer threads). The
811449Stomee * consumer loop and the getAggregate() method require a per-consumer lock
821449Stomee * rather than a global lock; in that case the argument to MonitorEnter() and
831449Stomee * MonitorExit() is the consumerLock member of the LocalConsumer, not the
841449Stomee * LocalConsumer itself.
851449Stomee */
861449Stomee
873645Stomee /*
883645Stomee * Increment the version whenever there is a change in the interface between
893645Stomee * Java and native code, whether from Java into native code:
903645Stomee * - LocalConsumer.h (generated by javah)
913645Stomee * or from native code back into Java:
923645Stomee * - dtj_table_load() in dtj_jnitab.c
933645Stomee * Changes to dtj_load_common() in dtj_util.c should not normally require a
943645Stomee * version update, since dtj_util.c defines classes in the JDK, not classes in
953645Stomee * the Java DTrace API.
963645Stomee *
973645Stomee * This version needs to match the version in LocalConsumer.java
983645Stomee */
99*6136Stomee #define DTRACE_JNI_VERSION 3
1001449Stomee
1011449Stomee #define FIRST_HANDLE 0 /* sequence-generated consumer ID */
1021449Stomee #define NO_HANDLE -1
1031449Stomee #define INITIAL_CAPACITY 8 /* initial size of consumer array */
1041449Stomee #define MAX_CAPACITY_INCREMENT 1024
1051449Stomee
1061449Stomee static boolean_t g_dtj_load = B_FALSE;
1071449Stomee static int g_handle_seq = NO_HANDLE;
1081449Stomee /*
1091449Stomee * key: caller's consumer handle (int)
1101449Stomee * value: per-consumer data includes dtrace handle (consumer_t *)
1111449Stomee */
1121449Stomee static dtj_consumer_t **g_consumer_table = NULL;
1131449Stomee static size_t g_consumer_capacity = 0;
1141449Stomee static size_t g_consumer_count = 0;
1151449Stomee static size_t g_max_capacity_increment = MAX_CAPACITY_INCREMENT;
1161449Stomee static size_t g_max_consumers = 0; /* no maximum */
1171449Stomee static boolean_t g_init = B_FALSE;
1181449Stomee static pthread_mutex_t g_table_lock;
1191449Stomee static pthread_mutexattr_t g_table_lock_attr;
1201449Stomee pthread_key_t g_dtj_consumer_key;
1211449Stomee
1221449Stomee static int dtj_get_handle(JNIEnv *, jobject);
1231449Stomee static dtj_status_t dtj_get_java_consumer(JNIEnv *, jobject,
1241449Stomee dtj_java_consumer_t *);
1251449Stomee static const char *dtj_getexecname(void);
1261449Stomee static jobject dtj_get_program_info(dtj_java_consumer_t *, dtrace_proginfo_t *);
1271449Stomee static jobject dtj_add_program(dtj_java_consumer_t *, dtj_program_t *);
1281449Stomee static void dtj_flag(uint_t *, uint_t, boolean_t *, boolean_t *);
1291449Stomee static boolean_t dtj_cflag(dtj_java_consumer_t *, const char *, boolean_t *,
1301449Stomee boolean_t *);
1311449Stomee static void dtj_list_probes(JNIEnv *, jobject, jobject, jobject,
1321449Stomee dtrace_probe_f *);
1331449Stomee static void dtj_list_compiled_probes(JNIEnv *, jobject, jobject, jobject,
1341449Stomee dtrace_probe_f *);
1351449Stomee static int dtj_list_probe(dtrace_hdl_t *, const dtrace_probedesc_t *, void *);
1361449Stomee static int dtj_list_probe_detail(dtrace_hdl_t *, const dtrace_probedesc_t *,
1371449Stomee void *);
1381449Stomee static int dtj_list_stmt(dtrace_hdl_t *, dtrace_prog_t *, dtrace_stmtdesc_t *,
1391449Stomee void *);
1401449Stomee static boolean_t dtj_add_consumer(JNIEnv *, dtj_consumer_t *, int *);
1411449Stomee static dtj_consumer_t *dtj_remove_consumer(JNIEnv *, jobject);
1421449Stomee static dtj_consumer_t *dtj_remove_consumer_at(int);
1431449Stomee
1441449Stomee /*
1451449Stomee * Gets a sequence-generated consumer ID, or NO_HANDLE if exception pending
1461449Stomee */
1471449Stomee static int
dtj_get_handle(JNIEnv * jenv,jobject caller)1481449Stomee dtj_get_handle(JNIEnv *jenv, jobject caller)
1491449Stomee {
1501449Stomee int handle;
1511449Stomee
1521449Stomee if (!g_dtj_load) {
1531449Stomee dtj_throw_illegal_state(jenv, "JNI table not loaded");
1541449Stomee return (NO_HANDLE);
1551449Stomee }
1561449Stomee handle = (*jenv)->CallIntMethod(jenv, caller, g_gethandle_jm);
1571449Stomee if ((*jenv)->ExceptionCheck(jenv)) {
1581449Stomee return (NO_HANDLE);
1591449Stomee }
1601449Stomee if (handle == NO_HANDLE) {
1611449Stomee dtj_throw_illegal_state(jenv, "no consumer handle");
1621449Stomee }
1631449Stomee return (handle);
1641449Stomee }
1651449Stomee
1661449Stomee /*
1671449Stomee * Populates the given java consumer created for use in the current native
1681449Stomee * method call. If the return value is DTJ_ERR, a java exception is pending.
1691449Stomee * Throws IllegalStateException if the caller does not have a valid handle.
1701449Stomee * Throws NoSuchElementException if the caller's handle is not in the global
1711449Stomee * caller table.
1721449Stomee */
1731449Stomee static dtj_status_t
dtj_get_java_consumer(JNIEnv * jenv,jobject caller,dtj_java_consumer_t * jc)1741449Stomee dtj_get_java_consumer(JNIEnv *jenv, jobject caller, dtj_java_consumer_t *jc)
1751449Stomee {
1761449Stomee dtj_consumer_t *consumer;
1771449Stomee int handle = dtj_get_handle(jenv, caller);
1781449Stomee if (handle == NO_HANDLE) {
1791449Stomee return (DTJ_ERR); /* java exception pending */
1801449Stomee }
1811449Stomee (void) pthread_mutex_lock(&g_table_lock);
1821449Stomee if (g_consumer_table) {
1831449Stomee if ((handle >= 0) && (handle < g_consumer_capacity)) {
1841449Stomee consumer = g_consumer_table[handle];
1851449Stomee } else {
1861449Stomee consumer = NULL;
1871449Stomee }
1881449Stomee } else {
1891449Stomee consumer = NULL;
1901449Stomee }
1911449Stomee (void) pthread_mutex_unlock(&g_table_lock);
1921449Stomee if (consumer == NULL) {
1931449Stomee dtj_throw_no_such_element(jenv, "consumer handle %d", handle);
1941449Stomee return (DTJ_ERR);
1951449Stomee }
1961449Stomee
1971449Stomee /* Initialize java consumer */
1981449Stomee bzero(jc, sizeof (dtj_java_consumer_t));
1991449Stomee
2001449Stomee /* Attach per-consumer data */
2011449Stomee jc->dtjj_consumer = consumer;
2021449Stomee
2031449Stomee /* Attach per-JNI-invocation data */
2041449Stomee jc->dtjj_caller = caller;
2051449Stomee jc->dtjj_jenv = jenv;
2061449Stomee
2071449Stomee return (DTJ_OK);
2081449Stomee }
2091449Stomee
2101449Stomee /*
2111449Stomee * Adds a consumer to the global consumer table.
2121449Stomee * Returns B_TRUE if successful; a java exception is pending otherwise.
2131449Stomee * Postcondition: if successful, g_handle_seq is the handle of the consumer just
2141449Stomee * added.
2151449Stomee */
2161449Stomee static boolean_t
dtj_add_consumer(JNIEnv * jenv,dtj_consumer_t * c,int * seq)2171449Stomee dtj_add_consumer(JNIEnv *jenv, dtj_consumer_t *c, int *seq)
2181449Stomee {
2191449Stomee int start;
2201449Stomee
2211449Stomee if (!g_init) {
2221449Stomee (void) pthread_key_create(&g_dtj_consumer_key, NULL);
2231449Stomee (void) pthread_mutexattr_init(&g_table_lock_attr);
2241449Stomee (void) pthread_mutexattr_settype(&g_table_lock_attr,
2251449Stomee PTHREAD_MUTEX_RECURSIVE);
2261449Stomee (void) pthread_mutex_init(&g_table_lock,
2271449Stomee &g_table_lock_attr);
2281449Stomee g_init = B_TRUE;
2291449Stomee }
2301449Stomee
2311449Stomee *seq = NO_HANDLE;
2321449Stomee (void) pthread_mutex_lock(&g_table_lock);
2331449Stomee if (g_consumer_table == NULL) {
2341449Stomee g_consumer_table = malloc(INITIAL_CAPACITY *
2351449Stomee sizeof (dtj_consumer_t *));
2361449Stomee if (!g_consumer_table) {
2371449Stomee g_handle_seq = NO_HANDLE;
2381449Stomee dtj_throw_out_of_memory(jenv,
2391449Stomee "could not allocate consumer table");
2401449Stomee (void) pthread_mutex_unlock(&g_table_lock);
2411449Stomee return (B_FALSE);
2421449Stomee }
2431449Stomee bzero(g_consumer_table, (INITIAL_CAPACITY *
2441449Stomee sizeof (dtj_consumer_t *)));
2451449Stomee g_consumer_capacity = INITIAL_CAPACITY;
2463350Stomee } else if ((g_max_consumers > 0) && (g_consumer_count >=
2473350Stomee g_max_consumers)) {
2483350Stomee dtj_throw_resource_limit(jenv, "Too many consumers");
2493350Stomee (void) pthread_mutex_unlock(&g_table_lock);
2503350Stomee return (B_FALSE);
2511449Stomee } else if (g_consumer_count >= g_consumer_capacity) {
2521449Stomee dtj_consumer_t **t;
2531449Stomee size_t new_capacity;
2541449Stomee
2551449Stomee if (g_consumer_capacity <= g_max_capacity_increment) {
2561449Stomee new_capacity = (g_consumer_capacity * 2);
2571449Stomee } else {
2581449Stomee new_capacity = (g_consumer_capacity +
2591449Stomee g_max_capacity_increment);
2601449Stomee }
2611449Stomee
2621449Stomee if ((g_max_consumers > 0) && (new_capacity > g_max_consumers)) {
2631449Stomee new_capacity = g_max_consumers;
2641449Stomee }
2651449Stomee
2661449Stomee t = realloc(g_consumer_table,
2671449Stomee new_capacity * sizeof (dtj_consumer_t *));
2681449Stomee if (!t) {
2691449Stomee dtj_throw_out_of_memory(jenv,
2701449Stomee "could not reallocate consumer table");
2711449Stomee (void) pthread_mutex_unlock(&g_table_lock);
2721449Stomee return (B_FALSE);
2731449Stomee }
2741449Stomee
2751449Stomee g_consumer_table = t;
2761449Stomee bzero(g_consumer_table + g_consumer_capacity, ((new_capacity -
2771449Stomee g_consumer_capacity) * sizeof (dtj_consumer_t *)));
2781449Stomee g_consumer_capacity = new_capacity;
2791449Stomee }
2801449Stomee
2811449Stomee /* Look for an empty slot in the table */
2821449Stomee g_handle_seq = (g_handle_seq == NO_HANDLE
2831449Stomee ? FIRST_HANDLE : g_handle_seq + 1);
2841449Stomee if (g_handle_seq >= g_consumer_capacity) {
2851449Stomee g_handle_seq = FIRST_HANDLE;
2861449Stomee }
2871449Stomee start = g_handle_seq; /* guard against infinite loop */
2881449Stomee while (g_consumer_table[g_handle_seq] != NULL) {
2891449Stomee ++g_handle_seq;
2901449Stomee if (g_handle_seq == start) {
2911449Stomee dtj_throw_illegal_state(jenv, "consumer table full,"
2921449Stomee " but count %d < capacity %d",
2931449Stomee g_consumer_count, g_consumer_capacity);
2941449Stomee (void) pthread_mutex_unlock(&g_table_lock);
2951449Stomee return (B_FALSE);
2961449Stomee } else if (g_handle_seq >= g_consumer_capacity) {
2971449Stomee g_handle_seq = FIRST_HANDLE;
2981449Stomee }
2991449Stomee }
3001449Stomee g_consumer_table[g_handle_seq] = c;
3011449Stomee *seq = g_handle_seq;
3021449Stomee ++g_consumer_count;
3031449Stomee (void) pthread_mutex_unlock(&g_table_lock);
3041449Stomee return (B_TRUE);
3051449Stomee }
3061449Stomee
3071449Stomee /*
3081449Stomee * Removes a consumer from the global consumer table. The call may be initiated
3091449Stomee * from Java code or from native code (because an exception has occurred).
3101449Stomee * Precondition: no exception pending (any pending exception must be temporarily
3111449Stomee * cleared)
3121449Stomee * Returns NULL if the caller is not in the table or if this function throws an
3131449Stomee * exception; either case leaves the global consumer table unchanged.
3141449Stomee * Throws IllegalStateException if the caller does not have a valid handle.
3151449Stomee */
3161449Stomee static dtj_consumer_t *
dtj_remove_consumer(JNIEnv * jenv,jobject caller)3171449Stomee dtj_remove_consumer(JNIEnv *jenv, jobject caller)
3181449Stomee {
3191449Stomee dtj_consumer_t *consumer;
3201449Stomee int handle = dtj_get_handle(jenv, caller);
3211449Stomee if (handle == NO_HANDLE) {
3221449Stomee return (NULL); /* java exception pending */
3231449Stomee }
3241449Stomee consumer = dtj_remove_consumer_at(handle);
3251449Stomee return (consumer);
3261449Stomee }
3271449Stomee
3281449Stomee /*
3291449Stomee * Returns NULL if there is no consumer with the given handle. Does not throw
3301449Stomee * exceptions.
3311449Stomee */
3321449Stomee static dtj_consumer_t *
dtj_remove_consumer_at(int handle)3331449Stomee dtj_remove_consumer_at(int handle)
3341449Stomee {
3351449Stomee dtj_consumer_t *consumer;
3361449Stomee (void) pthread_mutex_lock(&g_table_lock);
3371449Stomee if (g_consumer_table) {
3381449Stomee if ((handle >= 0) && (handle < g_consumer_capacity)) {
3391449Stomee consumer = g_consumer_table[handle];
3401449Stomee if (consumer != NULL) {
3411449Stomee g_consumer_table[handle] = NULL;
3421449Stomee --g_consumer_count;
3431449Stomee if (g_consumer_count == 0) {
3441449Stomee free(g_consumer_table);
3451449Stomee g_consumer_table = NULL;
3461449Stomee g_consumer_capacity = 0;
3471449Stomee g_handle_seq = NO_HANDLE;
3481449Stomee }
3491449Stomee }
3501449Stomee } else {
3511449Stomee consumer = NULL;
3521449Stomee }
3531449Stomee } else {
3541449Stomee consumer = NULL;
3551449Stomee }
3561449Stomee (void) pthread_mutex_unlock(&g_table_lock);
3571449Stomee return (consumer);
3581449Stomee }
3591449Stomee
3601449Stomee /*
3611449Stomee * Gets the name of the executable in case it is an application with an embedded
3621449Stomee * JVM and not "java". Implementation is copied from lib/mpss/common/mpss.c.
3631449Stomee * The use of static auxv_t makes the MT-level unsafe. The caller is expected
3641449Stomee * to use the global lock (LocalConsumer.class).
3651449Stomee */
3661449Stomee static const char *
dtj_getexecname(void)3671449Stomee dtj_getexecname(void)
3681449Stomee {
3691449Stomee const char *execname = NULL;
3701449Stomee static auxv_t auxb;
3711449Stomee
3721449Stomee /*
3731449Stomee * The first time through, read the initial aux vector that was
3741449Stomee * passed to the process at exec(2). Only do this once.
3751449Stomee */
3761449Stomee int fd = open("/proc/self/auxv", O_RDONLY);
3771449Stomee
3781449Stomee if (fd >= 0) {
3791449Stomee while (read(fd, &auxb, sizeof (auxv_t)) == sizeof (auxv_t)) {
3801449Stomee if (auxb.a_type == AT_SUN_EXECNAME) {
3811449Stomee execname = auxb.a_un.a_ptr;
3821449Stomee break;
3831449Stomee }
3841449Stomee }
3851449Stomee (void) close(fd);
3861449Stomee }
3871449Stomee return (execname);
3881449Stomee }
3891449Stomee
3901449Stomee /*
3911449Stomee * Add the compiled program to a list of programs the API expects to enable.
3921449Stomee * Returns the Program instance identifying the listed program, or NULL if the
3931449Stomee * Program constructor fails (exception pending in that case).
3941449Stomee */
3951449Stomee static jobject
dtj_add_program(dtj_java_consumer_t * jc,dtj_program_t * p)3961449Stomee dtj_add_program(dtj_java_consumer_t *jc, dtj_program_t *p)
3971449Stomee {
3981449Stomee JNIEnv *jenv = jc->dtjj_jenv;
3991449Stomee
4001449Stomee jobject jprogram = NULL;
4011449Stomee
4021449Stomee switch (p->dtjp_type) {
403*6136Stomee case DTJ_PROGRAM_STRING:
4041449Stomee jprogram = (*jenv)->NewObject(jenv, g_program_jc,
4051449Stomee g_proginit_jm);
4061449Stomee break;
407*6136Stomee case DTJ_PROGRAM_FILE:
4081449Stomee jprogram = (*jenv)->NewObject(jenv, g_programfile_jc,
4091449Stomee g_fproginit_jm);
4101449Stomee break;
411*6136Stomee default:
4121449Stomee dtj_throw_illegal_argument(jenv, "unexpected program type %d\n",
4131449Stomee p->dtjp_type);
4141449Stomee }
4151449Stomee if ((*jenv)->ExceptionCheck(jenv)) {
4161449Stomee return (NULL);
4171449Stomee }
4181449Stomee
4191449Stomee /* Does not throw exceptions */
4201449Stomee (*jenv)->SetIntField(jenv, jprogram, g_progid_jf,
4211449Stomee uu_list_numnodes(jc->dtjj_consumer->dtjc_program_list));
4221449Stomee
4231449Stomee if (!dtj_list_add(jc->dtjj_consumer->dtjc_program_list, p)) {
4241449Stomee (*jenv)->DeleteLocalRef(jenv, jprogram);
4251449Stomee dtj_throw_out_of_memory(jenv,
4261449Stomee "could not add program");
4271449Stomee return (NULL);
4281449Stomee }
4291449Stomee
4301449Stomee return (jprogram);
4311449Stomee }
4321449Stomee
4331449Stomee /*
4341449Stomee * Returns a new ProgramInfo, or NULL if the constructor fails (java exception
4351449Stomee * pending in that case).
4361449Stomee */
4371449Stomee static jobject
dtj_get_program_info(dtj_java_consumer_t * jc,dtrace_proginfo_t * pinfo)4381449Stomee dtj_get_program_info(dtj_java_consumer_t *jc, dtrace_proginfo_t *pinfo)
4391449Stomee {
4401449Stomee JNIEnv *jenv = jc->dtjj_jenv;
4411449Stomee
4421449Stomee jobject minProbeAttributes = NULL;
4431449Stomee jobject minStatementAttributes = NULL;
4441449Stomee jobject programInfo = NULL; /* return value */
4451449Stomee
4461449Stomee minProbeAttributes = dtj_new_attribute(jc, &pinfo->dpi_descattr);
4471449Stomee if (!minProbeAttributes) {
4481449Stomee return (NULL); /* java exception pending */
4491449Stomee }
4501449Stomee minStatementAttributes = dtj_new_attribute(jc, &pinfo->dpi_stmtattr);
4511449Stomee if (!minStatementAttributes) {
4521449Stomee (*jenv)->DeleteLocalRef(jenv, minProbeAttributes);
4531449Stomee return (NULL); /* java exception pending */
4541449Stomee }
4551449Stomee
4561449Stomee programInfo = (*jenv)->NewObject(jenv, g_proginfo_jc,
4571449Stomee g_proginfoinit_jm, minProbeAttributes, minStatementAttributes,
4581449Stomee pinfo->dpi_matches);
4591449Stomee (*jenv)->DeleteLocalRef(jenv, minProbeAttributes);
4601449Stomee (*jenv)->DeleteLocalRef(jenv, minStatementAttributes);
4611449Stomee
4621449Stomee return (programInfo);
4631449Stomee }
4641449Stomee
4651449Stomee /*
4661449Stomee * Called by LocalConsumer static initializer.
4671449Stomee */
4681449Stomee JNIEXPORT void JNICALL
4691449Stomee /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1checkVersion(JNIEnv * env,jclass class,jint version)4701449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1checkVersion(JNIEnv *env,
4711449Stomee jclass class, jint version)
4721449Stomee {
4731449Stomee if (version != DTRACE_JNI_VERSION) {
4741449Stomee dtj_throw_illegal_state(env,
4751449Stomee "LocalConsumer version %d incompatible with native "
4761449Stomee "implementation version %d", version, DTRACE_JNI_VERSION);
4771449Stomee }
4781449Stomee }
4791449Stomee
4801449Stomee /*
4811449Stomee * Called by LocalConsumer static initializer.
4821449Stomee */
4831449Stomee JNIEXPORT void JNICALL
4841449Stomee /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1loadJniTable(JNIEnv * env,jclass class)4851449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1loadJniTable(JNIEnv *env,
4861449Stomee jclass class)
4871449Stomee {
4881449Stomee if (g_dtj_load) {
4891449Stomee /*
4901449Stomee * JNI table includes a global reference to the LocalConsumer
4911449Stomee * class, preventing the class from being unloaded. The
4921449Stomee * LocalConsumer static initializer should never execute more
4931449Stomee * than once.
4941449Stomee */
4951449Stomee dtj_throw_illegal_state(env, "JNI table already loaded");
4961449Stomee return;
4971449Stomee }
4981449Stomee
4991449Stomee /* If this fails, a Java Error (e.g. NoSuchMethodError) is pending */
5001449Stomee if (dtj_load(env) == DTJ_OK) {
5011449Stomee g_dtj_load = B_TRUE;
5021449Stomee }
5031449Stomee }
5041449Stomee
5051449Stomee /*
5061449Stomee * Protected by global lock (LocalConsumer.class)
5071449Stomee */
5081449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1open(JNIEnv * env,jobject obj,jobjectArray flags)5091449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1open(JNIEnv *env, jobject obj,
5101449Stomee jobjectArray flags)
5111449Stomee {
5121449Stomee dtrace_hdl_t *dtp;
5131449Stomee dtj_consumer_t *c;
5141449Stomee const char *f; /* flag name */
5151449Stomee int oflags = 0;
5161449Stomee int i, len;
5171449Stomee int id;
5181449Stomee int err;
5191449Stomee
5201449Stomee jobject flag = NULL;
5211449Stomee jstring flagname = NULL;
5221449Stomee
5231449Stomee if (!g_dtj_load) {
5241449Stomee dtj_throw_illegal_state(env, "JNI table not loaded");
5251449Stomee return;
5261449Stomee }
5271449Stomee
5281449Stomee c = dtj_consumer_create(env);
5291449Stomee if (!c) {
5301449Stomee return; /* java exception pending */
5311449Stomee }
5321449Stomee
5331449Stomee /* Get open flags */
5341449Stomee len = (flags ? (*env)->GetArrayLength(env, flags) : 0);
5351449Stomee for (i = 0; i < len; ++i) {
5361449Stomee flag = (*env)->GetObjectArrayElement(env, flags, i);
5371449Stomee if ((*env)->ExceptionCheck(env)) {
5381449Stomee dtj_consumer_destroy(c);
5391449Stomee return;
5401449Stomee }
5411449Stomee
5421449Stomee flagname = (*env)->CallObjectMethod(env, flag, g_enumname_jm);
5431449Stomee (*env)->DeleteLocalRef(env, flag);
5441449Stomee if ((*env)->ExceptionCheck(env)) {
5451449Stomee dtj_consumer_destroy(c);
5461449Stomee return;
5471449Stomee }
5481449Stomee f = (*env)->GetStringUTFChars(env, flagname, NULL);
5491449Stomee if ((*env)->ExceptionCheck(env)) {
5501449Stomee (*env)->DeleteLocalRef(env, flagname);
5511449Stomee dtj_consumer_destroy(c);
5521449Stomee return;
5531449Stomee }
5541449Stomee if (strcmp(f, "ILP32") == 0) {
5551449Stomee oflags |= DTRACE_O_ILP32;
5561449Stomee } else if (strcmp(f, "LP64") == 0) {
5571449Stomee oflags |= DTRACE_O_LP64;
5581449Stomee }
5591449Stomee (*env)->ReleaseStringUTFChars(env, flagname, f);
5601449Stomee (*env)->DeleteLocalRef(env, flagname);
5611449Stomee }
5621449Stomee
5631449Stomee /* Check for mutually exclusive flags */
5641449Stomee if ((oflags & DTRACE_O_ILP32) && (oflags & DTRACE_O_LP64)) {
5651449Stomee dtj_throw_illegal_argument(env,
5661449Stomee "Cannot set both ILP32 and LP64");
5671449Stomee dtj_consumer_destroy(c);
5681449Stomee return;
5691449Stomee }
5701449Stomee
5711449Stomee /*
5721449Stomee * Make sure we can add the consumer before calling dtrace_open().
5731449Stomee * Repeated calls to open() when the consumer table is maxed out should
5741449Stomee * avoid calling dtrace_open(). (Normally there is no limit to the size
5751449Stomee * of the consumer table, but the undocumented JAVA_DTRACE_MAX_CONSUMERS
5761449Stomee * system property lets you set a limit after which
5771449Stomee * ResourceLimitException is thrown.)
5781449Stomee */
5791449Stomee if (!dtj_add_consumer(env, c, &id)) {
5801449Stomee dtj_consumer_destroy(c);
5811449Stomee return; /* java exception pending */
5821449Stomee }
5831449Stomee
5841449Stomee (*env)->CallVoidMethod(env, obj, g_sethandle_jm, id);
5851449Stomee if ((*env)->ExceptionCheck(env)) {
5861449Stomee (void) dtj_remove_consumer_at(id);
5871449Stomee dtj_consumer_destroy(c);
5881449Stomee return;
5891449Stomee }
5901449Stomee
5911449Stomee if ((dtp = dtrace_open(DTRACE_VERSION, oflags, &err)) == NULL) {
5921449Stomee dtj_java_consumer_t jc;
5931449Stomee jc.dtjj_jenv = env;
5941449Stomee dtj_throw_dtrace_exception(&jc, dtrace_errmsg(NULL, err));
5951449Stomee (void) dtj_remove_consumer_at(id);
5961449Stomee dtj_consumer_destroy(c);
5971449Stomee return;
5981449Stomee }
5991449Stomee c->dtjc_dtp = dtp; /* set consumer handle to native DTrace library */
6001449Stomee }
6011449Stomee
6021449Stomee static void
dtj_flag(uint_t * flags,uint_t flag,boolean_t * get,boolean_t * set)6031449Stomee dtj_flag(uint_t *flags, uint_t flag, boolean_t *get, boolean_t *set)
6041449Stomee {
6051449Stomee assert((get && !set) || (set && !get));
6061449Stomee
6071449Stomee if (get) {
6081449Stomee *get = (*flags & flag);
6091449Stomee } else {
6101449Stomee if (*set) {
6111449Stomee *flags |= flag;
6121449Stomee } else {
6131449Stomee *flags &= ~flag;
6141449Stomee }
6151449Stomee }
6161449Stomee }
6171449Stomee
6181449Stomee /*
6191449Stomee * Returns B_TRUE if opt is a recognized compile flag, B_FALSE otherwise.
6201449Stomee */
6211449Stomee static boolean_t
dtj_cflag(dtj_java_consumer_t * jc,const char * opt,boolean_t * get,boolean_t * set)6221449Stomee dtj_cflag(dtj_java_consumer_t *jc, const char *opt, boolean_t *get,
6231449Stomee boolean_t *set)
6241449Stomee {
6251449Stomee boolean_t is_cflag = B_TRUE;
6261449Stomee uint_t *flags = &jc->dtjj_consumer->dtjc_cflags;
6271449Stomee
628*6136Stomee /* see lib/libdtrace/common/dt_options.c */
6291449Stomee if (strcmp(opt, "argref") == 0) {
6301449Stomee dtj_flag(flags, DTRACE_C_ARGREF, get, set);
6311449Stomee } else if (strcmp(opt, "cpp") == 0) {
6321449Stomee dtj_flag(flags, DTRACE_C_CPP, get, set);
6331449Stomee } else if (strcmp(opt, "defaultargs") == 0) {
6341449Stomee dtj_flag(flags, DTRACE_C_DEFARG, get, set);
6351449Stomee } else if (strcmp(opt, "empty") == 0) {
6361449Stomee dtj_flag(flags, DTRACE_C_EMPTY, get, set);
6371449Stomee } else if (strcmp(opt, "errtags") == 0) {
6381449Stomee dtj_flag(flags, DTRACE_C_ETAGS, get, set);
6391449Stomee } else if (strcmp(opt, "knodefs") == 0) {
6401449Stomee dtj_flag(flags, DTRACE_C_KNODEF, get, set);
6411449Stomee } else if (strcmp(opt, "nolibs") == 0) {
6421449Stomee dtj_flag(flags, DTRACE_C_NOLIBS, get, set);
6431449Stomee } else if (strcmp(opt, "pspec") == 0) {
6441449Stomee dtj_flag(flags, DTRACE_C_PSPEC, get, set);
6451449Stomee } else if (strcmp(opt, "unodefs") == 0) {
6461449Stomee dtj_flag(flags, DTRACE_C_UNODEF, get, set);
6471449Stomee } else if (strcmp(opt, "verbose") == 0) {
6481449Stomee dtj_flag(flags, DTRACE_C_DIFV, get, set);
6491449Stomee } else if (strcmp(opt, "zdefs") == 0) {
6501449Stomee dtj_flag(flags, DTRACE_C_ZDEFS, get, set);
6511449Stomee } else {
6521449Stomee is_cflag = B_FALSE;
6531449Stomee }
6541449Stomee
6551449Stomee if (is_cflag && set &&
6561449Stomee (jc->dtjj_consumer->dtjc_state != DTJ_CONSUMER_INIT)) {
6571449Stomee dtj_throw_illegal_state(jc->dtjj_jenv,
6581449Stomee "cannot set compile time option \"%s\" after calling go()",
6591449Stomee opt);
6601449Stomee return (is_cflag);
6611449Stomee }
6621449Stomee
6631449Stomee return (is_cflag);
6641449Stomee }
6651449Stomee
6661449Stomee /*
6671449Stomee * Protected by global lock (LocalConsumer.class)
6681449Stomee */
6691449Stomee JNIEXPORT jobject JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1compileString(JNIEnv * env,jobject obj,jstring program,jobjectArray args)6701449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1compileString(JNIEnv *env,
6711449Stomee jobject obj, jstring program, jobjectArray args)
6721449Stomee {
6731449Stomee const char *prog;
6741449Stomee dtj_java_consumer_t jc;
6751449Stomee dtrace_hdl_t *dtp;
6761449Stomee dtj_program_t *p;
6771449Stomee int argc = 0;
6781449Stomee char **argv = NULL;
6791449Stomee
6801449Stomee jstring jprogram = NULL;
6811449Stomee
6821449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
6831449Stomee return (NULL); /* java exception pending */
6841449Stomee }
6851449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
6861449Stomee
6871449Stomee prog = (*env)->GetStringUTFChars(env, program, 0);
6881449Stomee if ((*env)->ExceptionCheck(env)) {
6891449Stomee return (NULL);
6901449Stomee }
6911449Stomee
6921449Stomee p = dtj_program_create(env, DTJ_PROGRAM_STRING, prog);
6931449Stomee if (!p) {
6941449Stomee (*env)->ReleaseStringUTFChars(env, program, prog);
6951449Stomee return (NULL); /* java exception pending */
6961449Stomee }
6971449Stomee
6981449Stomee if (args) {
6991449Stomee argv = dtj_get_argv(env, args, &argc);
7001449Stomee if ((*env)->ExceptionCheck(env)) {
7011449Stomee (*env)->ReleaseStringUTFChars(env, program, prog);
7021449Stomee dtj_program_destroy(p, NULL);
7031449Stomee return (NULL);
7041449Stomee }
7051449Stomee }
7061449Stomee
7071449Stomee if ((p->dtjp_program = dtrace_program_strcompile(dtp,
7081449Stomee prog, DTRACE_PROBESPEC_NAME, jc.dtjj_consumer->dtjc_cflags,
7091449Stomee argc, argv)) == NULL) {
7101449Stomee dtj_throw_dtrace_exception(&jc,
7111449Stomee "invalid probe specifier %s: %s",
7121449Stomee prog, dtrace_errmsg(dtp, dtrace_errno(dtp)));
7131449Stomee (*env)->ReleaseStringUTFChars(env, program, prog);
7141449Stomee dtj_program_destroy(p, NULL);
7151449Stomee dtj_free_argv(argv);
7161449Stomee return (NULL);
7171449Stomee }
7181449Stomee (*env)->ReleaseStringUTFChars(env, program, prog);
7191449Stomee dtj_free_argv(argv);
7201449Stomee
7211449Stomee jprogram = dtj_add_program(&jc, p);
7221449Stomee return (jprogram); /* NULL if exception pending */
7231449Stomee }
7241449Stomee
7251449Stomee /*
7261449Stomee * Protected by global lock (LocalConsumer.class)
7271449Stomee */
7281449Stomee JNIEXPORT jobject JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1compileFile(JNIEnv * env,jobject obj,jstring filename,jobjectArray args)7291449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1compileFile(JNIEnv *env,
7301449Stomee jobject obj, jstring filename, jobjectArray args)
7311449Stomee {
7321449Stomee FILE *fp;
7331449Stomee const char *file;
7341449Stomee dtj_java_consumer_t jc;
7351449Stomee dtrace_hdl_t *dtp;
7361449Stomee dtj_program_t *p;
7371449Stomee int argc = 0;
7381449Stomee char **argv = NULL;
7391449Stomee
7401449Stomee jstring jprogram = NULL;
7411449Stomee
7421449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
7431449Stomee return (NULL); /* java exception pending */
7441449Stomee }
7451449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
7461449Stomee
7471449Stomee file = dtj_GetStringNativeChars(env, filename);
7481449Stomee if ((fp = fopen(file, "r")) == NULL) {
7491449Stomee dtj_throw_dtrace_exception(&jc, "failed to open %s", file);
7501449Stomee dtj_ReleaseStringNativeChars(env, filename, file);
7511449Stomee return (NULL);
7521449Stomee }
7531449Stomee
7541449Stomee p = dtj_program_create(env, DTJ_PROGRAM_FILE, file);
7551449Stomee if (!p) {
7561449Stomee (void) fclose(fp);
7571449Stomee dtj_ReleaseStringNativeChars(env, filename, file);
7581449Stomee return (NULL); /* java exception pending */
7591449Stomee }
7601449Stomee
7611449Stomee if (args) {
7621449Stomee argv = dtj_get_argv(env, args, &argc);
7631449Stomee if ((*env)->ExceptionCheck(env)) {
7641449Stomee (void) fclose(fp);
7651449Stomee dtj_ReleaseStringNativeChars(env, filename, file);
7661449Stomee dtj_program_destroy(p, NULL);
7671449Stomee return (NULL);
7681449Stomee }
7691449Stomee }
7701449Stomee
7711449Stomee if ((p->dtjp_program = dtrace_program_fcompile(dtp,
7721449Stomee fp, jc.dtjj_consumer->dtjc_cflags, argc, argv)) == NULL) {
7731449Stomee dtj_throw_dtrace_exception(&jc,
7741449Stomee "failed to compile script %s: %s", file,
7751449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp)));
7761449Stomee (void) fclose(fp);
7771449Stomee dtj_ReleaseStringNativeChars(env, filename, file);
7781449Stomee dtj_program_destroy(p, NULL);
7791449Stomee dtj_free_argv(argv);
7801449Stomee return (NULL);
7811449Stomee }
7821449Stomee (void) fclose(fp);
7831449Stomee dtj_ReleaseStringNativeChars(env, filename, file);
7841449Stomee dtj_free_argv(argv);
7851449Stomee
7861449Stomee jprogram = dtj_add_program(&jc, p);
7871449Stomee return (jprogram); /* NULL if exception pending */
7881449Stomee }
7891449Stomee
7901449Stomee /*
7911449Stomee * Protected by global lock (LocalConsumer.class)
7921449Stomee */
7931449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1exec(JNIEnv * env,jobject obj,jobject program)7941449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1exec(JNIEnv *env, jobject obj,
7951449Stomee jobject program)
7961449Stomee {
7971449Stomee dtj_java_consumer_t jc;
7981449Stomee dtrace_hdl_t *dtp;
7991449Stomee int progid = -1;
8001449Stomee uu_list_walk_t *itr;
8011449Stomee dtj_program_t *p;
8021449Stomee dtrace_proginfo_t *pinfo = NULL;
8031449Stomee int i;
8041449Stomee
8051449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
8061449Stomee return; /* java exception pending */
8071449Stomee }
8081449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
8091449Stomee
8101449Stomee if (program) {
8111449Stomee progid = (*env)->GetIntField(env, program, g_progid_jf);
8121449Stomee }
8131449Stomee
8141449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
8151449Stomee dtj_throw_illegal_state(env, "no program compiled");
8161449Stomee return;
8171449Stomee }
8181449Stomee
8191449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
8201449Stomee for (i = 0; (p = uu_list_walk_next(itr)) != NULL; ++i) {
8211449Stomee /* enable all probes or those of given program only */
8221449Stomee if ((progid != -1) && (progid != i)) {
8231449Stomee continue;
8241449Stomee }
8251449Stomee
8261449Stomee if (p->dtjp_enabled) {
8271449Stomee dtj_throw_illegal_state(env, "program already enabled");
8281449Stomee uu_list_walk_end(itr);
8291449Stomee return;
8301449Stomee }
8311449Stomee
8321449Stomee pinfo = &p->dtjp_info;
8331449Stomee if (dtrace_program_exec(dtp, p->dtjp_program, pinfo) == -1) {
8341449Stomee dtj_throw_dtrace_exception(&jc,
8351449Stomee "failed to enable %s: %s", p->dtjp_name,
8361449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp)));
8371449Stomee uu_list_walk_end(itr);
8381449Stomee return;
8391449Stomee }
8401449Stomee p->dtjp_enabled = B_TRUE;
8411449Stomee }
8421449Stomee uu_list_walk_end(itr);
8431449Stomee
8441449Stomee if (program) {
8451449Stomee jobject programInfo = NULL;
8461449Stomee
8471449Stomee if (!pinfo) {
8481449Stomee /*
8491449Stomee * Consumer.enable() has already checked that the
8501449Stomee * program was compiled by this consumer. This is an
8511449Stomee * implementation error, not a user error.
8521449Stomee */
8531449Stomee dtj_throw_illegal_state(env, "program not found");
8541449Stomee return;
8551449Stomee }
8561449Stomee
8571449Stomee programInfo = dtj_get_program_info(&jc, pinfo);
8581449Stomee if (!programInfo) {
8591449Stomee return; /* java exception pending */
8601449Stomee }
8611449Stomee
8621449Stomee (*env)->SetObjectField(env, program, g_proginfo_jf,
8631449Stomee programInfo);
8641449Stomee (*env)->DeleteLocalRef(env, programInfo);
8651449Stomee }
8661449Stomee }
8671449Stomee
8681449Stomee /*
8691449Stomee * Protected by global lock (LocalConsumer.class)
8701449Stomee */
8711449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1getProgramInfo(JNIEnv * env,jobject obj,jobject program)8721449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getProgramInfo(JNIEnv *env,
8731449Stomee jobject obj, jobject program)
8741449Stomee {
8751449Stomee dtj_java_consumer_t jc;
8761449Stomee dtrace_hdl_t *dtp;
8771449Stomee int progid;
8781449Stomee uu_list_walk_t *itr;
8791449Stomee dtj_program_t *p;
8801449Stomee dtrace_proginfo_t *pinfo = NULL;
8811449Stomee int i;
8821449Stomee
8831449Stomee jobject programInfo = NULL;
8841449Stomee
8851449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
8861449Stomee return; /* java exception pending */
8871449Stomee }
8881449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
8891449Stomee
8901449Stomee progid = (*env)->GetIntField(env, program, g_progid_jf);
8911449Stomee
8921449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
8931449Stomee dtj_throw_illegal_state(env, "no program compiled");
8941449Stomee return;
8951449Stomee }
8961449Stomee
8971449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
8981449Stomee for (i = 0; ((p = uu_list_walk_next(itr)) != NULL) && !pinfo; ++i) {
8991449Stomee if (progid != i) {
9001449Stomee /* get info of given program only */
9011449Stomee continue;
9021449Stomee }
9031449Stomee
9041449Stomee pinfo = &p->dtjp_info;
9051449Stomee dtrace_program_info(dtp, p->dtjp_program, pinfo);
9061449Stomee }
9071449Stomee uu_list_walk_end(itr);
9081449Stomee
9091449Stomee programInfo = dtj_get_program_info(&jc, pinfo);
9101449Stomee if (!programInfo) {
9111449Stomee return; /* java exception pending */
9121449Stomee }
9131449Stomee
9141449Stomee (*env)->SetObjectField(env, program, g_proginfo_jf,
9151449Stomee programInfo);
9161449Stomee (*env)->DeleteLocalRef(env, programInfo);
9171449Stomee }
9181449Stomee
9191449Stomee /*
9201449Stomee * Protected by global lock (LocalConsumer.class)
9211449Stomee */
9221449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1setOption(JNIEnv * env,jobject obj,jstring option,jstring value)9231449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1setOption(JNIEnv *env,
9241449Stomee jobject obj, jstring option, jstring value)
9251449Stomee {
9261449Stomee dtj_java_consumer_t jc;
9271449Stomee const char *opt;
9281449Stomee const char *val;
9291449Stomee boolean_t on;
9301449Stomee
9311449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
9321449Stomee return; /* java exception pending */
9331449Stomee }
9341449Stomee
9351449Stomee opt = (*env)->GetStringUTFChars(env, option, 0);
9361449Stomee if (!opt) {
9371449Stomee dtj_throw_out_of_memory(env,
9381449Stomee "could not allocate option string");
9391449Stomee return;
9401449Stomee }
9411449Stomee
9421449Stomee if (value) {
9431449Stomee val = (*env)->GetStringUTFChars(env, value, 0);
9441449Stomee if (!val) {
9451449Stomee dtj_throw_out_of_memory(env,
9461449Stomee "could not allocate option value string");
9471449Stomee (*env)->ReleaseStringUTFChars(env, option, opt);
9481449Stomee return;
9491449Stomee }
9501449Stomee } else {
9511449Stomee /*
9521449Stomee * dtrace_setopt() sets option to 0 if value is NULL. That's
9531449Stomee * not the same thing as unsetting a boolean option, since
9541449Stomee * libdtrace uses -2 to mean unset. We'll leave it to
9551449Stomee * LocalConsumer.java to disallow null or not.
9561449Stomee */
9571449Stomee val = NULL;
9581449Stomee }
9591449Stomee
9601449Stomee /*
9611449Stomee * Check for boolean compile-time options not handled by
9621449Stomee * dtrace_setopt().
9631449Stomee */
9641449Stomee on = (!val || (strcmp(val, "unset") != 0));
9651449Stomee if (dtj_cflag(&jc, opt, NULL, &on)) {
9661449Stomee (*env)->ReleaseStringUTFChars(env, option, opt);
9671449Stomee if (value) {
9681449Stomee (*env)->ReleaseStringUTFChars(env, value, val);
9691449Stomee }
9701449Stomee return;
9711449Stomee }
9721449Stomee
9731449Stomee /*
9741449Stomee * The transition from INIT to GO is protected by synchronization
9751449Stomee * (a per-consumer lock) in LocalConsumer.java, ensuring that go() and
9761449Stomee * setOption() execute sequentially.
9771449Stomee */
9781449Stomee if (jc.dtjj_consumer->dtjc_state != DTJ_CONSUMER_INIT) {
9791449Stomee /*
9801449Stomee * If the consumer is already running, defer setting the option
9811449Stomee * until we wake up from dtrace_sleep.
9821449Stomee */
9831449Stomee dtj_request_t *request;
9841449Stomee
9851449Stomee
9861449Stomee (void) pthread_mutex_lock(
9871449Stomee &jc.dtjj_consumer->dtjc_request_list_lock);
9881449Stomee request = dtj_request_create(env, DTJ_REQUEST_OPTION, opt, val);
9891449Stomee if (request) {
9901449Stomee if (!dtj_list_add(jc.dtjj_consumer->dtjc_request_list,
9911449Stomee request)) {
9921449Stomee dtj_throw_out_of_memory(env,
9931449Stomee "Failed to add setOption request");
9941449Stomee }
9951449Stomee } /* else java exception pending */
9961449Stomee (void) pthread_mutex_unlock(
9971449Stomee &jc.dtjj_consumer->dtjc_request_list_lock);
9981449Stomee } else {
9991449Stomee dtrace_hdl_t *dtp = jc.dtjj_consumer->dtjc_dtp;
10001449Stomee if (dtrace_setopt(dtp, opt, val) == -1) {
10011449Stomee dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp,
10021449Stomee dtrace_errno(dtp)));
10031449Stomee }
10041449Stomee }
10051449Stomee
10061449Stomee (*env)->ReleaseStringUTFChars(env, option, opt);
10071449Stomee if (value) {
10081449Stomee (*env)->ReleaseStringUTFChars(env, value, val);
10091449Stomee }
10101449Stomee }
10111449Stomee
10121449Stomee /*
10131449Stomee * Protected by global lock (LocalConsumer.class)
10141449Stomee */
10151449Stomee JNIEXPORT jlong JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1getOption(JNIEnv * env,jobject obj,jstring option)10161449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getOption(JNIEnv *env,
10171449Stomee jobject obj, jstring option)
10181449Stomee {
10191449Stomee dtj_java_consumer_t jc;
10201449Stomee dtrace_hdl_t *dtp;
10211449Stomee const char *opt;
10221449Stomee dtrace_optval_t optval;
10231449Stomee boolean_t cflag;
10241449Stomee
10251449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
10261449Stomee return (0); /* java exception pending */
10271449Stomee }
10281449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
10291449Stomee
10301449Stomee opt = (*env)->GetStringUTFChars(env, option, 0);
10311449Stomee if (!opt) {
10321449Stomee dtj_throw_out_of_memory(env,
10331449Stomee "could not allocate option string");
10341449Stomee return (0);
10351449Stomee }
10361449Stomee
10371449Stomee /*
10381449Stomee * Check for boolean compile-time options not handled by
10391449Stomee * dtrace_setopt().
10401449Stomee */
10411449Stomee if (dtj_cflag(&jc, opt, &cflag, NULL)) {
10421449Stomee (*env)->ReleaseStringUTFChars(env, option, opt);
10431449Stomee return (cflag ? 1 : DTRACEOPT_UNSET);
10441449Stomee }
10451449Stomee
10461449Stomee if (dtrace_getopt(dtp, opt, &optval) == -1) {
10471449Stomee dtj_throw_dtrace_exception(&jc,
10481449Stomee "couldn't get option %s: %s", opt,
10491449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp)));
10501449Stomee (*env)->ReleaseStringUTFChars(env, option, opt);
10511449Stomee return (0);
10521449Stomee }
10531449Stomee (*env)->ReleaseStringUTFChars(env, option, opt);
10541449Stomee return (optval);
10551449Stomee }
10561449Stomee
10571449Stomee /*
10581449Stomee * Throws IllegalStateException if not all compiled programs are enabled.
10591449Stomee */
10601449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1checkProgramEnabling(JNIEnv * env,jobject obj)10611449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1checkProgramEnabling(JNIEnv *env,
10621449Stomee jobject obj)
10631449Stomee {
10641449Stomee dtj_java_consumer_t jc;
10651449Stomee dtj_program_t *p;
10661449Stomee uu_list_walk_t *itr;
10671449Stomee
10681449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
10691449Stomee return; /* java exception pending */
10701449Stomee }
10711449Stomee
10721449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
10731449Stomee dtj_throw_illegal_state(env, "no program compiled");
10741449Stomee return;
10751449Stomee }
10761449Stomee
10771449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
10781449Stomee while ((p = uu_list_walk_next(itr)) != NULL) {
10791449Stomee if (!p->dtjp_enabled) {
10801449Stomee const char *type;
10811449Stomee switch (p->dtjp_type) {
10821449Stomee case DTJ_PROGRAM_STRING:
10831449Stomee type = "description";
10841449Stomee break;
10851449Stomee case DTJ_PROGRAM_FILE:
10861449Stomee type = "script";
10871449Stomee break;
10881449Stomee default:
10891449Stomee assert(p->dtjp_type == DTJ_PROGRAM_STRING ||
10901449Stomee p->dtjp_type == DTJ_PROGRAM_FILE);
10911449Stomee }
10921449Stomee dtj_throw_illegal_state(env,
10931449Stomee "Not all compiled probes are enabled. "
10941449Stomee "Compiled %s %s not enabled.",
10951449Stomee type, p->dtjp_name);
10961449Stomee uu_list_walk_end(itr);
10971449Stomee return;
10981449Stomee }
10991449Stomee }
11001449Stomee uu_list_walk_end(itr);
11011449Stomee }
11021449Stomee
11031449Stomee JNIEXPORT jboolean JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1isEnabled(JNIEnv * env,jobject obj)11041449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1isEnabled(JNIEnv *env,
11051449Stomee jobject obj)
11061449Stomee {
11071449Stomee dtj_java_consumer_t jc;
11081449Stomee dtj_program_t *p;
11091449Stomee uu_list_walk_t *itr;
11101449Stomee
11111449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
11121449Stomee return (JNI_FALSE); /* java exception pending */
11131449Stomee }
11141449Stomee
11151449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
11161449Stomee return (JNI_FALSE); /* no program compiled */
11171449Stomee }
11181449Stomee
11191449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
11201449Stomee while ((p = uu_list_walk_next(itr)) != NULL) {
11211449Stomee if (!p->dtjp_enabled) {
11221449Stomee uu_list_walk_end(itr);
11231449Stomee return (JNI_FALSE);
11241449Stomee }
11251449Stomee }
11261449Stomee uu_list_walk_end(itr);
11271449Stomee
11281449Stomee return (JNI_TRUE);
11291449Stomee }
11301449Stomee
11311449Stomee /*
11321449Stomee * Protected by global lock (LocalConsumer.class)
11331449Stomee */
11341449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1go(JNIEnv * env,jobject obj)11351449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1go(JNIEnv *env, jobject obj)
11361449Stomee {
11371449Stomee dtj_java_consumer_t jc;
11381449Stomee dtrace_hdl_t *dtp;
11391449Stomee
11401449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
11411449Stomee return; /* java exception pending */
11421449Stomee }
11431449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
11441449Stomee
11451449Stomee if (dtj_set_callback_handlers(&jc) != DTJ_OK) {
11461449Stomee return; /* java exception pending */
11471449Stomee }
11481449Stomee
11491449Stomee if (dtrace_go(dtp) != 0) {
11501449Stomee dtj_throw_dtrace_exception(&jc,
11511449Stomee "could not enable tracing: %s",
11521449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp)));
11531449Stomee return;
11541449Stomee }
11551449Stomee
11561449Stomee jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_GO;
11571449Stomee }
11581449Stomee
11591449Stomee /*
11601449Stomee * Protected by global lock (LocalConsumer.class). Called when aborting the
11611449Stomee * consumer loop before it starts.
11621449Stomee */
11631449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1stop(JNIEnv * env,jobject obj)11641449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1stop(JNIEnv *env,
11651449Stomee jobject obj)
11661449Stomee {
11671449Stomee dtj_java_consumer_t jc;
11681449Stomee dtrace_hdl_t *dtp;
11691449Stomee
11701449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
11711449Stomee return; /* java exception pending */
11721449Stomee }
11731449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
11741449Stomee
11751449Stomee if (dtrace_stop(dtp) == -1) {
11761449Stomee dtj_throw_dtrace_exception(&jc,
11771449Stomee "couldn't stop tracing: %s",
11781449Stomee dtrace_errmsg(jc.dtjj_consumer->dtjc_dtp,
11791449Stomee dtrace_errno(jc.dtjj_consumer->dtjc_dtp)));
11801449Stomee } else {
11811449Stomee jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_STOP;
11821449Stomee }
11831449Stomee }
11841449Stomee
11851449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1consume(JNIEnv * env,jobject obj)11861449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1consume(JNIEnv *env,
11871449Stomee jobject obj)
11881449Stomee {
11891449Stomee dtj_java_consumer_t jc;
11901449Stomee dtrace_hdl_t *dtp;
11911449Stomee
11921449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
11931449Stomee return; /* java exception pending */
11941449Stomee }
11951449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
11961449Stomee jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_START;
11971449Stomee
11981449Stomee if (dtj_java_consumer_init(env, &jc) != DTJ_OK) {
11991449Stomee return; /* java exception pending */
12001449Stomee }
12011449Stomee
12021449Stomee /*
12031449Stomee * Must set the thread-specific java consumer before starting the
12041449Stomee * dtrace_work() loop because the bufhandler can also be invoked by
12051449Stomee * getAggregate() from another thread. The bufhandler needs access to
12061449Stomee * the correct JNI state specific to either the consumer loop or the
12071449Stomee * getAggregate() call.
12081449Stomee */
12091449Stomee (void) pthread_setspecific(g_dtj_consumer_key, &jc);
12101449Stomee
12111449Stomee if (jc.dtjj_consumer->dtjc_process_list != NULL) {
12121449Stomee struct ps_prochandle *P;
12131449Stomee uu_list_walk_t *itr;
12141449Stomee
12153645Stomee /* Must not call MonitorEnter with a pending exception */
12163645Stomee if ((*env)->ExceptionCheck(env)) {
12173645Stomee dtj_java_consumer_fini(env, &jc);
12183645Stomee return; /* java exception pending */
12193645Stomee }
12201449Stomee (*env)->MonitorEnter(env, g_caller_jc);
12211449Stomee if ((*env)->ExceptionCheck(env)) {
12221449Stomee dtj_java_consumer_fini(env, &jc);
12231449Stomee return; /* java exception pending */
12241449Stomee }
12251449Stomee
12261449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_process_list,
12271449Stomee 0);
12281449Stomee while ((P = dtj_pointer_list_walk_next(itr)) !=
12291449Stomee DTJ_INVALID_PTR) {
12301449Stomee dtrace_proc_continue(dtp, P);
12311449Stomee }
12321449Stomee uu_list_walk_end(itr);
12331449Stomee
12341449Stomee (*env)->MonitorExit(env, g_caller_jc);
12351449Stomee if ((*env)->ExceptionCheck(env)) {
12361449Stomee dtj_java_consumer_fini(env, &jc);
12371449Stomee return; /* java exception pending */
12381449Stomee }
12391449Stomee }
12401449Stomee
12411449Stomee /*
12421449Stomee * Blocking call starts consumer loop.
12431449Stomee */
12441449Stomee (void) dtj_consume(&jc);
12451449Stomee
12461449Stomee dtj_java_consumer_fini(env, &jc);
12471449Stomee /*
12481449Stomee * Stop the consumer after the consumer loop terminates, whether
12491449Stomee * normally because of the exit() action or LocalConsumer.stop(), or
12501449Stomee * abnormally because of an exception. The call is ignored if the
12511449Stomee * consumer is already stopped. It is safe to call dtj_stop() with a
12521449Stomee * pending exception.
12531449Stomee */
12541449Stomee dtj_stop(&jc);
12551449Stomee }
12561449Stomee
12571449Stomee /*
12581449Stomee * Interrupts a running consumer. May be called from any thread.
12591449Stomee */
12601449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1interrupt(JNIEnv * env,jobject obj)12611449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1interrupt(JNIEnv *env,
12621449Stomee jobject obj)
12631449Stomee {
12641449Stomee dtj_java_consumer_t jc;
12651449Stomee
12661449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
12671449Stomee return; /* java exception pending */
12681449Stomee }
12691449Stomee
12701449Stomee jc.dtjj_consumer->dtjc_interrupt = B_TRUE;
12711449Stomee }
12721449Stomee
12731449Stomee /*
12741449Stomee * Protected by global lock (LocalConsumer.class)
12751449Stomee */
12761449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1close(JNIEnv * env,jobject obj)12771449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1close(JNIEnv *env, jobject obj)
12781449Stomee {
12791449Stomee dtj_java_consumer_t jc;
12801449Stomee dtrace_hdl_t *dtp;
12811449Stomee
12821449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
12831449Stomee return; /* java exception pending */
12841449Stomee }
12851449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
12861449Stomee
12871449Stomee /*
12881449Stomee * Need to release any created procs here, since the consumer_t
12891449Stomee * destructor (called by _destroy) will not have access to the dtrace
12901449Stomee * handle needed to release them (this function closes the dtrace
12911449Stomee * handle).
12921449Stomee */
12931449Stomee if (jc.dtjj_consumer->dtjc_process_list != NULL) {
12941449Stomee struct ps_prochandle *P;
12951449Stomee uu_list_walk_t *itr;
12961449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_process_list,
12971449Stomee 0);
12981449Stomee while ((P = dtj_pointer_list_walk_next(itr)) !=
12991449Stomee DTJ_INVALID_PTR) {
13001449Stomee dtrace_proc_release(dtp, P);
13011449Stomee }
13021449Stomee uu_list_walk_end(itr);
13031449Stomee }
13041449Stomee
13051449Stomee dtrace_close(dtp);
13061449Stomee }
13071449Stomee
13081449Stomee /*
13091449Stomee * Static Consumer.java method
13101449Stomee */
13111449Stomee JNIEXPORT jint JNICALL
13121449Stomee /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1openCount(JNIEnv * env,jclass c)13131449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1openCount(JNIEnv *env, jclass c)
13141449Stomee {
13151449Stomee int open;
13161449Stomee (void) pthread_mutex_lock(&g_table_lock);
13171449Stomee if (g_consumer_table == NULL) {
13181449Stomee open = 0;
13191449Stomee } else {
13201449Stomee open = g_consumer_count;
13211449Stomee }
13221449Stomee (void) pthread_mutex_unlock(&g_table_lock);
13231449Stomee return (open);
13241449Stomee }
13251449Stomee
13261449Stomee /*
13271449Stomee * Static Consumer.java method
13281449Stomee */
13291449Stomee JNIEXPORT jlong JNICALL
13301449Stomee /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1quantizeBucket(JNIEnv * env,jclass c,jint bucket)13311449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1quantizeBucket(JNIEnv *env,
13321449Stomee jclass c, jint bucket)
13331449Stomee {
13341449Stomee return (DTRACE_QUANTIZE_BUCKETVAL(bucket));
13351449Stomee }
13361449Stomee
13371449Stomee /*
13381449Stomee * Protected by global lock (LocalConsumer.class)
13391449Stomee */
13401449Stomee JNIEXPORT jstring JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupKernelFunction(JNIEnv * jenv,jobject caller,jobject address)13411449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupKernelFunction(
13421449Stomee JNIEnv *jenv, jobject caller, jobject address)
13431449Stomee {
13441449Stomee dtj_java_consumer_t jc;
13451449Stomee dtrace_hdl_t *dtp;
13461449Stomee
13471449Stomee jstring jfunc; /* return value */
13481449Stomee
13491449Stomee GElf_Addr addr;
13501449Stomee char dummy;
13511449Stomee char *s;
13521449Stomee int rc;
13531449Stomee
13541449Stomee if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) {
13551449Stomee return (NULL); /* java exception pending */
13561449Stomee }
13571449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
13581449Stomee
13591449Stomee /* Does not throw exceptions */
13601449Stomee if ((*jenv)->IsInstanceOf(jenv, address, g_int_jc)) {
13611449Stomee /* intValue() of class Number does not throw exceptions */
13621449Stomee addr = (GElf_Addr)(uint32_t)(*jenv)->CallIntMethod(jenv,
13631449Stomee address, g_intval_jm);
13641449Stomee } else if ((*jenv)->IsInstanceOf(jenv, address, g_number_jc)) {
13651449Stomee /* longValue() of class Number does not throw exceptions */
13661449Stomee addr = (GElf_Addr)(*jenv)->CallLongMethod(jenv,
13671449Stomee address, g_longval_jm);
13681449Stomee } else {
13691449Stomee dtj_throw_class_cast(jenv, "Expected Number address");
13701449Stomee return (NULL);
13711449Stomee }
13721449Stomee
13731449Stomee rc = dtrace_addr2str(dtp, addr, &dummy, 1);
13741847Stomee s = malloc(rc + 1);
13751449Stomee if (!s) {
13761449Stomee dtj_throw_out_of_memory(jenv,
13771449Stomee "Failed to allocate kernel function name");
13781449Stomee return (NULL);
13791449Stomee }
13801847Stomee (void) dtrace_addr2str(dtp, addr, s, rc + 1);
13811449Stomee
13821449Stomee jfunc = (*jenv)->NewStringUTF(jenv, s);
13831449Stomee free(s);
13841449Stomee return (jfunc);
13851449Stomee }
13861449Stomee
13871449Stomee /*
13881449Stomee * Protected by global lock in Consumer.java
13891449Stomee */
13901449Stomee JNIEXPORT jstring JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupUserFunction(JNIEnv * jenv,jobject caller,jint pid,jobject address)13911449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupUserFunction(JNIEnv *jenv,
13921449Stomee jobject caller, jint pid, jobject address)
13931449Stomee {
13941449Stomee dtj_java_consumer_t jc;
13951449Stomee dtrace_hdl_t *dtp;
13961449Stomee
13971449Stomee jstring jfunc; /* return value */
13981449Stomee
13991449Stomee GElf_Addr addr;
14001449Stomee char dummy;
14011449Stomee char *s;
14021449Stomee int rc;
14031449Stomee
14041449Stomee if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) {
14051449Stomee return (NULL); /* java exception pending */
14061449Stomee }
14071449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
14081449Stomee
14091449Stomee /* Does not throw exceptions */
14101449Stomee if ((*jenv)->IsInstanceOf(jenv, address, g_int_jc)) {
14111449Stomee /* intValue() of class Number does not throw exceptions */
14121449Stomee addr = (GElf_Addr)(uint32_t)(*jenv)->CallIntMethod(jenv,
14131449Stomee address, g_intval_jm);
14141449Stomee } else if ((*jenv)->IsInstanceOf(jenv, address, g_number_jc)) {
14151449Stomee /* longValue() of class Number does not throw exceptions */
14161449Stomee addr = (GElf_Addr)(*jenv)->CallLongMethod(jenv,
14171449Stomee address, g_longval_jm);
14181449Stomee } else {
14191449Stomee dtj_throw_class_cast(jenv, "Expected Number address");
14201449Stomee return (NULL);
14211449Stomee }
14221449Stomee
14231449Stomee rc = dtrace_uaddr2str(dtp, pid, addr, &dummy, 1);
14241847Stomee s = malloc(rc + 1);
14251449Stomee if (!s) {
14261449Stomee dtj_throw_out_of_memory(jenv,
14271449Stomee "Failed to allocate user function name");
14281449Stomee return (NULL);
14291449Stomee }
14301847Stomee (void) dtrace_uaddr2str(dtp, pid, addr, s, rc + 1);
14311449Stomee
14321449Stomee jfunc = (*jenv)->NewStringUTF(jenv, s);
14331449Stomee free(s);
14341449Stomee return (jfunc);
14351449Stomee }
14361449Stomee
14371449Stomee JNIEXPORT jobject JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1getAggregate(JNIEnv * env,jobject obj,jobject spec)14381449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getAggregate(JNIEnv *env,
14391449Stomee jobject obj, jobject spec)
14401449Stomee {
14411449Stomee dtj_java_consumer_t jc;
14421449Stomee
14431449Stomee jobject aggregate = NULL;
14441449Stomee
14451449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
14461449Stomee return (NULL); /* java exception pending */
14471449Stomee }
14481449Stomee
14491449Stomee if (dtj_java_consumer_init(env, &jc) != DTJ_OK) {
14501449Stomee return (NULL); /* java exception pending */
14511449Stomee }
14521449Stomee jc.dtjj_aggregate_spec = spec;
14531449Stomee
14541449Stomee /*
14551449Stomee * Must set the thread-specific java consumer before calling any
14561449Stomee * function that triggers callbacks to the bufhandler set by
14571449Stomee * dtrace_handle_buffered(). The bufhandler needs access to the correct
14581449Stomee * JNI state specific to either the consumer loop or the
14591449Stomee * getAggregate() call.
14601449Stomee */
14611449Stomee (void) pthread_setspecific(g_dtj_consumer_key, &jc);
14621449Stomee aggregate = dtj_get_aggregate(&jc);
14631449Stomee if (!aggregate) {
14641449Stomee /* java exception pending */
14651449Stomee jc.dtjj_consumer->dtjc_interrupt = B_TRUE;
14661449Stomee }
14671449Stomee /*
14681449Stomee * Cleans up only references created by this JNI invocation. Leaves
14691449Stomee * cached per-consumer state untouched.
14701449Stomee */
14711449Stomee dtj_java_consumer_fini(env, &jc);
14721449Stomee return (aggregate);
14731449Stomee }
14741449Stomee
14751449Stomee /*
14761449Stomee * Returns the pid of the created process, or -1 in case of an error (java
14771449Stomee * exception pending).
14781449Stomee * Protected by global lock (LocalConsumer.class)
14791449Stomee */
14801449Stomee JNIEXPORT int JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1createProcess(JNIEnv * jenv,jobject caller,jstring command)14811449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1createProcess(JNIEnv *jenv,
14821449Stomee jobject caller, jstring command)
14831449Stomee {
14841449Stomee dtj_java_consumer_t jc;
14851449Stomee dtrace_hdl_t *dtp;
14861449Stomee struct ps_prochandle *P;
14871449Stomee char **argv;
14881449Stomee int argc;
14891449Stomee
14901449Stomee if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) {
14911449Stomee return (-1); /* java exception pending */
14921449Stomee }
14931449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
14941449Stomee
14951449Stomee if (jc.dtjj_consumer->dtjc_process_list == NULL) {
14961449Stomee jc.dtjj_consumer->dtjc_process_list = dtj_pointer_list_create();
14971449Stomee if (!jc.dtjj_consumer->dtjc_process_list) {
14981449Stomee dtj_throw_out_of_memory(jenv,
14991449Stomee "Could not allocate process list");
15001449Stomee return (-1);
15011449Stomee }
15021449Stomee }
15031449Stomee
15041449Stomee argv = dtj_make_argv(jenv, command, &argc);
15051449Stomee if ((*jenv)->ExceptionCheck(jenv)) {
15061449Stomee return (-1);
15071449Stomee }
15081449Stomee
15091449Stomee P = dtrace_proc_create(dtp, argv[0], argv);
15101449Stomee dtj_free_argv(argv);
15111449Stomee
15121449Stomee if (!P) {
15131449Stomee dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp,
15141449Stomee dtrace_errno(dtp)));
15151449Stomee return (-1);
15161449Stomee }
15171449Stomee
15181449Stomee if (!dtj_pointer_list_add(jc.dtjj_consumer->dtjc_process_list, P)) {
15191449Stomee dtj_throw_out_of_memory(jenv,
15201449Stomee "Failed to add process to process list");
15211449Stomee dtrace_proc_release(dtp, P);
15221449Stomee return (-1);
15231449Stomee }
15241449Stomee return (Pstatus(P)->pr_pid);
15251449Stomee }
15261449Stomee
15271449Stomee /*
15281449Stomee * Protected by global lock (LocalConsumer.class)
15291449Stomee */
15301449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1grabProcess(JNIEnv * jenv,jobject caller,jint pid)15311449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1grabProcess(JNIEnv *jenv,
15321449Stomee jobject caller, jint pid)
15331449Stomee {
15341449Stomee dtj_java_consumer_t jc;
15351449Stomee dtrace_hdl_t *dtp;
15361449Stomee struct ps_prochandle *P;
15371449Stomee
15381449Stomee if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) {
15391449Stomee return; /* java exception pending */
15401449Stomee }
15411449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
15421449Stomee
15431449Stomee if (jc.dtjj_consumer->dtjc_process_list == NULL) {
15441449Stomee jc.dtjj_consumer->dtjc_process_list = dtj_pointer_list_create();
15451449Stomee if (jc.dtjj_consumer->dtjc_process_list == NULL) {
15461449Stomee dtj_throw_out_of_memory(jenv,
15471449Stomee "Could not allocate process list");
15481449Stomee return;
15491449Stomee }
15501449Stomee }
15511449Stomee
15521449Stomee P = dtrace_proc_grab(dtp, (pid_t)pid, 0);
15531449Stomee if (!P) {
15541449Stomee dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp,
15551449Stomee dtrace_errno(dtp)));
15561449Stomee return;
15571449Stomee }
15581449Stomee
15591449Stomee if (!dtj_pointer_list_add(jc.dtjj_consumer->dtjc_process_list, P)) {
15601449Stomee dtj_throw_out_of_memory(jenv,
15611449Stomee "Failed to add process to process list");
15621449Stomee dtrace_proc_release(dtp, P);
15631449Stomee return;
15641449Stomee }
15651449Stomee }
15661449Stomee
15671449Stomee /*
15681449Stomee * Lists all probes, or lists matching probes (using the matching rules from
15691449Stomee * Table 4-1 of the DTrace manual).
15701449Stomee *
15711449Stomee * In the future it may be desirable to support an array of probe filters rather
15721449Stomee * than a single filter. It could be that if a probe matched any of the given
15731449Stomee * filters, it would be included (implied logical OR).
15741449Stomee *
15751449Stomee * Protected by global lock (LocalConsumer.class)
15761449Stomee * param list: an empty list to populate (this function empties the list if it
15771449Stomee * is not empty already)
15781449Stomee * param filter: a ProbeDescription instance; the list will include only probes
15791449Stomee * that match the filter (match all probes if filter is null)
15801449Stomee */
15811449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbes(JNIEnv * env,jobject obj,jobject list,jobject filter)15821449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbes(JNIEnv *env,
15831449Stomee jobject obj, jobject list, jobject filter)
15841449Stomee {
15851449Stomee dtj_list_probes(env, obj, list, filter, dtj_list_probe);
15861449Stomee }
15871449Stomee
15881449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbeDetail(JNIEnv * env,jobject obj,jobject list,jobject filter)15891449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbeDetail(JNIEnv *env,
15901449Stomee jobject obj, jobject list, jobject filter)
15911449Stomee {
15921449Stomee dtj_list_probes(env, obj, list, filter, dtj_list_probe_detail);
15931449Stomee }
15941449Stomee
15951449Stomee static void
dtj_list_probes(JNIEnv * env,jobject obj,jobject list,jobject filter,dtrace_probe_f * func)15961449Stomee dtj_list_probes(JNIEnv *env, jobject obj, jobject list, jobject filter,
15971449Stomee dtrace_probe_f *func)
15981449Stomee {
15991449Stomee dtj_java_consumer_t jc;
16001449Stomee dtrace_hdl_t *dtp;
16011449Stomee dtrace_probedesc_t probe;
16021449Stomee dtrace_probedesc_t *pdp = NULL;
16031449Stomee const char *probestr;
16041449Stomee int rc;
16051449Stomee
16061449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
16071449Stomee return; /* java exception pending */
16081449Stomee }
16091449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
16101449Stomee
16111449Stomee jc.dtjj_probelist = list;
16121449Stomee
16131449Stomee /* clear in-out list parameter */
16141449Stomee (*env)->CallVoidMethod(env, list, g_listclear_jm);
16151449Stomee if ((*env)->ExceptionCheck(env)) {
16161449Stomee return;
16171449Stomee }
16181449Stomee
16191449Stomee if (filter) {
16201449Stomee jstring jprobestr = NULL;
16211449Stomee
16221449Stomee jprobestr = (*env)->CallObjectMethod(env, filter,
16231449Stomee g_tostring_jm);
16241449Stomee if ((*env)->ExceptionCheck(env)) {
16251449Stomee return;
16261449Stomee }
16271449Stomee probestr = (*env)->GetStringUTFChars(env, jprobestr, NULL);
16281449Stomee if (!probestr) {
16291449Stomee (*env)->DeleteLocalRef(env, jprobestr);
16301449Stomee return; /* java exception pending */
16311449Stomee }
16321449Stomee
16331449Stomee bzero(&probe, sizeof (probe));
16341449Stomee rc = dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, probestr,
16351449Stomee &probe);
16361449Stomee (*env)->ReleaseStringUTFChars(env, jprobestr, probestr);
16371449Stomee (*env)->DeleteLocalRef(env, jprobestr);
16381449Stomee if (rc == -1) {
16391449Stomee dtj_throw_dtrace_exception(&jc,
16401449Stomee "%s is not a valid probe description: %s",
16411449Stomee probestr, dtrace_errmsg(dtp,
16421449Stomee dtrace_errno(dtp)));
16431449Stomee return;
16441449Stomee }
16451449Stomee
16461449Stomee pdp = &probe;
16471449Stomee }
16481449Stomee
16491449Stomee (void) dtrace_probe_iter(dtp, pdp, func, &jc);
16501449Stomee }
16511449Stomee
16521449Stomee /*
16531449Stomee * Returns 0 to indicate success, or -1 to cause dtrace_probe_iter() to return a
16541449Stomee * negative value prematurely (indicating no match or failure).
16551449Stomee */
16561449Stomee static int
16571449Stomee /* ARGSUSED */
dtj_list_probe(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp,void * arg)16581449Stomee dtj_list_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
16591449Stomee {
16601449Stomee dtj_java_consumer_t *jc = arg;
16611449Stomee JNIEnv *jenv = jc->dtjj_jenv;
16621449Stomee
16631449Stomee jobject jprobedesc = NULL;
16641449Stomee
16651449Stomee jprobedesc = dtj_new_probedesc(jc, pdp);
16661449Stomee if (!jprobedesc) {
16671449Stomee return (-1); /* java exception pending */
16681449Stomee }
16691449Stomee
16701449Stomee /* add probe to list */
16711449Stomee (*jenv)->CallVoidMethod(jenv, jc->dtjj_probelist, g_listadd_jm,
16721449Stomee jprobedesc);
16731449Stomee (*jenv)->DeleteLocalRef(jenv, jprobedesc);
16741449Stomee if ((*jenv)->ExceptionCheck(jenv)) {
16751449Stomee return (-1);
16761449Stomee }
16771449Stomee
16781449Stomee return (0);
16791449Stomee }
16801449Stomee
16811449Stomee /*ARGSUSED*/
16821449Stomee static int
dtj_list_probe_detail(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp,void * arg)16831449Stomee dtj_list_probe_detail(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
16841449Stomee void *arg)
16851449Stomee {
16861449Stomee dtj_java_consumer_t *jc = arg;
16871449Stomee JNIEnv *jenv = jc->dtjj_jenv;
16881449Stomee dtrace_probeinfo_t p;
16891449Stomee
16901449Stomee jobject jprobedesc = NULL;
16911449Stomee jobject jprobeinfo = NULL;
16921449Stomee jobject jprobe = NULL;
16931449Stomee
16941449Stomee jprobedesc = dtj_new_probedesc(jc, pdp);
16951449Stomee if (!jprobedesc) {
16961449Stomee return (-1); /* java exception pending */
16971449Stomee }
16981449Stomee
16991449Stomee /*
17001449Stomee * If dtrace_probe_info() returns a non-zero value, dtrace_errno is set
17011449Stomee * for us. In that case, ignore the dtrace error and simply omit probe
17021449Stomee * info. That error is implicitly cleared the next time a call is made
17031449Stomee * using the same dtrace handle.
17041449Stomee */
17051449Stomee if (dtrace_probe_info(dtp, pdp, &p) == 0) {
17061449Stomee /* create probe info instance */
17071449Stomee jprobeinfo = dtj_new_probeinfo(jc, &p);
17081449Stomee if (!jprobeinfo) {
17091449Stomee (*jenv)->DeleteLocalRef(jenv, jprobedesc);
17101449Stomee return (-1); /* java exception pending */
17111449Stomee }
17121449Stomee }
17131449Stomee
17141449Stomee /* create listed probe instance */
17151449Stomee jprobe = (*jenv)->NewObject(jenv, g_probe_jc, g_probeinit_jm,
17161449Stomee jprobedesc, jprobeinfo);
17171449Stomee (*jenv)->DeleteLocalRef(jenv, jprobedesc);
17181449Stomee (*jenv)->DeleteLocalRef(jenv, jprobeinfo);
17191449Stomee if (!jprobe) {
17201449Stomee return (-1); /* java exception pending */
17211449Stomee }
17221449Stomee
17231449Stomee /* add probe to list */
17241449Stomee (*jenv)->CallVoidMethod(jenv, jc->dtjj_probelist, g_listadd_jm,
17251449Stomee jprobe);
17261449Stomee (*jenv)->DeleteLocalRef(jenv, jprobe);
17271449Stomee if ((*jenv)->ExceptionCheck(jenv)) {
17281449Stomee return (-1);
17291449Stomee }
17301449Stomee
17311449Stomee return (0);
17321449Stomee }
17331449Stomee
17341449Stomee /*ARGSUSED*/
17351449Stomee static int
dtj_list_stmt(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmtdesc_t * stp,void * arg)17361449Stomee dtj_list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
17371449Stomee dtrace_stmtdesc_t *stp, void *arg)
17381449Stomee {
17391449Stomee dtj_java_consumer_t *jc = arg;
17401449Stomee dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc;
17411449Stomee
17421449Stomee if (edp == jc->dtjj_consumer->dtjc_last_probe) {
17431449Stomee return (0);
17441449Stomee }
17451449Stomee
17461449Stomee if (dtrace_probe_iter(dtp, &edp->dted_probe,
17471449Stomee jc->dtjj_consumer->dtjc_plistfunc, arg) != 0) {
17481449Stomee dtj_throw_dtrace_exception(jc,
17491449Stomee "failed to match %s:%s:%s:%s: %s",
17501449Stomee edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod,
17511449Stomee edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name,
17521449Stomee dtrace_errmsg(dtp, dtrace_errno(dtp)));
17531449Stomee return (1);
17541449Stomee }
17551449Stomee
17561449Stomee jc->dtjj_consumer->dtjc_last_probe = edp;
17571449Stomee return (0);
17581449Stomee }
17591449Stomee
17601449Stomee /*
17611449Stomee * Protected by global lock in Consumer.java
17621449Stomee */
17631449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbes(JNIEnv * env,jobject obj,jobject list,jobject program)17641449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbes(JNIEnv *env,
17651449Stomee jobject obj, jobject list, jobject program)
17661449Stomee {
17671449Stomee dtj_list_compiled_probes(env, obj, list, program, dtj_list_probe);
17681449Stomee }
17691449Stomee
17701449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbeDetail(JNIEnv * env,jobject obj,jobject list,jobject program)17711449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbeDetail(
17721449Stomee JNIEnv *env, jobject obj, jobject list, jobject program)
17731449Stomee {
17741449Stomee dtj_list_compiled_probes(env, obj, list, program,
17751449Stomee dtj_list_probe_detail);
17761449Stomee }
17771449Stomee
17781449Stomee static void
dtj_list_compiled_probes(JNIEnv * env,jobject obj,jobject list,jobject program,dtrace_probe_f * func)17791449Stomee dtj_list_compiled_probes(JNIEnv *env, jobject obj, jobject list,
17801449Stomee jobject program, dtrace_probe_f *func)
17811449Stomee {
17821449Stomee dtj_java_consumer_t jc;
17831449Stomee dtrace_hdl_t *dtp;
17841449Stomee uu_list_walk_t *itr;
17851449Stomee dtj_program_t *p;
17861449Stomee boolean_t found;
17871449Stomee int progid = -1;
17881449Stomee int i;
17891449Stomee
17901449Stomee if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
17911449Stomee return; /* java exception pending */
17921449Stomee }
17931449Stomee dtp = jc.dtjj_consumer->dtjc_dtp;
17941449Stomee jc.dtjj_probelist = list;
17951449Stomee
17961449Stomee (*env)->CallVoidMethod(env, list, g_listclear_jm);
17971449Stomee if ((*env)->ExceptionCheck(env)) {
17981449Stomee return;
17991449Stomee }
18001449Stomee
18011449Stomee if (program) {
18021449Stomee if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
18031449Stomee dtj_throw_no_such_element(env, "no compiled program");
18041449Stomee return;
18051449Stomee }
18061449Stomee progid = (*env)->GetIntField(env, program, g_progid_jf);
18071449Stomee if (progid == -1) {
18081449Stomee dtj_throw_illegal_argument(env, "invalid program");
18091449Stomee return;
18101449Stomee }
18111449Stomee }
18121449Stomee
18131449Stomee jc.dtjj_consumer->dtjc_plistfunc = func;
18141449Stomee found = B_FALSE;
18151449Stomee itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
18161449Stomee for (i = 0; (p = uu_list_walk_next(itr)) != NULL; ++i) {
18171449Stomee if ((progid != -1) && (progid != i)) {
18181449Stomee continue;
18191449Stomee }
18201449Stomee
18211449Stomee found = B_TRUE;
18221449Stomee (void) dtrace_stmt_iter(dtp, p->dtjp_program,
18231449Stomee (dtrace_stmt_f *)dtj_list_stmt, &jc);
18241449Stomee }
18251449Stomee uu_list_walk_end(itr);
18261449Stomee
18271449Stomee if (program && !found) {
18281449Stomee dtj_throw_no_such_element(env, "program not found");
18291449Stomee }
18301449Stomee }
18311449Stomee
18321449Stomee /*
18331449Stomee * Static LocalConsumer.java method
18341449Stomee * Protected by global lock (LocalConsumer.class)
18351449Stomee */
18361449Stomee JNIEXPORT jstring JNICALL
18371449Stomee /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1getVersion(JNIEnv * env,jclass class)18381449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getVersion(JNIEnv *env,
18391449Stomee jclass class)
18401449Stomee {
18411449Stomee /*
18421449Stomee * Handles the case of locale-specific encoding of the user-visible
18431449Stomee * version string containing non-ASCII characters.
18441449Stomee */
18451449Stomee return (dtj_NewStringNative(env, _dtrace_version));
18461449Stomee }
18471449Stomee
18481449Stomee /*
18491449Stomee * Static LocalConsumer.java method
18501449Stomee * Protected by global lock (LocalConsumer.class)
18511449Stomee */
18521449Stomee JNIEXPORT jstring JNICALL
18531449Stomee /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1getExecutableName(JNIEnv * env,jclass class)18541449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1getExecutableName(JNIEnv *env,
18551449Stomee jclass class)
18561449Stomee {
18571449Stomee jstring jname = NULL;
18581449Stomee const char *name = NULL;
18591449Stomee char *s;
18601449Stomee int len;
18611449Stomee
18621449Stomee name = dtj_getexecname();
18631449Stomee len = strlen(name);
18641449Stomee s = malloc(len + 1);
18651449Stomee if (!s) {
18661449Stomee dtj_throw_out_of_memory(env, "Failed to allocate execname");
18671449Stomee return (NULL);
18681449Stomee }
18691449Stomee (void) strcpy(s, name);
18701449Stomee name = basename(s);
18711449Stomee free(s);
18721449Stomee jname = (*env)->NewStringUTF(env, name);
18731449Stomee return (jname);
18741449Stomee }
18751449Stomee
18761449Stomee /*
18771449Stomee * Static LocalConsumer.java method
18781449Stomee */
18791449Stomee JNIEXPORT void JNICALL
18801449Stomee /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1setMaximumConsumers(JNIEnv * env,jclass class,jint max)18811449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1setMaximumConsumers(JNIEnv *env,
18821449Stomee jclass class, jint max)
18831449Stomee {
18841449Stomee g_max_consumers = max;
18851449Stomee }
18861449Stomee
18871449Stomee /*
18881449Stomee * Static LocalConsumer.java method
18891449Stomee */
18901449Stomee JNIEXPORT void JNICALL
18911449Stomee /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1setDebug(JNIEnv * env,jclass class,jboolean debug)18921449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1setDebug(JNIEnv *env,
18931449Stomee jclass class, jboolean debug)
18941449Stomee {
18951449Stomee g_dtj_util_debug = debug;
18961449Stomee }
18971449Stomee
18981449Stomee JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1destroy(JNIEnv * env,jobject obj)18991449Stomee Java_org_opensolaris_os_dtrace_LocalConsumer__1destroy(JNIEnv *env, jobject obj)
19001449Stomee {
19011449Stomee dtj_consumer_t *c;
19021449Stomee
19031449Stomee c = dtj_remove_consumer(env, obj);
19041449Stomee if (c == NULL) {
19051449Stomee return; /* java exception pending */
19061449Stomee }
19071449Stomee dtj_consumer_destroy(c);
19081449Stomee }
1909