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