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