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 struct lttng_ust_jni_provider
{
48 struct lttng_ust_registered_context_provider
*reg_provider
;
50 struct lttng_ust_context_provider provider
;
53 /* TLS passing context info from JNI to callbacks. */
54 __thread
struct lttng_ust_jni_tls lttng_ust_context_info_tls
;
56 static const char *get_ctx_string_at_offset(int32_t offset
)
58 signed char *ctx_strings_array
= lttng_ust_context_info_tls
.ctx_strings
;
60 if (offset
< 0 || offset
>= lttng_ust_context_info_tls
.ctx_strings_len
) {
63 return (const char *) (ctx_strings_array
+ offset
);
66 static struct lttng_ust_jni_ctx_entry
*lookup_ctx_by_name(const char *ctx_name
)
68 struct lttng_ust_jni_ctx_entry
*ctx_entries_array
= lttng_ust_context_info_tls
.ctx_entries
;
69 int i
, len
= lttng_ust_context_info_tls
.ctx_entries_len
/ sizeof(struct lttng_ust_jni_ctx_entry
);
71 for (i
= 0; i
< len
; i
++) {
72 int32_t offset
= ctx_entries_array
[i
].context_name_offset
;
73 const char *string
= get_ctx_string_at_offset(offset
);
75 if (string
&& strcmp(string
, ctx_name
) == 0) {
76 return &ctx_entries_array
[i
];
82 static size_t get_size_cb(void *priv
, size_t offset
)
84 struct lttng_ust_jni_ctx_entry
*jctx
;
86 struct lttng_ust_jni_provider
*jni_provider
= (struct lttng_ust_jni_provider
*) priv
;
87 const char *ctx_name
= jni_provider
->name
;
88 enum lttng_ust_jni_type jni_type
;
90 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(char));
91 size
+= sizeof(char); /* tag */
92 jctx
= lookup_ctx_by_name(ctx_name
);
94 jni_type
= JNI_TYPE_NULL
;
96 jni_type
= jctx
->type
;
101 case JNI_TYPE_INTEGER
:
102 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(int32_t));
103 size
+= sizeof(int32_t); /* variant */
106 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(int64_t));
107 size
+= sizeof(int64_t); /* variant */
109 case JNI_TYPE_DOUBLE
:
110 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(double));
111 size
+= sizeof(double); /* variant */
114 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(float));
115 size
+= sizeof(float); /* variant */
118 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(int16_t));
119 size
+= sizeof(int16_t); /* variant */
121 case JNI_TYPE_BYTE
: /* Fall-through. */
122 case JNI_TYPE_BOOLEAN
:
123 size
+= lttng_ust_lib_ring_buffer_align(offset
, lttng_ust_rb_alignof(char));
124 size
+= sizeof(char); /* variant */
126 case JNI_TYPE_STRING
:
128 /* The value is an offset, the string is in the "strings" array */
129 int32_t string_offset
= jctx
->value
._string_offset
;
130 const char *string
= get_ctx_string_at_offset(string_offset
);
133 size
+= strlen(string
) + 1;
144 static void record_cb(void *priv
,
145 struct lttng_ust_lib_ring_buffer_ctx
*ctx
,
146 struct lttng_ust_channel_buffer
*lttng_chan_buf
)
148 struct lttng_ust_jni_ctx_entry
*jctx
;
149 struct lttng_ust_jni_provider
*jni_provider
= (struct lttng_ust_jni_provider
*) priv
;
150 const char *ctx_name
= jni_provider
->name
;
151 enum lttng_ust_jni_type jni_type
;
154 jctx
= lookup_ctx_by_name(ctx_name
);
156 jni_type
= JNI_TYPE_NULL
;
158 jni_type
= jctx
->type
;
163 sel_char
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
164 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
166 case JNI_TYPE_INTEGER
:
168 int32_t v
= jctx
->value
._integer
;
170 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S32
;
171 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
172 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
177 int64_t v
= jctx
->value
._long
;
179 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S64
;
180 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
181 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
184 case JNI_TYPE_DOUBLE
:
186 double v
= jctx
->value
._double
;
188 sel_char
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
189 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
190 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
195 float v
= jctx
->value
._float
;
197 sel_char
= LTTNG_UST_DYNAMIC_TYPE_FLOAT
;
198 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
199 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
204 int16_t v
= jctx
->value
._short
;
206 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S16
;
207 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
208 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
213 char v
= jctx
->value
._byte
;
215 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S8
;
216 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
217 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
220 case JNI_TYPE_BOOLEAN
:
222 char v
= jctx
->value
._boolean
;
224 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S8
;
225 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
226 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
229 case JNI_TYPE_STRING
:
231 int32_t offset
= jctx
->value
._string_offset
;
232 const char *str
= get_ctx_string_at_offset(offset
);
235 sel_char
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
237 sel_char
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
239 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
241 lttng_chan_buf
->ops
->event_write(ctx
, str
, strlen(str
) + 1, 1);
250 static void get_value_cb(void *priv
, struct lttng_ust_ctx_value
*value
)
252 struct lttng_ust_jni_provider
*jni_provider
= (struct lttng_ust_jni_provider
*) priv
;
253 struct lttng_ust_jni_ctx_entry
*jctx
;
254 const char *ctx_name
= jni_provider
->name
;
255 enum lttng_ust_jni_type jni_type
;
257 jctx
= lookup_ctx_by_name(ctx_name
);
259 jni_type
= JNI_TYPE_NULL
;
261 jni_type
= jctx
->type
;
266 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
268 case JNI_TYPE_INTEGER
:
269 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
270 value
->u
.s64
= (int64_t) jctx
->value
._integer
;
273 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
274 value
->u
.s64
= jctx
->value
._long
;
276 case JNI_TYPE_DOUBLE
:
277 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
278 value
->u
.d
= jctx
->value
._double
;
281 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
282 value
->u
.d
= (double) jctx
->value
._float
;
285 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
286 value
->u
.s64
= (int64_t) jctx
->value
._short
;
289 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
290 value
->u
.s64
= (int64_t) jctx
->value
._byte
;
292 case JNI_TYPE_BOOLEAN
:
293 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
294 value
->u
.s64
= (int64_t) jctx
->value
._boolean
;
296 case JNI_TYPE_STRING
:
298 int32_t offset
= jctx
->value
._string_offset
;
299 const char *str
= get_ctx_string_at_offset(offset
);
302 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
305 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
315 * Register a context provider to UST.
317 * Called from the Java side when an application registers a context retriever,
318 * so we create and register a corresponding provider on the C side.
320 JNIEXPORT jlong JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv
*env
,
321 jobject jobj
__attribute__((unused
)),
322 jstring provider_name
)
325 const char *provider_name_jstr
;
326 char *provider_name_cstr
;
327 struct lttng_ust_context_provider
*provider
;
328 struct lttng_ust_jni_provider
*jni_provider
;
330 * Note: a "jlong" is 8 bytes on all architectures, whereas a
335 provider_name_jstr
= (*env
)->GetStringUTFChars(env
, provider_name
, &iscopy
);
336 if (!provider_name_jstr
) {
339 /* Keep our own copy of the string so UST can use it. */
340 provider_name_cstr
= strdup(provider_name_jstr
);
341 (*env
)->ReleaseStringUTFChars(env
, provider_name
, provider_name_jstr
);
342 if (!provider_name_cstr
) {
345 jni_provider
= zmalloc(sizeof(*jni_provider
));
349 provider
= &jni_provider
->provider
;
350 provider
->struct_size
= sizeof(*provider
);
351 jni_provider
->name
= provider_name_cstr
;
352 provider
->name
= jni_provider
->name
;
353 provider
->get_size
= get_size_cb
;
354 provider
->record
= record_cb
;
355 provider
->get_value
= get_value_cb
;
356 provider
->priv
= jni_provider
;
358 jni_provider
->reg_provider
= lttng_ust_context_provider_register(provider
);
359 if (!jni_provider
->reg_provider
) {
363 provider_ref
= (jlong
) (long) jni_provider
;
366 /* Error handling. */
370 free(provider_name_cstr
);
377 * Unregister a previously-registered context provider.
379 * Called from the Java side when an application unregisters a context retriever,
380 * so we unregister and delete the corresponding provider on the C side.
382 JNIEXPORT
void JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv
*env
__attribute__((unused
)),
383 jobject jobj
__attribute__((unused
)),
386 struct lttng_ust_jni_provider
*jni_provider
=
387 (struct lttng_ust_jni_provider
*) (unsigned long) provider_ref
;
393 lttng_ust_context_provider_unregister(jni_provider
->reg_provider
);
395 free(jni_provider
->name
);