xref: /illumos-gate/usr/src/lib/libdtrace_jni/common/dtrace_jni.h (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 #ifndef	_DTRACE_JNI_H
28 #define	_DTRACE_JNI_H
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <libuutil.h>
33 #include <jni.h>
34 #include <dtrace.h>
35 #include <dtj_util.h>
36 
37 #ifdef	__cplusplus
38 extern "C" {
39 #endif
40 
41 /* Java DTrace API native library */
42 
43 
44 /*
45  * Thread-specific data key used to obtain JNI state specific to either the
46  * consumer loop (calls dtrace_work()) or the getAggregate() method (calls
47  * dtrace_aggregate_print()).
48  */
49 extern pthread_key_t g_dtj_consumer_key;
50 
51 typedef enum dtj_consumer_state {
52 	DTJ_CONSUMER_INIT,
53 	DTJ_CONSUMER_GO,
54 	DTJ_CONSUMER_START,
55 	DTJ_CONSUMER_STOP
56 } dtj_consumer_state_t;
57 
58 typedef struct dtj_error {
59 	int dtje_number;		/* dtrace_errno() */
60 	const char *dtje_message;	/* dtrace_errmsg() */
61 } dtj_error_t;
62 
63 /*
64  * Identifies which function should handle a request dequeued after
65  * dtrace_sleep().
66  */
67 typedef enum dtj_request_type {
68 	DTJ_REQUEST_OPTION		/* set DTrace runtime option */
69 } dtj_request_type_t;
70 
71 /*
72  * A request made from Java (by native method call) that is unsafe to process
73  * until just after the consumer loop wakes up from dtrace_sleep().
74  */
75 typedef struct dtj_request {
76 	dtj_request_type_t dtjr_type;	/* request handler ID */
77 	uu_list_t *dtjr_args;		/* string args to request handler */
78 	uu_list_node_t dtjr_node;	/* points to next and prev requests */
79 } dtj_request_t;
80 
81 typedef enum dtj_program_type {
82 	DTJ_PROGRAM_NONE,
83 	DTJ_PROGRAM_STRING,		/* dtrace_program_strcompile() */
84 	DTJ_PROGRAM_FILE		/* dtrace_program_fcompile() */
85 } dtj_program_type_t;
86 
87 /* Identifier and description of a compiled DTrace program */
88 typedef struct dtj_program {
89 	dtj_program_type_t dtjp_type;	/* string or file */
90 	const char *dtjp_name;		/* string or filename for err msg */
91 	dtrace_prog_t *dtjp_program;	/* libdtrace program handle */
92 	dtrace_proginfo_t dtjp_info;	/* program attributes */
93 	boolean_t dtjp_enabled;		/* dtrace_program_exec() flag */
94 	uu_list_node_t dtjp_node;	/* points to next and prev programs */
95 } dtj_program_t;
96 
97 /*
98  * An entry used to maintain the association between the value of an aggregating
99  * action (such as count()) and the aggregation to which the value belongs until
100  * all the data associated with a single tuple is available to the callback
101  * handler.
102  */
103 typedef struct dtj_aggval {
104 	jobject dtja_value;		/* value of aggregating action */
105 	const char *dtja_aggname;	/* aggregation name */
106 	int64_t dtja_aggid;		/* libdtrace aggregation ID */
107 	uu_list_node_t dtja_node;	/* points to next and prev aggvals */
108 } dtj_aggval_t;
109 
110 /*
111  * Per-consumer state, including the libdtrace consumer handle, is valid across
112  * multiple threads.  One consumer entry is added to a global table per
113  * dtrace_open().
114  */
115 typedef struct dtj_consumer {
116 	/* Consumer state */
117 
118 	dtrace_hdl_t *dtjc_dtp;		/* libdtrace consumer handle */
119 	uu_list_t *dtjc_program_list;	/* program_t list */
120 	uu_list_t *dtjc_process_list;	/* proc handle list */
121 
122 	/*
123 	 * Count of processes that have ended.  The consumer is stopped when
124 	 * this count equals the number of outstanding target processes and
125 	 * grabbed processes (see the Java Consumer createProcess() and
126 	 * grabProcess() methods).
127 	 */
128 	int dtjc_procs_ended;
129 
130 	/*
131 	 * Bit-field passed to dtrace_program_strcompile() and
132 	 * dtrace_program_fcompile() containing compile flags.  The flags are
133 	 * set from Java by the setOption() Consumer method (just like the
134 	 * runtime options handled by dtrace_setopt(), except that they must be
135 	 * set before program compilation to have any effect).
136 	 */
137 	uint_t dtjc_cflags;
138 
139 	boolean_t dtjc_flow;	/* current value of the flowindent option */
140 	dtj_consumer_state_t dtjc_state; /* execution state */
141 	boolean_t dtjc_interrupt;	/* flag that stops consumer */
142 
143 	/* Pending requests */
144 	uu_list_t *dtjc_request_list;	/* request_t queue */
145 	pthread_mutex_t dtjc_request_list_lock;
146 
147 
148 	/* Cached for optimization and for use across functions */
149 
150 	/*
151 	 * Nanosecond timestamp cached in the consumer loop just before
152 	 * dtrace_work().  The timestamp is applied to each Java PrintaRecord
153 	 * generated in that iteration of the consumer loop.  A value of zero
154 	 * indicates that we are not in the consumer loop, but that the
155 	 * callback was triggered instead by the Consumer getAggregate() method
156 	 * (from dtrace_aggregate_print()).
157 	 */
158 	hrtime_t dtjc_printa_snaptime;
159 
160 	/*
161 	 * The aggregation ID is used to optimize aggregation inclusion by
162 	 * testing for inclusion only when the aggregation has changed.
163 	 */
164 	int64_t dtjc_aggid;
165 	boolean_t dtjc_included;
166 
167 	/*
168 	 * The expected tuple member count is used to determine whether or not
169 	 * the aggregation tuple values are completely specified in the printa()
170 	 * format string.
171 	 */
172 	int dtjc_expected;
173 
174 	int dtjc_probedata_rec_i;	/* probe data record index */
175 
176 	/*
177 	 * The current DTrace action may apply across multiple libdtrace probe
178 	 * data records.
179 	 */
180 	dtrace_actkind_t dtjc_probedata_act;
181 
182 	/* Placeholder used when listing probes */
183 	dtrace_ecbdesc_t *dtjc_last_probe;
184 
185 	/* Function used by statement iterator when listing probes */
186 	dtrace_probe_f *dtjc_plistfunc;
187 } dtj_consumer_t;
188 
189 /*
190  * A view of a dtj_consumer_t that lasts only as long as a single native method
191  * call.  This view attaches state needed for interaction with Java and specific
192  * to the JNI.
193  */
194 typedef struct dtj_java_consumer {
195 	/* Per-consumer state in global consumer table */
196 	dtj_consumer_t *dtjj_consumer;
197 
198 	JNIEnv *dtjj_jenv;	/* Java environment pointer */
199 	jobject dtjj_caller;	/* Java Consumer to call back with probe data */
200 
201 	/*
202 	 * Java Object references used across function boundaries, valid only
203 	 * within the current native method call.
204 	 */
205 
206 	jobject dtjj_probedata;	/* instance of class ProbeData */
207 
208 	/*
209 	 * StringBuffer used to concatenate buffered printa() output associated
210 	 * with the current tuple.
211 	 */
212 	jobject dtjj_printa_buffer;
213 
214 	jobject dtjj_aggregate;	/* instance of class Aggregate */
215 	jobject dtjj_tuple;	/* instance of class Tuple */
216 
217 	/*
218 	 * AggregationValue instances cached until we receive the
219 	 * DTRACE_BUFDATA_AGGLAST flag indicating the last callback associated
220 	 * with the current tuple.
221 	 */
222 	uu_list_t *dtjj_aggval_list;
223 
224 	/* AggregateSpec used by get_aggregate() */
225 	jobject dtjj_aggregate_spec;
226 
227 	jobject dtjj_probelist;	/* java.util.List returned by listProbes() */
228 
229 	/*
230 	 * Exception temporarily cleared by callback handlers who cannot return
231 	 * a signal to abort the consumer.  At a safe point when the consumer
232 	 * loop gets control back from libdtrace, the exception is rethrown.
233 	 */
234 	jthrowable dtjj_exception;
235 
236 	jobject dtjj_consumer_lock; /* per-consumer lock */
237 
238 } dtj_java_consumer_t;
239 
240 /*
241  * Cache of jclass, jmethodID, and jfieldID values, usable across multiple
242  * native method calls and multiple threads.  Caching all of them up front
243  * rather than as-needed guarantees early detection of incorrect class, method,
244  * or field definitions, and eliminates the need for test cases to cover
245  * seldom-used definitions.
246  *
247  * Suffix conventions:
248  *   jc  java class
249  *   jm  java method
250  *   jsm java static method
251  *   jf  java field
252  *   jsf java static field
253  */
254 
255 /* LocalConsumer */
256 extern jclass g_caller_jc;
257 extern jmethodID g_gethandle_jm;
258 extern jmethodID g_sethandle_jm;
259 extern jmethodID g_pdatanext_jm;
260 extern jmethodID g_drop_jm;
261 extern jmethodID g_error_jm;
262 extern jmethodID g_proc_jm;
263 extern jmethodID g_interval_began_jm;
264 extern jmethodID g_interval_ended_jm;
265 extern jfieldID g_consumer_lock_jf;
266 
267 /* DTraceException */
268 extern jclass g_dtx_jc;
269 extern jmethodID g_dtxinit_jm;
270 
271 /* InterfaceAttributes */
272 extern jclass g_attr_jc;
273 extern jmethodID g_attrinit_jm;
274 extern jmethodID g_attrset_name_jm;
275 extern jmethodID g_attrset_data_jm;
276 extern jmethodID g_attrset_class_jm;
277 
278 /* ProbeDescription */
279 extern jclass g_probedesc_jc;
280 extern jmethodID g_probedescinit_jm;
281 extern jfieldID g_probedesc_id_jf;
282 
283 /* ProbeInfo */
284 extern jclass g_probeinfo_jc;
285 extern jmethodID g_probeinfoinit_jm;
286 
287 /* Probe */
288 extern jclass g_probe_jc;
289 extern jmethodID g_probeinit_jm;
290 
291 /* Program */
292 extern jclass g_program_jc;
293 extern jmethodID g_proginit_jm;
294 extern jfieldID g_progid_jf;
295 extern jfieldID g_proginfo_jf;
296 
297 /* Program.File */
298 extern jclass g_programfile_jc;
299 extern jmethodID g_fproginit_jm;
300 
301 /* ProgramInfo */
302 extern jclass g_proginfo_jc;
303 extern jmethodID g_proginfoinit_jm;
304 
305 /* Flow */
306 extern jclass g_flow_jc;
307 extern jmethodID g_flowinit_jm;
308 
309 /* ProbeData */
310 extern jclass g_pdata_jc;
311 extern jmethodID g_pdatainit_jm;
312 extern jmethodID g_pdataadd_jm;
313 extern jmethodID g_pdataadd_rec_jm;
314 extern jmethodID g_pdataadd_trace_jm;
315 extern jmethodID g_pdataadd_stack_jm;
316 extern jmethodID g_pdataadd_symbol_jm;
317 extern jmethodID g_pdataadd_printf_jm;
318 extern jmethodID g_pdataadd_printa_jm;
319 extern jmethodID g_pdatainvalidate_printa_jm;
320 extern jmethodID g_pdataadd_aggrec_jm;
321 extern jmethodID g_pdataadd_printa_str_jm;
322 extern jmethodID g_pdataadd_exit_jm;
323 extern jmethodID g_pdataattach_jm;
324 extern jmethodID g_pdataset_formatted_jm;
325 extern jmethodID g_pdataclear_jm;
326 
327 /* Drop */
328 extern jclass g_drop_jc;
329 extern jmethodID g_dropinit_jm;
330 
331 /* Error */
332 extern jclass g_error_jc;
333 extern jmethodID g_errinit_jm;
334 
335 /* ProcessState */
336 extern jclass g_process_jc;
337 extern jmethodID g_procinit_jm;
338 extern jmethodID g_procexit_jm;
339 
340 /* Aggregate */
341 extern jclass g_agg_jc;
342 extern jmethodID g_agginit_jm;
343 extern jmethodID g_aggaddrec_jm;
344 
345 /* AggregateSpec */
346 extern jclass g_aggspec_jc;
347 extern jmethodID g_aggspec_included_jm;
348 extern jmethodID g_aggspec_cleared_jm;
349 
350 /* Tuple */
351 extern jclass g_tuple_jc;
352 extern jmethodID g_tupleinit_jm;
353 extern jmethodID g_tupleadd_jm;
354 extern jmethodID g_tuplesize_jm;
355 extern jfieldID g_tuple_EMPTY_jsf;
356 
357 /* AggregationRecord */
358 extern jclass g_aggrec_jc;
359 extern jmethodID g_aggrecinit_jm;
360 extern jmethodID g_aggrecget_tuple_jm;
361 
362 /* SumValue */
363 extern jclass g_aggsum_jc;
364 extern jmethodID g_aggsuminit_jm;
365 
366 /* CountValue */
367 extern jclass g_aggcount_jc;
368 extern jmethodID g_aggcountinit_jm;
369 
370 /* AvgValue */
371 extern jclass g_aggavg_jc;
372 extern jmethodID g_aggavginit_jm;
373 
374 /* MinValue */
375 extern jclass g_aggmin_jc;
376 extern jmethodID g_aggmininit_jm;
377 
378 /* MaxValue */
379 extern jclass g_aggmax_jc;
380 extern jmethodID g_aggmaxinit_jm;
381 
382 /* StddevValue */
383 extern jclass g_aggstddev_jc;
384 extern jmethodID g_aggstddevinit_jm;
385 
386 /* KernelStackRecord */
387 extern jclass g_stack_jc;
388 extern jmethodID g_parsestack_jsm;
389 extern jmethodID g_stackinit_jm;
390 extern jmethodID g_stackset_frames_jm;
391 
392 /* UserStackRecord */
393 extern jclass g_ustack_jc;
394 extern jmethodID g_ustackinit_jm;
395 extern jmethodID g_ustackset_frames_jm;
396 
397 /* Distribution */
398 extern jclass g_adist_jc;
399 extern jmethodID g_dist_normal_jm;
400 
401 /* LogDistribution */
402 extern jclass g_dist_jc;
403 extern jmethodID g_distinit_jm;
404 
405 /* LinearDistribution */
406 extern jclass g_ldist_jc;
407 extern jmethodID g_ldistinit_jm;
408 
409 /* KernelSymbolRecord */
410 extern jclass g_symbol_jc;
411 extern jmethodID g_symbolinit_jm;
412 extern jmethodID g_symbolset_name_jm;
413 
414 /* UserSymbolRecord */
415 extern jclass g_usymbol_jc;
416 extern jmethodID g_usymbolinit_jm;
417 extern jmethodID g_usymbolset_name_jm;
418 
419 /* ScalarRecord */
420 extern jclass g_scalar_jc;
421 extern jmethodID g_scalarinit_jm;
422 
423 /*
424  * Populates the java class references and associated method and field IDs
425  * declared in this file (above).
426  *
427  * Throws NoClassDefFoundError, NoSuchMethodError, or NoSuchFieldError if any
428  * dtj_table_entry_t in dtj_jnitab.c is incorrect.
429  */
430 extern dtj_status_t dtj_load(JNIEnv *);
431 
432 /*
433  * Functions that create a structure return NULL if out of memory.  A Java
434  * OutOfMemoryError is pending in that case.
435  */
436 extern dtj_request_t *dtj_request_create(JNIEnv *, dtj_request_type_t, ...);
437 extern dtj_program_t *dtj_program_create(JNIEnv *, dtj_program_type_t,
438     const char *);
439 extern dtj_aggval_t *dtj_aggval_create(JNIEnv *, jobject, const char *,
440     int64_t);
441 
442 /*
443  * uu_list_t element destructors' signatures match uuwrap_value_destroy_f
444  */
445 extern void dtj_request_destroy(void *, void *); /* expects NULL user arg */
446 extern void dtj_program_destroy(void *, void *); /* expects NULL user arg */
447 extern void dtj_aggval_destroy(void *, void *);	/* expects JNIEnv * user arg */
448 
449 /* Allocates and frees per-consumer state kept in the global consumer table */
450 extern dtj_consumer_t *dtj_consumer_create(JNIEnv *);
451 extern void dtj_consumer_destroy(dtj_consumer_t *);
452 
453 /* Sets callback handlers before calling dtrace_go() */
454 extern dtj_status_t dtj_set_callback_handlers(dtj_java_consumer_t *);
455 
456 /*
457  * Initializes Java Object references cached across multiple functions called
458  * within the consumer loop.  Deletes the references after exiting the consumer
459  * loop.  It is only necessary to initialize and finalize a dtj_java_consumer_t
460  * if the native method call will enter the consumer loop.
461  */
462 extern dtj_status_t dtj_java_consumer_init(JNIEnv *, dtj_java_consumer_t *);
463 extern void dtj_java_consumer_fini(JNIEnv *, dtj_java_consumer_t *);
464 
465 /*
466  * Throws a DTraceException with a message constructed from the given format
467  * string and variable arg list.
468  */
469 extern void dtj_throw_dtrace_exception(dtj_java_consumer_t *,
470     const char *, ...);
471 
472 /* Returns NULL if pending Java Exception or OutOfMemoryError */
473 extern jobject dtj_new_probedesc(dtj_java_consumer_t *,
474     const dtrace_probedesc_t *);
475 extern jobject dtj_new_probeinfo(dtj_java_consumer_t *,
476     const dtrace_probeinfo_t *);
477 extern jobject dtj_new_attribute(dtj_java_consumer_t *,
478     const dtrace_attribute_t *);
479 
480 /*
481  * Returns NULL if the given fault is unrecognized, otherwise returns the name
482  * of the fault, guaranteed not to change across multiple versions of this API
483  * even if the integer value changes in libdtrace.
484  */
485 extern const char *dtj_get_fault_name(int);
486 
487 /* Gets the libdtrace error number and message */
488 extern dtj_status_t dtj_get_dtrace_error(dtj_java_consumer_t *, dtj_error_t *);
489 
490 /* Stops the DTrace consumer */
491 extern void dtj_stop(dtj_java_consumer_t *);
492 
493 /*
494  * The Consumer getAggregate() method runs in the caller's current thread
495  * separate from the consumer loop.
496  */
497 extern jobject dtj_get_aggregate(dtj_java_consumer_t *);
498 
499 /*
500  * A blocking call that runs the consumer loop.  If this function returns an
501  * error status, it is necessary to call stop() in order to dtrace_stop() the
502  * consumer in libdtrace (it is safe to call stop() in either case).
503  */
504 extern dtj_status_t dtj_consume(dtj_java_consumer_t *);
505 
506 #ifdef	__cplusplus
507 }
508 #endif
509 
510 #endif	/* _DTRACE_JNI_H */
511