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
dtj_table_load(JNIEnv * jenv)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
dtj_load(JNIEnv * jenv)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
dtj_check_request_pool(void)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 *
dtj_request_create(JNIEnv * jenv,dtj_request_type_t type,...)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
dtj_check_program_pool(void)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 *
dtj_program_create(JNIEnv * jenv,dtj_program_type_t type,const char * name)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
dtj_check_aggval_pool(void)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 *
dtj_aggval_create(JNIEnv * jenv,jobject aggval,const char * aggname,int64_t aggid)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
dtj_java_consumer_init(JNIEnv * jenv,dtj_java_consumer_t * jc)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
dtj_java_consumer_fini(JNIEnv * jenv,dtj_java_consumer_t * jc)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 *
dtj_consumer_create(JNIEnv * jenv)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 */
dtj_request_destroy(void * v,void * arg)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 */
dtj_program_destroy(void * v,void * arg)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
dtj_aggval_destroy(void * v,void * arg)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
dtj_consumer_destroy(dtj_consumer_t * c)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
dtj_throw_dtrace_exception(dtj_java_consumer_t * jc,const char * fmt,...)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