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