summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdtrace_jni/common/dtrace_jni.h
blob: 9068f7eb5b1eaeb57658ac09971ffc23d3f073c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_DTRACE_JNI_H
#define	_DTRACE_JNI_H

#include <libuutil.h>
#include <jni.h>
#include <dtrace.h>
#include <dtj_util.h>

#ifdef	__cplusplus
extern "C" {
#endif

/* Java DTrace API native library */


/*
 * Thread-specific data key used to obtain JNI state specific to either the
 * consumer loop (calls dtrace_work()) or the getAggregate() method (calls
 * dtrace_aggregate_print()).
 */
extern pthread_key_t g_dtj_consumer_key;

typedef enum dtj_consumer_state {
	DTJ_CONSUMER_INIT,
	DTJ_CONSUMER_GO,
	DTJ_CONSUMER_START,
	DTJ_CONSUMER_STOP
} dtj_consumer_state_t;

typedef struct dtj_error {
	int dtje_number;		/* dtrace_errno() */
	const char *dtje_message;	/* dtrace_errmsg() */
} dtj_error_t;

/*
 * Identifies which function should handle a request dequeued after
 * dtrace_sleep().
 */
typedef enum dtj_request_type {
	DTJ_REQUEST_OPTION		/* set DTrace runtime option */
} dtj_request_type_t;

/*
 * A request made from Java (by native method call) that is unsafe to process
 * until just after the consumer loop wakes up from dtrace_sleep().
 */
typedef struct dtj_request {
	dtj_request_type_t dtjr_type;	/* request handler ID */
	uu_list_t *dtjr_args;		/* string args to request handler */
	uu_list_node_t dtjr_node;	/* points to next and prev requests */
} dtj_request_t;

typedef enum dtj_program_type {
	DTJ_PROGRAM_NONE,
	DTJ_PROGRAM_STRING,		/* dtrace_program_strcompile() */
	DTJ_PROGRAM_FILE		/* dtrace_program_fcompile() */
} dtj_program_type_t;

/* Identifier and description of a compiled DTrace program */
typedef struct dtj_program {
	dtj_program_type_t dtjp_type;	/* string or file */
	const char *dtjp_name;		/* string or filename for err msg */
	dtrace_prog_t *dtjp_program;	/* libdtrace program handle */
	dtrace_proginfo_t dtjp_info;	/* program attributes */
	boolean_t dtjp_enabled;		/* dtrace_program_exec() flag */
	uu_list_node_t dtjp_node;	/* points to next and prev programs */
} dtj_program_t;

/*
 * An entry used to maintain the association between the value of an aggregating
 * action (such as count()) and the aggregation to which the value belongs until
 * all the data associated with a single tuple is available to the callback
 * handler.
 */
typedef struct dtj_aggval {
	jobject dtja_value;		/* value of aggregating action */
	const char *dtja_aggname;	/* aggregation name */
	int64_t dtja_aggid;		/* libdtrace aggregation ID */
	uu_list_node_t dtja_node;	/* points to next and prev aggvals */
} dtj_aggval_t;

/*
 * Per-consumer state, including the libdtrace consumer handle, is valid across
 * multiple threads.  One consumer entry is added to a global table per
 * dtrace_open().
 */
typedef struct dtj_consumer {
	/* Consumer state */

	dtrace_hdl_t *dtjc_dtp;		/* libdtrace consumer handle */
	uu_list_t *dtjc_program_list;	/* program_t list */
	uu_list_t *dtjc_process_list;	/* proc handle list */

	/*
	 * Count of processes that have ended.  The consumer is stopped when
	 * this count equals the number of outstanding target processes and
	 * grabbed processes (see the Java Consumer createProcess() and
	 * grabProcess() methods).
	 */
	int dtjc_procs_ended;

	/*
	 * Bit-field passed to dtrace_program_strcompile() and
	 * dtrace_program_fcompile() containing compile flags.  The flags are
	 * set from Java by the setOption() Consumer method (just like the
	 * runtime options handled by dtrace_setopt(), except that they must be
	 * set before program compilation to have any effect).
	 */
	uint_t dtjc_cflags;

	boolean_t dtjc_flow;	/* current value of the flowindent option */
	dtj_consumer_state_t dtjc_state; /* execution state */
	boolean_t dtjc_interrupt;	/* flag that stops consumer */

	/* Pending requests */
	uu_list_t *dtjc_request_list;	/* request_t queue */
	pthread_mutex_t dtjc_request_list_lock;


	/* Cached for optimization and for use across functions */

	/*
	 * Nanosecond timestamp cached in the consumer loop just before
	 * dtrace_work().  The timestamp is applied to each Java PrintaRecord
	 * generated in that iteration of the consumer loop.  A value of zero
	 * indicates that we are not in the consumer loop, but that the
	 * callback was triggered instead by the Consumer getAggregate() method
	 * (from dtrace_aggregate_print()).
	 */
	hrtime_t dtjc_printa_snaptime;

	/*
	 * The aggregation ID is used to optimize aggregation inclusion by
	 * testing for inclusion only when the aggregation has changed.
	 */
	int64_t dtjc_aggid;
	boolean_t dtjc_included;

	/*
	 * The expected tuple member count is used to determine whether or not
	 * the aggregation tuple values are completely specified in the printa()
	 * format string.
	 */
	int dtjc_expected;

	int dtjc_probedata_rec_i;	/* probe data record index */

	/*
	 * The current DTrace action may apply across multiple libdtrace probe
	 * data records.
	 */
	dtrace_actkind_t dtjc_probedata_act;

	/* Placeholder used when listing probes */
	dtrace_ecbdesc_t *dtjc_last_probe;

	/* Function used by statement iterator when listing probes */
	dtrace_probe_f *dtjc_plistfunc;
} dtj_consumer_t;

/*
 * A view of a dtj_consumer_t that lasts only as long as a single native method
 * call.  This view attaches state needed for interaction with Java and specific
 * to the JNI.
 */
typedef struct dtj_java_consumer {
	/* Per-consumer state in global consumer table */
	dtj_consumer_t *dtjj_consumer;

	JNIEnv *dtjj_jenv;	/* Java environment pointer */
	jobject dtjj_caller;	/* Java Consumer to call back with probe data */

	/*
	 * Java Object references used across function boundaries, valid only
	 * within the current native method call.
	 */

	jobject dtjj_probedata;	/* instance of class ProbeData */

	/*
	 * StringBuffer used to concatenate buffered printa() output associated
	 * with the current tuple.
	 */
	jobject dtjj_printa_buffer;

	jobject dtjj_aggregate;	/* instance of class Aggregate */
	jobject dtjj_tuple;	/* instance of class Tuple */

	/*
	 * AggregationValue instances cached until we receive the
	 * DTRACE_BUFDATA_AGGLAST flag indicating the last callback associated
	 * with the current tuple.
	 */
	uu_list_t *dtjj_aggval_list;

	/* AggregateSpec used by get_aggregate() */
	jobject dtjj_aggregate_spec;

	jobject dtjj_probelist;	/* java.util.List returned by listProbes() */

	/*
	 * Exception temporarily cleared by callback handlers who cannot return
	 * a signal to abort the consumer.  At a safe point when the consumer
	 * loop gets control back from libdtrace, the exception is rethrown.
	 */
	jthrowable dtjj_exception;

	jobject dtjj_consumer_lock; /* per-consumer lock */

} dtj_java_consumer_t;

/*
 * Cache of jclass, jmethodID, and jfieldID values, usable across multiple
 * native method calls and multiple threads.  Caching all of them up front
 * rather than as-needed guarantees early detection of incorrect class, method,
 * or field definitions, and eliminates the need for test cases to cover
 * seldom-used definitions.
 *
 * Suffix conventions:
 *   jc  java class
 *   jm  java method
 *   jsm java static method
 *   jf  java field
 *   jsf java static field
 */

/* LocalConsumer */
extern jclass g_caller_jc;
extern jmethodID g_gethandle_jm;
extern jmethodID g_sethandle_jm;
extern jmethodID g_pdatanext_jm;
extern jmethodID g_drop_jm;
extern jmethodID g_error_jm;
extern jmethodID g_proc_jm;
extern jmethodID g_interval_began_jm;
extern jmethodID g_interval_ended_jm;
extern jfieldID g_consumer_lock_jf;

/* DTraceException */
extern jclass g_dtx_jc;
extern jmethodID g_dtxinit_jm;

/* InterfaceAttributes */
extern jclass g_attr_jc;
extern jmethodID g_attrinit_jm;
extern jmethodID g_attrset_name_jm;
extern jmethodID g_attrset_data_jm;
extern jmethodID g_attrset_class_jm;

/* ProbeDescription */
extern jclass g_probedesc_jc;
extern jmethodID g_probedescinit_jm;
extern jfieldID g_probedesc_id_jf;

/* ProbeInfo */
extern jclass g_probeinfo_jc;
extern jmethodID g_probeinfoinit_jm;

/* Probe */
extern jclass g_probe_jc;
extern jmethodID g_probeinit_jm;

/* Program */
extern jclass g_program_jc;
extern jmethodID g_proginit_jm;
extern jfieldID g_progid_jf;
extern jfieldID g_proginfo_jf;

/* Program.File */
extern jclass g_programfile_jc;
extern jmethodID g_fproginit_jm;

/* ProgramInfo */
extern jclass g_proginfo_jc;
extern jmethodID g_proginfoinit_jm;

/* Flow */
extern jclass g_flow_jc;
extern jmethodID g_flowinit_jm;

/* ProbeData */
extern jclass g_pdata_jc;
extern jmethodID g_pdatainit_jm;
extern jmethodID g_pdataadd_jm;
extern jmethodID g_pdataadd_rec_jm;
extern jmethodID g_pdataadd_trace_jm;
extern jmethodID g_pdataadd_stack_jm;
extern jmethodID g_pdataadd_symbol_jm;
extern jmethodID g_pdataadd_printf_jm;
extern jmethodID g_pdataadd_printa_jm;
extern jmethodID g_pdatainvalidate_printa_jm;
extern jmethodID g_pdataadd_aggrec_jm;
extern jmethodID g_pdataadd_printa_str_jm;
extern jmethodID g_pdataadd_exit_jm;
extern jmethodID g_pdataattach_jm;
extern jmethodID g_pdataset_formatted_jm;
extern jmethodID g_pdataclear_jm;

/* Drop */
extern jclass g_drop_jc;
extern jmethodID g_dropinit_jm;

/* Error */
extern jclass g_error_jc;
extern jmethodID g_errinit_jm;

/* ProcessState */
extern jclass g_process_jc;
extern jmethodID g_procinit_jm;
extern jmethodID g_procexit_jm;

/* Aggregate */
extern jclass g_agg_jc;
extern jmethodID g_agginit_jm;
extern jmethodID g_aggaddrec_jm;

/* AggregateSpec */
extern jclass g_aggspec_jc;
extern jmethodID g_aggspec_included_jm;
extern jmethodID g_aggspec_cleared_jm;

/* Tuple */
extern jclass g_tuple_jc;
extern jmethodID g_tupleinit_jm;
extern jmethodID g_tupleadd_jm;
extern jmethodID g_tuplesize_jm;
extern jfieldID g_tuple_EMPTY_jsf;

/* AggregationRecord */
extern jclass g_aggrec_jc;
extern jmethodID g_aggrecinit_jm;
extern jmethodID g_aggrecget_tuple_jm;

/* SumValue */
extern jclass g_aggsum_jc;
extern jmethodID g_aggsuminit_jm;

/* CountValue */
extern jclass g_aggcount_jc;
extern jmethodID g_aggcountinit_jm;

/* AvgValue */
extern jclass g_aggavg_jc;
extern jmethodID g_aggavginit_jm;

/* MinValue */
extern jclass g_aggmin_jc;
extern jmethodID g_aggmininit_jm;

/* MaxValue */
extern jclass g_aggmax_jc;
extern jmethodID g_aggmaxinit_jm;

/* StddevValue */
extern jclass g_aggstddev_jc;
extern jmethodID g_aggstddevinit_jm;

/* KernelStackRecord */
extern jclass g_stack_jc;
extern jmethodID g_parsestack_jsm;
extern jmethodID g_stackinit_jm;
extern jmethodID g_stackset_frames_jm;

/* UserStackRecord */
extern jclass g_ustack_jc;
extern jmethodID g_ustackinit_jm;
extern jmethodID g_ustackset_frames_jm;

/* Distribution */
extern jclass g_adist_jc;
extern jmethodID g_dist_normal_jm;

/* LogDistribution */
extern jclass g_dist_jc;
extern jmethodID g_distinit_jm;

/* LogLinearDistribution */
extern jclass g_lldist_jc;
extern jmethodID g_lldistinit_jm;

/* LinearDistribution */
extern jclass g_ldist_jc;
extern jmethodID g_ldistinit_jm;

/* KernelSymbolRecord */
extern jclass g_symbol_jc;
extern jmethodID g_symbolinit_jm;
extern jmethodID g_symbolset_name_jm;

/* UserSymbolRecord */
extern jclass g_usymbol_jc;
extern jmethodID g_usymbolinit_jm;
extern jmethodID g_usymbolset_name_jm;

/* ScalarRecord */
extern jclass g_scalar_jc;
extern jmethodID g_scalarinit_jm;

/*
 * Populates the java class references and associated method and field IDs
 * declared in this file (above).
 *
 * Throws NoClassDefFoundError, NoSuchMethodError, or NoSuchFieldError if any
 * dtj_table_entry_t in dtj_jnitab.c is incorrect.
 */
extern dtj_status_t dtj_load(JNIEnv *);

/*
 * Functions that create a structure return NULL if out of memory.  A Java
 * OutOfMemoryError is pending in that case.
 */
extern dtj_request_t *dtj_request_create(JNIEnv *, dtj_request_type_t, ...);
extern dtj_program_t *dtj_program_create(JNIEnv *, dtj_program_type_t,
    const char *);
extern dtj_aggval_t *dtj_aggval_create(JNIEnv *, jobject, const char *,
    int64_t);

/*
 * uu_list_t element destructors' signatures match uuwrap_value_destroy_f
 */
extern void dtj_request_destroy(void *, void *); /* expects NULL user arg */
extern void dtj_program_destroy(void *, void *); /* expects NULL user arg */
extern void dtj_aggval_destroy(void *, void *);	/* expects JNIEnv * user arg */

/* Allocates and frees per-consumer state kept in the global consumer table */
extern dtj_consumer_t *dtj_consumer_create(JNIEnv *);
extern void dtj_consumer_destroy(dtj_consumer_t *);

/* Sets callback handlers before calling dtrace_go() */
extern dtj_status_t dtj_set_callback_handlers(dtj_java_consumer_t *);

/*
 * Initializes Java Object references cached across multiple functions called
 * within the consumer loop.  Deletes the references after exiting the consumer
 * loop.  It is only necessary to initialize and finalize a dtj_java_consumer_t
 * if the native method call will enter the consumer loop.
 */
extern dtj_status_t dtj_java_consumer_init(JNIEnv *, dtj_java_consumer_t *);
extern void dtj_java_consumer_fini(JNIEnv *, dtj_java_consumer_t *);

/*
 * Throws a DTraceException with a message constructed from the given format
 * string and variable arg list.
 */
extern void dtj_throw_dtrace_exception(dtj_java_consumer_t *,
    const char *, ...);

/* Returns NULL if pending Java Exception or OutOfMemoryError */
extern jobject dtj_new_probedesc(dtj_java_consumer_t *,
    const dtrace_probedesc_t *);
extern jobject dtj_new_probeinfo(dtj_java_consumer_t *,
    const dtrace_probeinfo_t *);
extern jobject dtj_new_attribute(dtj_java_consumer_t *,
    const dtrace_attribute_t *);

/*
 * Returns NULL if the given fault is unrecognized, otherwise returns the name
 * of the fault, guaranteed not to change across multiple versions of this API
 * even if the integer value changes in libdtrace.
 */
extern const char *dtj_get_fault_name(int);

/* Gets the libdtrace error number and message */
extern dtj_status_t dtj_get_dtrace_error(dtj_java_consumer_t *, dtj_error_t *);

/* Stops the DTrace consumer */
extern void dtj_stop(dtj_java_consumer_t *);

/*
 * The Consumer getAggregate() method runs in the caller's current thread
 * separate from the consumer loop.
 */
extern jobject dtj_get_aggregate(dtj_java_consumer_t *);

/*
 * A blocking call that runs the consumer loop.  If this function returns an
 * error status, it is necessary to call stop() in order to dtrace_stop() the
 * consumer in libdtrace (it is safe to call stop() in either case).
 */
extern dtj_status_t dtj_consume(dtj_java_consumer_t *);

#ifdef	__cplusplus
}
#endif

#endif	/* _DTRACE_JNI_H */