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