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