xref: /onnv-gate/usr/src/lib/libdtrace_jni/common/dtrace_jni.c (revision 6136:b1f0a0698377)
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