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