xref: /illumos-gate/usr/src/lib/libdtrace_jni/common/dtj_jnitab.c (revision 445f2479fe3d7435daab18bf2cdc310b86cd6738)
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 <stdlib.h>
30 #include <stddef.h>
31 #include <limits.h>
32 #include <strings.h>
33 #include <pthread.h>
34 #include <dtrace_jni.h>
35 
36 /*
37  * dtj_jnitab.c defines the JNI table of classes, methods, and fields belonging
38  * to the Java DTrace API.  Another JNI table defining classes from the JDK is
39  * defined in dtj_util.c.  Utility functions specific to the Java DTrace API are
40  * also defined here, while general utilities are defined in dtj_util.c.
41  */
42 
43 static uu_list_pool_t *g_request_pool = NULL;
44 static uu_list_pool_t *g_program_pool = NULL;
45 static uu_list_pool_t *g_aggval_pool = NULL;
46 
47 static boolean_t dtj_check_request_pool(void);
48 static boolean_t dtj_check_program_pool(void);
49 static boolean_t dtj_check_aggval_pool(void);
50 
51 /* LocalConsumer */
52 jclass g_caller_jc = 0;
53 jmethodID g_gethandle_jm = 0;
54 jmethodID g_sethandle_jm = 0;
55 jmethodID g_pdatanext_jm = 0;
56 jmethodID g_drop_jm = 0;
57 jmethodID g_error_jm = 0;
58 jmethodID g_proc_jm = 0;
59 jmethodID g_interval_began_jm = 0;
60 jmethodID g_interval_ended_jm = 0;
61 jfieldID g_consumer_lock_jf = 0;
62 
63 /* DTraceException */
64 jclass g_dtx_jc = 0;
65 jmethodID g_dtxinit_jm = 0;
66 
67 /* InterfaceAttributes */
68 jclass g_attr_jc = 0;
69 jmethodID g_attrinit_jm = 0;
70 jmethodID g_attrset_name_jm = 0;
71 jmethodID g_attrset_data_jm = 0;
72 jmethodID g_attrset_class_jm = 0;
73 
74 /* ProbeDescription */
75 jclass g_probedesc_jc = 0;
76 jmethodID g_probedescinit_jm = 0;
77 jfieldID g_probedesc_id_jf = 0;
78 
79 /* ProbeInfo */
80 jclass g_probeinfo_jc = 0;
81 jmethodID g_probeinfoinit_jm = 0;
82 
83 /* Probe */
84 jclass g_probe_jc = 0;
85 jmethodID g_probeinit_jm = 0;
86 
87 /* Program */
88 jclass g_program_jc = 0;
89 jmethodID g_proginit_jm = 0;
90 jfieldID g_progid_jf = 0;
91 jfieldID g_proginfo_jf = 0;
92 
93 /* Program.File */
94 jclass g_programfile_jc = 0;
95 jmethodID g_fproginit_jm = 0;
96 
97 /* ProgramInfo */
98 jclass g_proginfo_jc = 0;
99 jmethodID g_proginfoinit_jm = 0;
100 
101 /* Flow */
102 jclass g_flow_jc = 0;
103 jmethodID g_flowinit_jm = 0;
104 
105 /* ProbeData */
106 jclass g_pdata_jc = 0;
107 jmethodID g_pdatainit_jm = 0;
108 jmethodID g_pdataadd_jm = 0;
109 jmethodID g_pdataadd_rec_jm = 0;
110 jmethodID g_pdataadd_trace_jm = 0;
111 jmethodID g_pdataadd_stack_jm = 0;
112 jmethodID g_pdataadd_printf_jm = 0;
113 jmethodID g_pdataadd_printa_jm = 0;
114 jmethodID g_pdatainvalidate_printa_jm = 0;
115 jmethodID g_pdataadd_aggrec_jm = 0;
116 jmethodID g_pdataadd_printa_str_jm = 0;
117 jmethodID g_pdataadd_exit_jm = 0;
118 jmethodID g_pdataattach_jm = 0;
119 jmethodID g_pdataset_formatted_jm = 0;
120 jmethodID g_pdataclear_jm = 0;
121 
122 /* Drop */
123 jclass g_drop_jc = 0;
124 jmethodID g_dropinit_jm = 0;
125 
126 /* Error */
127 jclass g_error_jc = 0;
128 jmethodID g_errinit_jm = 0;
129 
130 /* ProcessState */
131 jclass g_process_jc = 0;
132 jmethodID g_procinit_jm = 0;
133 jmethodID g_procexit_jm = 0;
134 
135 /* Aggregate */
136 jclass g_agg_jc = 0;
137 jmethodID g_agginit_jm = 0;
138 jmethodID g_aggaddrec_jm = 0;
139 
140 /* AggregateSpec */
141 jclass g_aggspec_jc = 0;
142 jmethodID g_aggspec_included_jm = 0;
143 jmethodID g_aggspec_cleared_jm = 0;
144 
145 /* Tuple */
146 jclass g_tuple_jc = 0;
147 jmethodID g_tupleinit_jm = 0;
148 jmethodID g_tupleadd_jm = 0;
149 jmethodID g_tuplesize_jm = 0;
150 jfieldID g_tuple_EMPTY_jsf = 0;
151 
152 /* AggregationRecord */
153 jclass g_aggrec_jc = 0;
154 jmethodID g_aggrecinit_jm = 0;
155 jmethodID g_aggrecget_tuple_jm = 0;
156 
157 /* SumValue */
158 jclass g_aggsum_jc = 0;
159 jmethodID g_aggsuminit_jm = 0;
160 
161 /* CountValue */
162 jclass g_aggcount_jc = 0;
163 jmethodID g_aggcountinit_jm = 0;
164 
165 /* AvgValue */
166 jclass g_aggavg_jc = 0;
167 jmethodID g_aggavginit_jm = 0;
168 
169 /* MinValue */
170 jclass g_aggmin_jc = 0;
171 jmethodID g_aggmininit_jm = 0;
172 
173 /* MaxValue */
174 jclass g_aggmax_jc = 0;
175 jmethodID g_aggmaxinit_jm = 0;
176 
177 /* KernelStackRecord */
178 jclass g_stack_jc = 0;
179 jmethodID g_parsestack_jsm = 0;
180 jmethodID g_stackinit_jm = 0;
181 jmethodID g_stackset_frames_jm = 0;
182 
183 /* UserStackRecord */
184 jclass g_ustack_jc = 0;
185 jmethodID g_ustackinit_jm = 0;
186 jmethodID g_ustackset_frames_jm = 0;
187 
188 /* Distribution */
189 jclass g_adist_jc = 0;
190 jmethodID g_dist_normal_jm = 0;
191 
192 /* LogDistribution */
193 jclass g_dist_jc = 0;
194 jmethodID g_distinit_jm = 0;
195 
196 /* LinearDistribution */
197 jclass g_ldist_jc = 0;
198 jmethodID g_ldistinit_jm = 0;
199 
200 
201 static dtj_status_t
202 dtj_table_load(JNIEnv *jenv)
203 {
204 	static const dtj_table_entry_t table[] = {
205 		/* LocalConsumer */
206 		{ JCLASS,  &g_caller_jc,
207 			"org/opensolaris/os/dtrace/LocalConsumer" },
208 		{ JMETHOD, &g_gethandle_jm, "getHandle", "()I" },
209 		{ JMETHOD, &g_sethandle_jm, "setHandle", "(I)V" },
210 		{ JMETHOD, &g_pdatanext_jm, "nextProbeData",
211 			"(Lorg/opensolaris/os/dtrace/ProbeData;)V" },
212 		{ JMETHOD, &g_drop_jm, "dataDropped",
213 			"(Lorg/opensolaris/os/dtrace/Drop;)V" },
214 		{ JMETHOD, &g_error_jm, "errorEncountered",
215 			"(Lorg/opensolaris/os/dtrace/Error;)V" },
216 		{ JMETHOD, &g_proc_jm, "processStateChanged",
217 			"(Lorg/opensolaris/os/dtrace/ProcessState;)V" },
218 		{ JMETHOD, &g_interval_began_jm, "intervalBegan", "()V" },
219 		{ JMETHOD, &g_interval_ended_jm, "intervalEnded", "()V" },
220 		{ JFIELD,  &g_consumer_lock_jf, "consumerLock",
221 			"Ljava/lang/Object;" },
222 
223 		/* DTraceException */
224 		{ JCLASS,  &g_dtx_jc,
225 			"org/opensolaris/os/dtrace/DTraceException" },
226 		{ JMETHOD, &g_dtxinit_jm, CONSTRUCTOR,
227 			"(Ljava/lang/String;)V" },
228 
229 		/* InterfaceAttributes */
230 		{ JCLASS,  &g_attr_jc,
231 			"org/opensolaris/os/dtrace/InterfaceAttributes" },
232 		{ JMETHOD, &g_attrinit_jm, CONSTRUCTOR, "()V" },
233 		{ JMETHOD, &g_attrset_name_jm, "setNameStability",
234 			"(Ljava/lang/String;)V" },
235 		{ JMETHOD, &g_attrset_data_jm, "setDataStability",
236 			"(Ljava/lang/String;)V" },
237 		{ JMETHOD, &g_attrset_class_jm, "setDependencyClass",
238 			"(Ljava/lang/String;)V" },
239 
240 		/* ProbeDescription */
241 		{ JCLASS,  &g_probedesc_jc,
242 			"org/opensolaris/os/dtrace/ProbeDescription" },
243 		{ JMETHOD, &g_probedescinit_jm, CONSTRUCTOR,
244 			"(Ljava/lang/String;Ljava/lang/String;"
245 			    "Ljava/lang/String;Ljava/lang/String;)V" },
246 		{ JFIELD,  &g_probedesc_id_jf, "id", "I" },
247 
248 		/* ProbeInfo */
249 		{ JCLASS,  &g_probeinfo_jc,
250 			"org/opensolaris/os/dtrace/ProbeInfo" },
251 		{ JMETHOD, &g_probeinfoinit_jm, CONSTRUCTOR,
252 			"(Lorg/opensolaris/os/dtrace/InterfaceAttributes;"
253 			    "Lorg/opensolaris/os/dtrace/InterfaceAttributes;"
254 			    ")V" },
255 
256 		/* Probe */
257 		{ JCLASS,  &g_probe_jc, "org/opensolaris/os/dtrace/Probe" },
258 		{ JMETHOD, &g_probeinit_jm, CONSTRUCTOR,
259 			"(Lorg/opensolaris/os/dtrace/ProbeDescription;"
260 			    "Lorg/opensolaris/os/dtrace/ProbeInfo;)V" },
261 
262 		/* Program */
263 		{ JCLASS,  &g_program_jc,
264 			"org/opensolaris/os/dtrace/Program" },
265 		{ JMETHOD, &g_proginit_jm, CONSTRUCTOR, "()V" },
266 		{ JFIELD,  &g_progid_jf, "id", "I" },
267 		{ JFIELD,  &g_proginfo_jf, "info",
268 			"Lorg/opensolaris/os/dtrace/ProgramInfo;" },
269 
270 		/* Program.File */
271 		{ JCLASS,  &g_programfile_jc,
272 			"org/opensolaris/os/dtrace/Program$File" },
273 		{ JMETHOD, &g_fproginit_jm, CONSTRUCTOR, "()V" },
274 
275 		/* ProgramInfo */
276 		{ JCLASS,  &g_proginfo_jc,
277 			"org/opensolaris/os/dtrace/ProgramInfo" },
278 		{ JMETHOD, &g_proginfoinit_jm, CONSTRUCTOR,
279 			"(Lorg/opensolaris/os/dtrace/InterfaceAttributes;"
280 			    "Lorg/opensolaris/os/dtrace/InterfaceAttributes;"
281 			    "I)V" },
282 
283 		/* Flow */
284 		{ JCLASS,  &g_flow_jc, "org/opensolaris/os/dtrace/Flow" },
285 		{ JMETHOD, &g_flowinit_jm, CONSTRUCTOR,
286 			"(Ljava/lang/String;I)V" },
287 
288 		/* ProbeData */
289 		{ JCLASS,  &g_pdata_jc,
290 			"org/opensolaris/os/dtrace/ProbeData" },
291 		{ JMETHOD, &g_pdatainit_jm, CONSTRUCTOR,
292 			"(IILorg/opensolaris/os/dtrace/ProbeDescription;"
293 			    "Lorg/opensolaris/os/dtrace/Flow;I)V" },
294 		{ JMETHOD, &g_pdataadd_jm, "addDataElement",
295 			"(Ljava/lang/Object;)V" },
296 		{ JMETHOD, &g_pdataadd_rec_jm, "addRecord",
297 			"(Lorg/opensolaris/os/dtrace/Record;)V" },
298 		{ JMETHOD, &g_pdataadd_trace_jm, "addTraceRecord", "(I)V" },
299 		{ JMETHOD, &g_pdataadd_stack_jm, "addStackRecord",
300 			"(ILjava/lang/String;)V" },
301 		{ JMETHOD, &g_pdataadd_printf_jm, "addPrintfRecord", "()V" },
302 		{ JMETHOD, &g_pdataadd_printa_jm, "addPrintaRecord", "(JZ)V" },
303 		{ JMETHOD, &g_pdatainvalidate_printa_jm,
304 			"invalidatePrintaRecord", "()V" },
305 		{ JMETHOD, &g_pdataadd_aggrec_jm, "addAggregationRecord",
306 			"(Ljava/lang/String;J"
307 			    "Lorg/opensolaris/os/dtrace/AggregationRecord;)V" },
308 		{ JMETHOD, &g_pdataadd_printa_str_jm,
309 			"addPrintaFormattedString",
310 			"(Lorg/opensolaris/os/dtrace/Tuple;"
311 			    "Ljava/lang/String;)V" },
312 		{ JMETHOD, &g_pdataadd_exit_jm, "addExitRecord", "(I)V" },
313 		{ JMETHOD, &g_pdataattach_jm, "attachRecordElements",
314 			"(II)V" },
315 		{ JMETHOD, &g_pdataset_formatted_jm, "setFormattedString",
316 			"(Ljava/lang/String;)V" },
317 		{ JMETHOD, &g_pdataclear_jm, "clearNativeElements", "()V" },
318 
319 		/* Drop */
320 		{ JCLASS,  &g_drop_jc, "org/opensolaris/os/dtrace/Drop" },
321 		{ JMETHOD, &g_dropinit_jm, CONSTRUCTOR,
322 			"(ILjava/lang/String;JJLjava/lang/String;)V" },
323 
324 		/* Error */
325 		{ JCLASS,  &g_error_jc, "org/opensolaris/os/dtrace/Error" },
326 		{ JMETHOD, &g_errinit_jm, CONSTRUCTOR,
327 			"(Lorg/opensolaris/os/dtrace/ProbeDescription;IIII"
328 			    "Ljava/lang/String;JLjava/lang/String;)V" },
329 
330 		/* ProcessState */
331 		{ JCLASS,  &g_process_jc,
332 			"org/opensolaris/os/dtrace/ProcessState" },
333 		{ JMETHOD, &g_procinit_jm, CONSTRUCTOR,
334 			"(ILjava/lang/String;ILjava/lang/String;"
335 			    "Ljava/lang/Integer;Ljava/lang/String;)V" },
336 		{ JMETHOD, &g_procexit_jm, "setExitStatus", "(I)V" },
337 
338 		/* Aggregate */
339 		{ JCLASS,  &g_agg_jc, "org/opensolaris/os/dtrace/Aggregate" },
340 		{ JMETHOD, &g_agginit_jm, CONSTRUCTOR, "(J)V" },
341 		{ JMETHOD, &g_aggaddrec_jm, "addRecord",
342 		    "(Ljava/lang/String;J"
343 			"Lorg/opensolaris/os/dtrace/AggregationRecord;)V" },
344 
345 		/* AggregateSpec */
346 		{ JCLASS,  &g_aggspec_jc,
347 			"org/opensolaris/os/dtrace/AggregateSpec" },
348 		{ JMETHOD, &g_aggspec_included_jm, "isIncluded",
349 			"(Ljava/lang/String;)Z" },
350 		{ JMETHOD, &g_aggspec_cleared_jm, "isCleared",
351 			"(Ljava/lang/String;)Z" },
352 
353 		/* Tuple */
354 		{ JCLASS,  &g_tuple_jc, "org/opensolaris/os/dtrace/Tuple" },
355 		{ JMETHOD, &g_tupleinit_jm, CONSTRUCTOR, "()V" },
356 		{ JMETHOD, &g_tupleadd_jm, "addElement",
357 			"(Ljava/lang/Object;)V" },
358 		{ JMETHOD, &g_tuplesize_jm, "size", "()I" },
359 		{ JFIELD_STATIC, &g_tuple_EMPTY_jsf, "EMPTY",
360 			"Lorg/opensolaris/os/dtrace/Tuple;" },
361 
362 		/* AggregationRecord */
363 		{ JCLASS,  &g_aggrec_jc,
364 			"org/opensolaris/os/dtrace/AggregationRecord" },
365 		{ JMETHOD, &g_aggrecinit_jm, CONSTRUCTOR,
366 			"(Lorg/opensolaris/os/dtrace/Tuple;"
367 			    "Lorg/opensolaris/os/dtrace/AggregationValue;)V" },
368 		{ JMETHOD, &g_aggrecget_tuple_jm, "getTuple",
369 			"()Lorg/opensolaris/os/dtrace/Tuple;" },
370 
371 		/* SumValue */
372 		{ JCLASS,  &g_aggsum_jc,
373 			"org/opensolaris/os/dtrace/SumValue" },
374 		{ JMETHOD, &g_aggsuminit_jm, CONSTRUCTOR, "(J)V" },
375 
376 		/* CountValue */
377 		{ JCLASS,  &g_aggcount_jc,
378 			"org/opensolaris/os/dtrace/CountValue" },
379 		{ JMETHOD, &g_aggcountinit_jm, CONSTRUCTOR, "(J)V" },
380 
381 		/* AvgValue */
382 		{ JCLASS,  &g_aggavg_jc,
383 			"org/opensolaris/os/dtrace/AvgValue" },
384 		{ JMETHOD, &g_aggavginit_jm, CONSTRUCTOR, "(JJJ)V" },
385 
386 		/* MinValue */
387 		{ JCLASS,  &g_aggmin_jc,
388 			"org/opensolaris/os/dtrace/MinValue" },
389 		{ JMETHOD, &g_aggmininit_jm, CONSTRUCTOR, "(J)V" },
390 
391 		/* MaxValue */
392 		{ JCLASS,  &g_aggmax_jc,
393 			"org/opensolaris/os/dtrace/MaxValue" },
394 		{ JMETHOD, &g_aggmaxinit_jm, CONSTRUCTOR, "(J)V" },
395 
396 		/* KernelStackRecord */
397 		{ JCLASS,  &g_stack_jc,
398 			"org/opensolaris/os/dtrace/KernelStackRecord" },
399 		{ JMETHOD_STATIC, &g_parsestack_jsm, "parse",
400 			"(Ljava/lang/String;)"
401 			    "[Lorg/opensolaris/os/dtrace/StackFrame;" },
402 		{ JMETHOD, &g_stackinit_jm, CONSTRUCTOR, "([B)V" },
403 		{ JMETHOD, &g_stackset_frames_jm, "setStackFrames",
404 			"([Lorg/opensolaris/os/dtrace/StackFrame;)V" },
405 
406 		/* UserStackRecord */
407 		{ JCLASS,  &g_ustack_jc,
408 			"org/opensolaris/os/dtrace/UserStackRecord" },
409 		{ JMETHOD, &g_ustackinit_jm, CONSTRUCTOR, "(I[B)V" },
410 		{ JMETHOD, &g_ustackset_frames_jm, "setStackFrames",
411 			"([Lorg/opensolaris/os/dtrace/StackFrame;)V" },
412 
413 		/* Distribution */
414 		{ JCLASS,  &g_adist_jc,
415 			"org/opensolaris/os/dtrace/Distribution" },
416 		{ JMETHOD, &g_dist_normal_jm, "normalizeBuckets", "(J)V" },
417 
418 		/* LogDistribution */
419 		{ JCLASS,  &g_dist_jc,
420 			"org/opensolaris/os/dtrace/LogDistribution" },
421 		{ JMETHOD,  &g_distinit_jm, CONSTRUCTOR, "([J)V" },
422 
423 		/* LinearDistribution */
424 		{ JCLASS,  &g_ldist_jc,
425 			"org/opensolaris/os/dtrace/LinearDistribution" },
426 		{ JMETHOD,  &g_ldistinit_jm, CONSTRUCTOR, "(JJ[J)V" },
427 
428 		{ DTJ_TYPE_END }
429 	};
430 
431 	return (dtj_cache_jni_classes(jenv, table));
432 }
433 
434 dtj_status_t
435 dtj_load(JNIEnv *jenv)
436 {
437 	if (dtj_load_common(jenv) != DTJ_OK) {
438 		/* Java Error pending */
439 		return (DTJ_ERR);
440 	}
441 
442 	return (dtj_table_load(jenv));
443 }
444 
445 static boolean_t
446 dtj_check_request_pool(void)
447 {
448 	if (!g_request_pool) {
449 		g_request_pool = uu_list_pool_create("g_request_pool",
450 		    sizeof (dtj_request_t),
451 		    offsetof(dtj_request_t, dtjr_node),
452 		    dtj_pointer_list_entry_cmp,
453 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
454 		if (!g_request_pool) {
455 			return (B_FALSE);
456 		}
457 	}
458 	return (B_TRUE);
459 }
460 
461 dtj_request_t *
462 dtj_request_create(JNIEnv *jenv, dtj_request_type_t type, ...)
463 {
464 	dtj_request_t *r;
465 
466 	if (!dtj_check_request_pool()) {
467 		dtj_throw_out_of_memory(jenv,
468 		    "Failed to allocate request pool");
469 		return (NULL);
470 	}
471 
472 	r = uu_zalloc(sizeof (dtj_request_t));
473 	if (r) {
474 		uu_list_node_init(r, &r->dtjr_node, g_request_pool);
475 		r->dtjr_type = type;
476 		r->dtjr_args = dtj_string_list_create();
477 		if (r->dtjr_args) {
478 			va_list ap;
479 			const char *arg;
480 			int i, len;
481 
482 			va_start(ap, type);
483 			switch (type) {
484 			case DTJ_REQUEST_OPTION:
485 				len = 2;
486 				break;
487 			default:
488 				len = 0;
489 			}
490 
491 			for (i = 0; i < len; ++i) {
492 				arg = va_arg(ap, char *);
493 				if (!dtj_string_list_add(r->dtjr_args, arg)) {
494 					dtj_throw_out_of_memory(jenv,
495 					    "Failed to add request arg");
496 					uu_list_node_fini(r, &r->dtjr_node,
497 					    g_request_pool);
498 					dtj_request_destroy(r, NULL);
499 					r = NULL;
500 				}
501 			}
502 			va_end(ap);
503 		} else {
504 			dtj_throw_out_of_memory(jenv,
505 			    "Failed to allocate request arglist");
506 			uu_list_node_fini(r, &r->dtjr_node, g_request_pool);
507 			dtj_request_destroy(r, NULL);
508 			r = NULL;
509 		}
510 	} else {
511 		dtj_throw_out_of_memory(jenv,
512 		    "Failed to allocate request");
513 	}
514 
515 	return (r);
516 }
517 
518 static boolean_t
519 dtj_check_program_pool(void)
520 {
521 	if (!g_program_pool) {
522 		g_program_pool = uu_list_pool_create("g_program_pool",
523 		    sizeof (dtj_program_t),
524 		    offsetof(dtj_program_t, dtjp_node),
525 		    dtj_pointer_list_entry_cmp,
526 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
527 		if (!g_program_pool) {
528 			return (B_FALSE);
529 		}
530 	}
531 	return (B_TRUE);
532 }
533 
534 dtj_program_t *
535 dtj_program_create(JNIEnv *jenv, dtj_program_type_t type, const char *name)
536 {
537 	dtj_program_t *p;
538 
539 	if (!dtj_check_program_pool()) {
540 		dtj_throw_out_of_memory(jenv,
541 		    "Failed to allocate program pool");
542 		return (NULL);
543 	}
544 
545 	p = uu_zalloc(sizeof (dtj_program_t));
546 	if (p) {
547 		char *program_name;
548 
549 		uu_list_node_init(p, &p->dtjp_node, g_program_pool);
550 		p->dtjp_type = type;
551 		program_name = malloc((size_t)
552 		    (sizeof (char)) * (strlen(name) + 1));
553 		if (program_name) {
554 			(void) strcpy(program_name, name);
555 			p->dtjp_name = program_name;
556 			p->dtjp_enabled = B_FALSE;
557 		} else {
558 			dtj_throw_out_of_memory(jenv,
559 			    "Failed to allocate program name");
560 			uu_list_node_fini(p, &p->dtjp_node, g_program_pool);
561 			dtj_program_destroy(p, NULL);
562 			p = NULL;
563 		}
564 	} else {
565 		dtj_throw_out_of_memory(jenv,
566 		    "Failed to allocate program");
567 	}
568 
569 	return (p);
570 }
571 
572 static boolean_t
573 dtj_check_aggval_pool(void)
574 {
575 	if (!g_aggval_pool) {
576 		g_aggval_pool = uu_list_pool_create("g_aggval_pool",
577 		    sizeof (dtj_aggval_t),
578 		    offsetof(dtj_aggval_t, dtja_node),
579 		    dtj_pointer_list_entry_cmp,
580 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
581 		if (!g_aggval_pool) {
582 			return (B_FALSE);
583 		}
584 	}
585 	return (B_TRUE);
586 }
587 
588 dtj_aggval_t *
589 dtj_aggval_create(JNIEnv *jenv, jobject aggval, const char *aggname,
590     int64_t aggid)
591 {
592 	dtj_aggval_t *e;
593 
594 	if (!dtj_check_aggval_pool()) {
595 		dtj_throw_out_of_memory(jenv,
596 		    "Failed to allocate aggval entry pool");
597 		return (NULL);
598 	}
599 
600 	e = uu_zalloc(sizeof (dtj_aggval_t));
601 	if (e) {
602 		char *a_name;
603 
604 		uu_list_node_init(e, &e->dtja_node, g_aggval_pool);
605 		e->dtja_value = aggval;
606 		a_name = malloc((size_t)
607 		    (sizeof (char)) * (strlen(aggname) + 1));
608 		if (a_name) {
609 			(void) strcpy(a_name, aggname);
610 			e->dtja_aggname = a_name;
611 		} else {
612 			dtj_throw_out_of_memory(jenv,
613 			    "Failed to allocate aggregation name");
614 			uu_list_node_fini(e, &e->dtja_node, g_aggval_pool);
615 			/* caller responsible for input java reference */
616 			e->dtja_value = NULL;
617 			dtj_aggval_destroy(e, jenv);
618 			e = NULL;
619 		}
620 		e->dtja_aggid = aggid;
621 	} else {
622 		dtj_throw_out_of_memory(jenv,
623 		    "Failed to allocate aggval entry");
624 	}
625 
626 	return (e);
627 }
628 
629 dtj_status_t
630 dtj_java_consumer_init(JNIEnv *jenv, dtj_java_consumer_t *jc)
631 {
632 	if (!dtj_check_aggval_pool()) {
633 		dtj_throw_out_of_memory(jenv,
634 		    "Failed to allocate aggval pool");
635 		return (DTJ_ERR);
636 	}
637 
638 	jc->dtjj_aggval_list = uu_list_create(g_aggval_pool, NULL,
639 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
640 	if (!jc->dtjj_aggval_list) {
641 		dtj_throw_out_of_memory(jenv,
642 		    "Failed to allocate aggval list");
643 		return (DTJ_ERR);
644 	}
645 
646 	/* Does not throw exceptions */
647 	jc->dtjj_consumer_lock = (*jenv)->GetObjectField(jenv, jc->dtjj_caller,
648 	    g_consumer_lock_jf);
649 
650 	return (DTJ_OK);
651 }
652 
653 void
654 dtj_java_consumer_fini(JNIEnv *jenv, dtj_java_consumer_t *jc)
655 {
656 	if (jc) {
657 		if (jc->dtjj_probedata) {
658 			(*jenv)->DeleteLocalRef(jenv, jc->dtjj_probedata);
659 			jc->dtjj_probedata = NULL;
660 		}
661 		if (jc->dtjj_printa_buffer) {
662 			(*jenv)->DeleteLocalRef(jenv, jc->dtjj_printa_buffer);
663 			jc->dtjj_printa_buffer = NULL;
664 		}
665 		if (jc->dtjj_aggregate) {
666 			(*jenv)->DeleteLocalRef(jenv, jc->dtjj_aggregate);
667 			jc->dtjj_aggregate = NULL;
668 		}
669 		if (jc->dtjj_tuple) {
670 			(*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple);
671 			jc->dtjj_tuple = NULL;
672 		}
673 		if (jc->dtjj_aggval_list) {
674 			dtj_list_destroy(jc->dtjj_aggval_list,
675 			    dtj_aggval_destroy, jenv);
676 			jc->dtjj_aggval_list = NULL;
677 		}
678 
679 		/*
680 		 * aggregate_spec records an input argument to a native JNI
681 		 * function (a reference we did not create), so we are not
682 		 * responsible for it.
683 		 */
684 		jc->dtjj_aggregate_spec = NULL;
685 
686 		/*
687 		 * probelist records an in-out argument to a native JNI function
688 		 * (a reference we did not create), so we are not responsible
689 		 * for it.
690 		 */
691 		jc->dtjj_probelist = NULL;
692 
693 		if (jc->dtjj_exception) {
694 			(*jenv)->DeleteLocalRef(jenv, jc->dtjj_exception);
695 			jc->dtjj_exception = NULL;
696 		}
697 		(*jenv)->DeleteLocalRef(jenv, jc->dtjj_consumer_lock);
698 		jc->dtjj_consumer_lock = NULL;
699 	}
700 }
701 
702 dtj_consumer_t *
703 dtj_consumer_create(JNIEnv *jenv)
704 {
705 	dtj_consumer_t *c;
706 
707 	if (!dtj_check_request_pool()) {
708 		dtj_throw_out_of_memory(jenv,
709 		    "Failed to allocate request pool");
710 		return (NULL);
711 	}
712 
713 	if (!dtj_check_program_pool()) {
714 		dtj_throw_out_of_memory(jenv,
715 		    "Failed to allocate program pool");
716 		return (NULL);
717 	}
718 
719 	c = uu_zalloc(sizeof (dtj_consumer_t));
720 	if (c) {
721 		c->dtjc_request_list = uu_list_create(g_request_pool, NULL,
722 		    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
723 		if (!c->dtjc_request_list) {
724 			dtj_throw_out_of_memory(jenv,
725 			    "Failed to allocate consumer request list");
726 			dtj_consumer_destroy(c);
727 			return (NULL);
728 		}
729 		(void) pthread_mutex_init(&c->dtjc_request_list_lock, NULL);
730 
731 		c->dtjc_program_list = uu_list_create(g_program_pool, NULL,
732 		    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
733 		if (!c->dtjc_program_list) {
734 			dtj_throw_out_of_memory(jenv,
735 			    "Failed to allocate consumer program list");
736 			dtj_consumer_destroy(c);
737 			return (NULL);
738 		}
739 
740 		c->dtjc_probedata_rec_i = 0;
741 		c->dtjc_probedata_act = DTRACEACT_NONE;
742 		c->dtjc_aggid = -1;
743 		c->dtjc_expected = -1;
744 		c->dtjc_state = DTJ_CONSUMER_INIT;
745 	} else {
746 		dtj_throw_out_of_memory(jenv,
747 		    "Failed to allocate consumer");
748 	}
749 
750 	return (c);
751 }
752 
753 void
754 /* ARGSUSED */
755 dtj_request_destroy(void *v, void *arg)
756 {
757 	if (v) {
758 		dtj_request_t *r = v;
759 		dtj_string_list_destroy(r->dtjr_args);
760 		uu_list_node_fini(r, &r->dtjr_node, g_request_pool);
761 		bzero(v, sizeof (dtj_request_t));
762 		uu_free(v);
763 	}
764 }
765 
766 void
767 /* ARGSUSED */
768 dtj_program_destroy(void *v, void *arg)
769 {
770 	if (v) {
771 		dtj_program_t *p = v;
772 		if (p->dtjp_name) {
773 			free((void *)p->dtjp_name);
774 		}
775 		uu_list_node_fini(p, &p->dtjp_node, g_program_pool);
776 		bzero(v, sizeof (dtj_program_t));
777 		uu_free(v);
778 	}
779 }
780 
781 void
782 dtj_aggval_destroy(void *v, void *arg)
783 {
784 	if (v) {
785 		dtj_aggval_t *a = v;
786 		if (a->dtja_value && arg) {
787 			JNIEnv *jenv = arg;
788 			(*jenv)->DeleteLocalRef(jenv, a->dtja_value);
789 		}
790 		if (a->dtja_aggname) {
791 			free((void *)a->dtja_aggname);
792 		}
793 		uu_list_node_fini(a, &a->dtja_node, g_aggval_pool);
794 		bzero(v, sizeof (dtj_aggval_t));
795 		uu_free(v);
796 	}
797 }
798 
799 /*
800  * Frees per-consumer state.  Assumes that the DTrace handle has been closed
801  * already.
802  */
803 void
804 dtj_consumer_destroy(dtj_consumer_t *c)
805 {
806 	if (c) {
807 		dtj_list_destroy(c->dtjc_request_list, dtj_request_destroy,
808 		    NULL);
809 		(void) pthread_mutex_destroy(&c->dtjc_request_list_lock);
810 		dtj_list_destroy(c->dtjc_program_list, dtj_program_destroy,
811 		    NULL);
812 		/*
813 		 * Cannot dtrace_proc_release the c->process_list proc
814 		 * elements here, because we need the dtrace handle for that.
815 		 * By the time this destructor is called, the dtrace handle is
816 		 * already closed.  The proc elements are released in
817 		 * dtrace_jni.c _close().
818 		 */
819 		if (c->dtjc_process_list) {
820 			dtj_list_destroy(c->dtjc_process_list, NULL, NULL);
821 		}
822 		bzero(c, sizeof (dtj_consumer_t));
823 		uu_free(c);
824 	}
825 }
826 
827 void
828 dtj_throw_dtrace_exception(dtj_java_consumer_t *jc, const char *fmt, ...)
829 {
830 	JNIEnv *jenv = jc->dtjj_jenv;
831 
832 	va_list ap;
833 	char msg[DTJ_MSG_SIZE];
834 
835 	jobject message = NULL;
836 	jobject exception = NULL;
837 
838 	va_start(ap, fmt);
839 	(void) vsnprintf(msg, sizeof (msg), fmt, ap);
840 	va_end(ap);
841 
842 	message = dtj_NewStringNative(jenv, msg);
843 	if (!message) {
844 		return; /* java exception pending */
845 	}
846 
847 	exception = (*jenv)->NewObject(jenv, g_dtx_jc, g_dtxinit_jm, message);
848 	(*jenv)->DeleteLocalRef(jenv, message);
849 	if (exception) {
850 		(*jenv)->Throw(jenv, exception);
851 		(*jenv)->DeleteLocalRef(jenv, exception);
852 	}
853 }
854