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
38extern "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 */
49extern pthread_key_t g_dtj_consumer_key;
50
51typedef 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
58typedef 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 */
67typedef 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 */
75typedef 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
81typedef 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 */
88typedef 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 */
103typedef 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 */
115typedef 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 */
194typedef 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 */
256extern jclass g_caller_jc;
257extern jmethodID g_gethandle_jm;
258extern jmethodID g_sethandle_jm;
259extern jmethodID g_pdatanext_jm;
260extern jmethodID g_drop_jm;
261extern jmethodID g_error_jm;
262extern jmethodID g_proc_jm;
263extern jmethodID g_interval_began_jm;
264extern jmethodID g_interval_ended_jm;
265extern jfieldID g_consumer_lock_jf;
266
267/* DTraceException */
268extern jclass g_dtx_jc;
269extern jmethodID g_dtxinit_jm;
270
271/* InterfaceAttributes */
272extern jclass g_attr_jc;
273extern jmethodID g_attrinit_jm;
274extern jmethodID g_attrset_name_jm;
275extern jmethodID g_attrset_data_jm;
276extern jmethodID g_attrset_class_jm;
277
278/* ProbeDescription */
279extern jclass g_probedesc_jc;
280extern jmethodID g_probedescinit_jm;
281extern jfieldID g_probedesc_id_jf;
282
283/* ProbeInfo */
284extern jclass g_probeinfo_jc;
285extern jmethodID g_probeinfoinit_jm;
286
287/* Probe */
288extern jclass g_probe_jc;
289extern jmethodID g_probeinit_jm;
290
291/* Program */
292extern jclass g_program_jc;
293extern jmethodID g_proginit_jm;
294extern jfieldID g_progid_jf;
295extern jfieldID g_proginfo_jf;
296
297/* Program.File */
298extern jclass g_programfile_jc;
299extern jmethodID g_fproginit_jm;
300
301/* ProgramInfo */
302extern jclass g_proginfo_jc;
303extern jmethodID g_proginfoinit_jm;
304
305/* Flow */
306extern jclass g_flow_jc;
307extern jmethodID g_flowinit_jm;
308
309/* ProbeData */
310extern jclass g_pdata_jc;
311extern jmethodID g_pdatainit_jm;
312extern jmethodID g_pdataadd_jm;
313extern jmethodID g_pdataadd_rec_jm;
314extern jmethodID g_pdataadd_trace_jm;
315extern jmethodID g_pdataadd_stack_jm;
316extern jmethodID g_pdataadd_symbol_jm;
317extern jmethodID g_pdataadd_printf_jm;
318extern jmethodID g_pdataadd_printa_jm;
319extern jmethodID g_pdatainvalidate_printa_jm;
320extern jmethodID g_pdataadd_aggrec_jm;
321extern jmethodID g_pdataadd_printa_str_jm;
322extern jmethodID g_pdataadd_exit_jm;
323extern jmethodID g_pdataattach_jm;
324extern jmethodID g_pdataset_formatted_jm;
325extern jmethodID g_pdataclear_jm;
326
327/* Drop */
328extern jclass g_drop_jc;
329extern jmethodID g_dropinit_jm;
330
331/* Error */
332extern jclass g_error_jc;
333extern jmethodID g_errinit_jm;
334
335/* ProcessState */
336extern jclass g_process_jc;
337extern jmethodID g_procinit_jm;
338extern jmethodID g_procexit_jm;
339
340/* Aggregate */
341extern jclass g_agg_jc;
342extern jmethodID g_agginit_jm;
343extern jmethodID g_aggaddrec_jm;
344
345/* AggregateSpec */
346extern jclass g_aggspec_jc;
347extern jmethodID g_aggspec_included_jm;
348extern jmethodID g_aggspec_cleared_jm;
349
350/* Tuple */
351extern jclass g_tuple_jc;
352extern jmethodID g_tupleinit_jm;
353extern jmethodID g_tupleadd_jm;
354extern jmethodID g_tuplesize_jm;
355extern jfieldID g_tuple_EMPTY_jsf;
356
357/* AggregationRecord */
358extern jclass g_aggrec_jc;
359extern jmethodID g_aggrecinit_jm;
360extern jmethodID g_aggrecget_tuple_jm;
361
362/* SumValue */
363extern jclass g_aggsum_jc;
364extern jmethodID g_aggsuminit_jm;
365
366/* CountValue */
367extern jclass g_aggcount_jc;
368extern jmethodID g_aggcountinit_jm;
369
370/* AvgValue */
371extern jclass g_aggavg_jc;
372extern jmethodID g_aggavginit_jm;
373
374/* MinValue */
375extern jclass g_aggmin_jc;
376extern jmethodID g_aggmininit_jm;
377
378/* MaxValue */
379extern jclass g_aggmax_jc;
380extern jmethodID g_aggmaxinit_jm;
381
382/* StddevValue */
383extern jclass g_aggstddev_jc;
384extern jmethodID g_aggstddevinit_jm;
385
386/* KernelStackRecord */
387extern jclass g_stack_jc;
388extern jmethodID g_parsestack_jsm;
389extern jmethodID g_stackinit_jm;
390extern jmethodID g_stackset_frames_jm;
391
392/* UserStackRecord */
393extern jclass g_ustack_jc;
394extern jmethodID g_ustackinit_jm;
395extern jmethodID g_ustackset_frames_jm;
396
397/* Distribution */
398extern jclass g_adist_jc;
399extern jmethodID g_dist_normal_jm;
400
401/* LogDistribution */
402extern jclass g_dist_jc;
403extern jmethodID g_distinit_jm;
404
405/* LinearDistribution */
406extern jclass g_ldist_jc;
407extern jmethodID g_ldistinit_jm;
408
409/* KernelSymbolRecord */
410extern jclass g_symbol_jc;
411extern jmethodID g_symbolinit_jm;
412extern jmethodID g_symbolset_name_jm;
413
414/* UserSymbolRecord */
415extern jclass g_usymbol_jc;
416extern jmethodID g_usymbolinit_jm;
417extern jmethodID g_usymbolset_name_jm;
418
419/* ScalarRecord */
420extern jclass g_scalar_jc;
421extern 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 */
430extern 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 */
436extern dtj_request_t *dtj_request_create(JNIEnv *, dtj_request_type_t, ...);
437extern dtj_program_t *dtj_program_create(JNIEnv *, dtj_program_type_t,
438    const char *);
439extern 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 */
445extern void dtj_request_destroy(void *, void *); /* expects NULL user arg */
446extern void dtj_program_destroy(void *, void *); /* expects NULL user arg */
447extern void dtj_aggval_destroy(void *, void *);	/* expects JNIEnv * user arg */
448
449/* Allocates and frees per-consumer state kept in the global consumer table */
450extern dtj_consumer_t *dtj_consumer_create(JNIEnv *);
451extern void dtj_consumer_destroy(dtj_consumer_t *);
452
453/* Sets callback handlers before calling dtrace_go() */
454extern 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 */
462extern dtj_status_t dtj_java_consumer_init(JNIEnv *, dtj_java_consumer_t *);
463extern 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 */
469extern void dtj_throw_dtrace_exception(dtj_java_consumer_t *,
470    const char *, ...);
471
472/* Returns NULL if pending Java Exception or OutOfMemoryError */
473extern jobject dtj_new_probedesc(dtj_java_consumer_t *,
474    const dtrace_probedesc_t *);
475extern jobject dtj_new_probeinfo(dtj_java_consumer_t *,
476    const dtrace_probeinfo_t *);
477extern 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 */
485extern const char *dtj_get_fault_name(int);
486
487/* Gets the libdtrace error number and message */
488extern dtj_status_t dtj_get_dtrace_error(dtj_java_consumer_t *, dtj_error_t *);
489
490/* Stops the DTrace consumer */
491extern 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 */
497extern 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 */
504extern dtj_status_t dtj_consume(dtj_java_consumer_t *);
505
506#ifdef	__cplusplus
507}
508#endif
509
510#endif	/* _DTRACE_JNI_H */
511