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/ust-ringbuffer-context.h>
15 #include <common/ust-context-provider.h>
17 #include "common/macros.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
, struct lttng_ust_probe_ctx
*probe_ctx
__attribute__((unused
)),
85 const struct lttng_ust_app_context
*app_ctx
= (const struct lttng_ust_app_context
*) priv
;
86 const char *ctx_name
= app_ctx
->ctx_name
;
87 struct lttng_ust_jni_ctx_entry
*jctx
;
89 enum lttng_ust_jni_type jni_type
;
91 size
+= lttng_ust_ring_buffer_align(offset
, lttng_ust_rb_alignof(char));
92 size
+= sizeof(char); /* tag */
93 jctx
= lookup_ctx_by_name(ctx_name
);
95 jni_type
= JNI_TYPE_NULL
;
97 jni_type
= jctx
->type
;
102 case JNI_TYPE_INTEGER
:
103 size
+= lttng_ust_ring_buffer_align(offset
, lttng_ust_rb_alignof(int32_t));
104 size
+= sizeof(int32_t); /* variant */
107 size
+= lttng_ust_ring_buffer_align(offset
, lttng_ust_rb_alignof(int64_t));
108 size
+= sizeof(int64_t); /* variant */
110 case JNI_TYPE_DOUBLE
:
111 size
+= lttng_ust_ring_buffer_align(offset
, lttng_ust_rb_alignof(double));
112 size
+= sizeof(double); /* variant */
115 size
+= lttng_ust_ring_buffer_align(offset
, lttng_ust_rb_alignof(float));
116 size
+= sizeof(float); /* variant */
119 size
+= lttng_ust_ring_buffer_align(offset
, lttng_ust_rb_alignof(int16_t));
120 size
+= sizeof(int16_t); /* variant */
122 case JNI_TYPE_BYTE
: /* Fall-through. */
123 case JNI_TYPE_BOOLEAN
:
124 size
+= lttng_ust_ring_buffer_align(offset
, lttng_ust_rb_alignof(char));
125 size
+= sizeof(char); /* variant */
127 case JNI_TYPE_STRING
:
129 /* The value is an offset, the string is in the "strings" array */
130 int32_t string_offset
= jctx
->value
._string_offset
;
131 const char *string
= get_ctx_string_at_offset(string_offset
);
134 size
+= strlen(string
) + 1;
145 static void record_cb(void *priv
,
146 struct lttng_ust_probe_ctx
*probe_ctx
__attribute__((unused
)),
147 struct lttng_ust_ring_buffer_ctx
*ctx
,
148 struct lttng_ust_channel_buffer
*lttng_chan_buf
)
150 const struct lttng_ust_app_context
*app_ctx
= (const struct lttng_ust_app_context
*) priv
;
151 const char *ctx_name
= app_ctx
->ctx_name
;
152 struct lttng_ust_jni_ctx_entry
*jctx
;
153 enum lttng_ust_jni_type jni_type
;
156 jctx
= lookup_ctx_by_name(ctx_name
);
158 jni_type
= JNI_TYPE_NULL
;
160 jni_type
= jctx
->type
;
165 sel_char
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
166 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
168 case JNI_TYPE_INTEGER
:
170 int32_t v
= jctx
->value
._integer
;
172 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S32
;
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
));
179 int64_t v
= jctx
->value
._long
;
181 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S64
;
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
));
186 case JNI_TYPE_DOUBLE
:
188 double v
= jctx
->value
._double
;
190 sel_char
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
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 float v
= jctx
->value
._float
;
199 sel_char
= LTTNG_UST_DYNAMIC_TYPE_FLOAT
;
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 int16_t v
= jctx
->value
._short
;
208 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S16
;
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
));
215 char v
= jctx
->value
._byte
;
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_BOOLEAN
:
224 char v
= jctx
->value
._boolean
;
226 sel_char
= LTTNG_UST_DYNAMIC_TYPE_S8
;
227 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
228 lttng_chan_buf
->ops
->event_write(ctx
, &v
, sizeof(v
), lttng_ust_rb_alignof(v
));
231 case JNI_TYPE_STRING
:
233 int32_t offset
= jctx
->value
._string_offset
;
234 const char *str
= get_ctx_string_at_offset(offset
);
237 sel_char
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
239 sel_char
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
241 lttng_chan_buf
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
), lttng_ust_rb_alignof(char));
243 lttng_chan_buf
->ops
->event_write(ctx
, str
, strlen(str
) + 1, 1);
252 static void get_value_cb(void *priv
, struct lttng_ust_probe_ctx
*probe_ctx
__attribute__((unused
)),
253 struct lttng_ust_ctx_value
*value
)
255 const struct lttng_ust_app_context
*app_ctx
= (const struct lttng_ust_app_context
*) priv
;
256 const char *ctx_name
= app_ctx
->ctx_name
;
257 struct lttng_ust_jni_ctx_entry
*jctx
;
258 enum lttng_ust_jni_type jni_type
;
260 jctx
= lookup_ctx_by_name(ctx_name
);
262 jni_type
= JNI_TYPE_NULL
;
264 jni_type
= jctx
->type
;
269 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
271 case JNI_TYPE_INTEGER
:
272 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
273 value
->u
.s64
= (int64_t) jctx
->value
._integer
;
276 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
277 value
->u
.s64
= jctx
->value
._long
;
279 case JNI_TYPE_DOUBLE
:
280 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
281 value
->u
.d
= jctx
->value
._double
;
284 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
285 value
->u
.d
= (double) jctx
->value
._float
;
288 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
289 value
->u
.s64
= (int64_t) jctx
->value
._short
;
292 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
293 value
->u
.s64
= (int64_t) jctx
->value
._byte
;
295 case JNI_TYPE_BOOLEAN
:
296 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
297 value
->u
.s64
= (int64_t) jctx
->value
._boolean
;
299 case JNI_TYPE_STRING
:
301 int32_t offset
= jctx
->value
._string_offset
;
302 const char *str
= get_ctx_string_at_offset(offset
);
305 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
308 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
318 * Register a context provider to UST.
320 * Called from the Java side when an application registers a context retriever,
321 * so we create and register a corresponding provider on the C side.
323 JNIEXPORT jlong JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv
*env
,
324 jobject jobj
__attribute__((unused
)),
325 jstring provider_name
)
328 const char *provider_name_jstr
;
329 char *provider_name_cstr
;
330 struct lttng_ust_context_provider
*provider
;
331 struct lttng_ust_jni_provider
*jni_provider
;
333 * Note: a "jlong" is 8 bytes on all architectures, whereas a
338 provider_name_jstr
= (*env
)->GetStringUTFChars(env
, provider_name
, &iscopy
);
339 if (!provider_name_jstr
) {
342 /* Keep our own copy of the string so UST can use it. */
343 provider_name_cstr
= strdup(provider_name_jstr
);
344 (*env
)->ReleaseStringUTFChars(env
, provider_name
, provider_name_jstr
);
345 if (!provider_name_cstr
) {
348 jni_provider
= zmalloc(sizeof(*jni_provider
));
352 provider
= &jni_provider
->provider
;
353 provider
->struct_size
= sizeof(*provider
);
354 jni_provider
->name
= provider_name_cstr
;
355 provider
->name
= jni_provider
->name
;
356 provider
->get_size
= get_size_cb
;
357 provider
->record
= record_cb
;
358 provider
->get_value
= get_value_cb
;
359 provider
->priv
= jni_provider
;
361 jni_provider
->reg_provider
= lttng_ust_context_provider_register(provider
);
362 if (!jni_provider
->reg_provider
) {
366 provider_ref
= (jlong
) (long) jni_provider
;
369 /* Error handling. */
373 free(provider_name_cstr
);
380 * Unregister a previously-registered context provider.
382 * Called from the Java side when an application unregisters a context retriever,
383 * so we unregister and delete the corresponding provider on the C side.
385 JNIEXPORT
void JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv
*env
__attribute__((unused
)),
386 jobject jobj
__attribute__((unused
)),
389 struct lttng_ust_jni_provider
*jni_provider
=
390 (struct lttng_ust_jni_provider
*) (unsigned long) provider_ref
;
396 lttng_ust_context_provider_unregister(jni_provider
->reg_provider
);
398 free(jni_provider
->name
);