2 * SPDX-License-Identifier: LGPL-2.1-only
4 * Copyright (C) 2016 EfficiOS Inc.
5 * Copyright (C) 2016 Alexandre Montplaisir <alexmonthy@efficios.com>
6 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 #include "org_lttng_ust_agent_context_LttngContextApi.h"
13 #include <lttng/ust-events.h>
14 #include <lttng/ringbuffer-context.h>
15 #include <ust-context-provider.h>
17 #include "ust-helper.h"
18 #include "lttng_ust_context.h"
20 enum lttng_ust_jni_type
{
32 struct lttng_ust_jni_ctx_entry
{
33 int32_t context_name_offset
;
34 char type
; /* enum lttng_ust_jni_type */
43 int32_t _string_offset
;
45 } __attribute__((packed
));
47 /* TLS passing context info from JNI to callbacks. */
48 __thread
struct lttng_ust_jni_tls lttng_ust_context_info_tls
;
50 static const char *get_ctx_string_at_offset(int32_t offset
)
52 signed char *ctx_strings_array
= lttng_ust_context_info_tls
.ctx_strings
;
54 if (offset
< 0 || offset
>= lttng_ust_context_info_tls
.ctx_strings_len
) {
57 return (const char *) (ctx_strings_array
+ offset
);
60 static struct lttng_ust_jni_ctx_entry
*lookup_ctx_by_name(const char *ctx_name
)
62 struct lttng_ust_jni_ctx_entry
*ctx_entries_array
= lttng_ust_context_info_tls
.ctx_entries
;
63 int i
, len
= lttng_ust_context_info_tls
.ctx_entries_len
/ sizeof(struct lttng_ust_jni_ctx_entry
);
65 for (i
= 0; i
< len
; i
++) {
66 int32_t offset
= ctx_entries_array
[i
].context_name_offset
;
67 const char *string
= get_ctx_string_at_offset(offset
);
69 if (string
&& strcmp(string
, ctx_name
) == 0) {
70 return &ctx_entries_array
[i
];
76 static size_t get_size_cb(struct lttng_ust_ctx_field
*field
, size_t offset
)
78 struct lttng_ust_jni_ctx_entry
*jctx
;
80 const char *ctx_name
= field
->event_field
->name
;
81 enum lttng_ust_jni_type jni_type
;
84 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(char));
85 size
+= sizeof(char); /* tag */
86 jctx
= lookup_ctx_by_name(ctx_name
);
88 jni_type
= JNI_TYPE_NULL
;
90 jni_type
= jctx
->type
;
95 case JNI_TYPE_INTEGER
:
96 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(int32_t));
97 size
+= sizeof(int32_t); /* variant */
100 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(int64_t));
101 size
+= sizeof(int64_t); /* variant */
103 case JNI_TYPE_DOUBLE
:
104 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(double));
105 size
+= sizeof(double); /* variant */
108 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(float));
109 size
+= sizeof(float); /* variant */
112 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(int16_t));
113 size
+= sizeof(int16_t); /* variant */
115 case JNI_TYPE_BYTE
: /* Fall-through. */
116 case JNI_TYPE_BOOLEAN
:
117 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(char));
118 size
+= sizeof(char); /* variant */
120 case JNI_TYPE_STRING
:
122 /* The value is an offset, the string is in the "strings" array */
123 int32_t string_offset
= jctx
->value
._string_offset
;
124 const char *string
= get_ctx_string_at_offset(string_offset
);
127 size
+= strlen(string
) + 1;
138 static void record_cb(struct lttng_ust_ctx_field
*field
,
139 struct lttng_ust_lib_ring_buffer_ctx
*ctx
,
140 struct lttng_ust_channel_buffer
*lttng_chan_buf
)
142 struct lttng_ust_jni_ctx_entry
*jctx
;
143 const char *ctx_name
= field
->event_field
->name
;
144 enum lttng_ust_jni_type jni_type
;
147 jctx
= lookup_ctx_by_name(ctx_name
);
149 jni_type
= JNI_TYPE_NULL
;
151 jni_type
= jctx
->type
;
156 sel_char
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
157 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
159 case JNI_TYPE_INTEGER
:
161 int32_t v
= jctx
->value
._integer
;
163 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S32
;
164 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
165 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
170 int64_t v
= jctx
->value
._long
;
172 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S64
;
173 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
174 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
177 case JNI_TYPE_DOUBLE
:
179 double v
= jctx
->value
._double
;
181 sel_char
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
182 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
183 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
188 float v
= jctx
->value
._float
;
190 sel_char
= LTTNG_UST_DYNAMIC_TYPE_FLOAT
;
191 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
192 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
197 int16_t v
= jctx
->value
._short
;
199 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S16
;
200 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
201 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
206 char v
= jctx
->value
._byte
;
208 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S8
;
209 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
210 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
213 case JNI_TYPE_BOOLEAN
:
215 char v
= jctx
->value
._boolean
;
217 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S8
;
218 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
219 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
222 case JNI_TYPE_STRING
:
224 int32_t offset
= jctx
->value
._string_offset
;
225 const char *str
= get_ctx_string_at_offset(offset
);
228 sel_char
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
230 sel_char
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
232 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
234 lttng_chan_buf
->ops
->event_write(ctx
, str
, strlen(str
) + 1, 1);
243 static void get_value_cb(struct lttng_ust_ctx_field
*field
,
244 struct lttng_ust_ctx_value
*value
)
246 struct lttng_ust_jni_ctx_entry
*jctx
;
247 const char *ctx_name
= field
->event_field
->name
;
248 enum lttng_ust_jni_type jni_type
;
250 jctx
= lookup_ctx_by_name(ctx_name
);
252 jni_type
= JNI_TYPE_NULL
;
254 jni_type
= jctx
->type
;
259 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
261 case JNI_TYPE_INTEGER
:
262 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
263 value
->u
.s64
= (int64_t) jctx
->value
._integer
;
266 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
267 value
->u
.s64
= jctx
->value
._long
;
269 case JNI_TYPE_DOUBLE
:
270 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
271 value
->u
.d
= jctx
->value
._double
;
274 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
275 value
->u
.d
= (double) jctx
->value
._float
;
278 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
279 value
->u
.s64
= (int64_t) jctx
->value
._short
;
282 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
283 value
->u
.s64
= (int64_t) jctx
->value
._byte
;
285 case JNI_TYPE_BOOLEAN
:
286 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
287 value
->u
.s64
= (int64_t) jctx
->value
._boolean
;
289 case JNI_TYPE_STRING
:
291 int32_t offset
= jctx
->value
._string_offset
;
292 const char *str
= get_ctx_string_at_offset(offset
);
295 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
298 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
308 * Register a context provider to UST.
310 * Called from the Java side when an application registers a context retriever,
311 * so we create and register a corresponding provider on the C side.
313 JNIEXPORT jlong JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv
*env
,
315 jstring provider_name
)
318 const char *provider_name_jstr
;
319 char *provider_name_cstr
;
320 struct lttng_ust_context_provider
*provider
;
322 * Note: a "jlong" is 8 bytes on all architectures, whereas a
327 provider_name_jstr
= (*env
)->GetStringUTFChars(env
, provider_name
, &iscopy
);
328 if (!provider_name_jstr
) {
331 /* Keep our own copy of the string so UST can use it. */
332 provider_name_cstr
= strdup(provider_name_jstr
);
333 (*env
)->ReleaseStringUTFChars(env
, provider_name
, provider_name_jstr
);
334 if (!provider_name_cstr
) {
337 provider
= zmalloc(sizeof(*provider
));
341 provider
->struct_size
= sizeof(*provider
);
342 provider
->name
= provider_name_cstr
;
343 provider
->get_size
= get_size_cb
;
344 provider
->record
= record_cb
;
345 provider
->get_value
= get_value_cb
;
347 if (lttng_ust_context_provider_register(provider
)) {
351 provider_ref
= (jlong
) (long) provider
;
354 /* Error handling. */
358 free(provider_name_cstr
);
365 * Unregister a previously-registered context provider.
367 * Called from the Java side when an application unregisters a context retriever,
368 * so we unregister and delete the corresponding provider on the C side.
370 JNIEXPORT
void JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv
*env
,
374 struct lttng_ust_context_provider
*provider
=
375 (struct lttng_ust_context_provider
*) (unsigned long) provider_ref
;
381 lttng_ust_context_provider_unregister(provider
);
383 free(provider
->name
);