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