6f6d0e0696b354fcfe05a0154b5142ef329a3fec
[lttng-ust.git] / src / lib / lttng-ust-java-agent / jni / common / lttng_ust_context.c
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
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>
7 */
8
9 #include "org_lttng_ust_agent_context_LttngContextApi.h"
10
11 #include <string.h>
12 #include <inttypes.h>
13 #include <lttng/ust-events.h>
14 #include <lttng/ust-ringbuffer-context.h>
15 #include <common/ust-context-provider.h>
16
17 #include "common/macros.h"
18 #include "lttng_ust_context.h"
19
20 enum lttng_ust_jni_type {
21 JNI_TYPE_NULL = 0,
22 JNI_TYPE_INTEGER = 1,
23 JNI_TYPE_LONG = 2,
24 JNI_TYPE_DOUBLE = 3,
25 JNI_TYPE_FLOAT = 4,
26 JNI_TYPE_BYTE = 5,
27 JNI_TYPE_SHORT = 6,
28 JNI_TYPE_BOOLEAN = 7,
29 JNI_TYPE_STRING = 8,
30 };
31
32 struct lttng_ust_jni_ctx_entry {
33 int32_t context_name_offset;
34 char type; /* enum lttng_ust_jni_type */
35 union {
36 int32_t _integer;
37 int64_t _long;
38 double _double;
39 float _float;
40 signed char _byte;
41 int16_t _short;
42 signed char _boolean;
43 int32_t _string_offset;
44 } value;
45 } __attribute__((packed));
46
47 struct lttng_ust_jni_provider {
48 struct lttng_ust_registered_context_provider *reg_provider;
49 char *name;
50 struct lttng_ust_context_provider provider;
51 };
52
53 /* TLS passing context info from JNI to callbacks. */
54 __thread struct lttng_ust_jni_tls lttng_ust_context_info_tls;
55
56 static const char *get_ctx_string_at_offset(int32_t offset)
57 {
58 signed char *ctx_strings_array = lttng_ust_context_info_tls.ctx_strings;
59
60 if (offset < 0 || offset >= lttng_ust_context_info_tls.ctx_strings_len) {
61 return NULL;
62 }
63 return (const char *) (ctx_strings_array + offset);
64 }
65
66 static struct lttng_ust_jni_ctx_entry *lookup_ctx_by_name(const char *ctx_name)
67 {
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);
70
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);
74
75 if (string && strcmp(string, ctx_name) == 0) {
76 return &ctx_entries_array[i];
77 }
78 }
79 return NULL;
80 }
81
82 static size_t get_size_cb(void *priv, size_t offset)
83 {
84 struct lttng_ust_jni_ctx_entry *jctx;
85 size_t size = 0;
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;
89
90 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(char));
91 size += sizeof(char); /* tag */
92 jctx = lookup_ctx_by_name(ctx_name);
93 if (!jctx) {
94 jni_type = JNI_TYPE_NULL;
95 } else {
96 jni_type = jctx->type;
97 }
98 switch (jni_type) {
99 case JNI_TYPE_NULL:
100 break;
101 case JNI_TYPE_INTEGER:
102 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int32_t));
103 size += sizeof(int32_t); /* variant */
104 break;
105 case JNI_TYPE_LONG:
106 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int64_t));
107 size += sizeof(int64_t); /* variant */
108 break;
109 case JNI_TYPE_DOUBLE:
110 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(double));
111 size += sizeof(double); /* variant */
112 break;
113 case JNI_TYPE_FLOAT:
114 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(float));
115 size += sizeof(float); /* variant */
116 break;
117 case JNI_TYPE_SHORT:
118 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int16_t));
119 size += sizeof(int16_t); /* variant */
120 break;
121 case JNI_TYPE_BYTE: /* Fall-through. */
122 case JNI_TYPE_BOOLEAN:
123 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(char));
124 size += sizeof(char); /* variant */
125 break;
126 case JNI_TYPE_STRING:
127 {
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);
131
132 if (string) {
133 size += strlen(string) + 1;
134 }
135 break;
136 }
137 default:
138 abort();
139 }
140 return size;
141
142 }
143
144 static void record_cb(void *priv,
145 struct lttng_ust_ring_buffer_ctx *ctx,
146 struct lttng_ust_channel_buffer *lttng_chan_buf)
147 {
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;
152 char sel_char;
153
154 jctx = lookup_ctx_by_name(ctx_name);
155 if (!jctx) {
156 jni_type = JNI_TYPE_NULL;
157 } else {
158 jni_type = jctx->type;
159 }
160
161 switch (jni_type) {
162 case JNI_TYPE_NULL:
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));
165 break;
166 case JNI_TYPE_INTEGER:
167 {
168 int32_t v = jctx->value._integer;
169
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));
173 break;
174 }
175 case JNI_TYPE_LONG:
176 {
177 int64_t v = jctx->value._long;
178
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));
182 break;
183 }
184 case JNI_TYPE_DOUBLE:
185 {
186 double v = jctx->value._double;
187
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));
191 break;
192 }
193 case JNI_TYPE_FLOAT:
194 {
195 float v = jctx->value._float;
196
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));
200 break;
201 }
202 case JNI_TYPE_SHORT:
203 {
204 int16_t v = jctx->value._short;
205
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));
209 break;
210 }
211 case JNI_TYPE_BYTE:
212 {
213 char v = jctx->value._byte;
214
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));
218 break;
219 }
220 case JNI_TYPE_BOOLEAN:
221 {
222 char v = jctx->value._boolean;
223
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));
227 break;
228 }
229 case JNI_TYPE_STRING:
230 {
231 int32_t offset = jctx->value._string_offset;
232 const char *str = get_ctx_string_at_offset(offset);
233
234 if (str) {
235 sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING;
236 } else {
237 sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
238 }
239 lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char));
240 if (str) {
241 lttng_chan_buf->ops->event_write(ctx, str, strlen(str) + 1, 1);
242 }
243 break;
244 }
245 default:
246 abort();
247 }
248 }
249
250 static void get_value_cb(void *priv, struct lttng_ust_ctx_value *value)
251 {
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;
256
257 jctx = lookup_ctx_by_name(ctx_name);
258 if (!jctx) {
259 jni_type = JNI_TYPE_NULL;
260 } else {
261 jni_type = jctx->type;
262 }
263
264 switch (jni_type) {
265 case JNI_TYPE_NULL:
266 value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
267 break;
268 case JNI_TYPE_INTEGER:
269 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
270 value->u.s64 = (int64_t) jctx->value._integer;
271 break;
272 case JNI_TYPE_LONG:
273 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
274 value->u.s64 = jctx->value._long;
275 break;
276 case JNI_TYPE_DOUBLE:
277 value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
278 value->u.d = jctx->value._double;
279 break;
280 case JNI_TYPE_FLOAT:
281 value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
282 value->u.d = (double) jctx->value._float;
283 break;
284 case JNI_TYPE_SHORT:
285 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
286 value->u.s64 = (int64_t) jctx->value._short;
287 break;
288 case JNI_TYPE_BYTE:
289 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
290 value->u.s64 = (int64_t) jctx->value._byte;
291 break;
292 case JNI_TYPE_BOOLEAN:
293 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
294 value->u.s64 = (int64_t) jctx->value._boolean;
295 break;
296 case JNI_TYPE_STRING:
297 {
298 int32_t offset = jctx->value._string_offset;
299 const char *str = get_ctx_string_at_offset(offset);
300
301 if (str) {
302 value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING;
303 value->u.str = str;
304 } else {
305 value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
306 }
307 break;
308 }
309 default:
310 abort();
311 }
312 }
313
314 /*
315 * Register a context provider to UST.
316 *
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.
319 */
320 JNIEXPORT jlong JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv *env,
321 jobject jobj __attribute__((unused)),
322 jstring provider_name)
323 {
324 jboolean iscopy;
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;
329 /*
330 * Note: a "jlong" is 8 bytes on all architectures, whereas a
331 * C "long" varies.
332 */
333 jlong provider_ref;
334
335 provider_name_jstr = (*env)->GetStringUTFChars(env, provider_name, &iscopy);
336 if (!provider_name_jstr) {
337 goto error_jstr;
338 }
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) {
343 goto error_strdup;
344 }
345 jni_provider = zmalloc(sizeof(*jni_provider));
346 if (!jni_provider) {
347 goto error_provider;
348 }
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;
357
358 jni_provider->reg_provider = lttng_ust_context_provider_register(provider);
359 if (!jni_provider->reg_provider) {
360 goto error_register;
361 }
362
363 provider_ref = (jlong) (long) jni_provider;
364 return provider_ref;
365
366 /* Error handling. */
367 error_register:
368 free(jni_provider);
369 error_provider:
370 free(provider_name_cstr);
371 error_strdup:
372 error_jstr:
373 return 0;
374 }
375
376 /*
377 * Unregister a previously-registered context provider.
378 *
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.
381 */
382 JNIEXPORT void JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv *env __attribute__((unused)),
383 jobject jobj __attribute__((unused)),
384 jlong provider_ref)
385 {
386 struct lttng_ust_jni_provider *jni_provider =
387 (struct lttng_ust_jni_provider *) (unsigned long) provider_ref;
388
389 if (!jni_provider) {
390 return;
391 }
392
393 lttng_ust_context_provider_unregister(jni_provider->reg_provider);
394
395 free(jni_provider->name);
396 free(jni_provider);
397 }
This page took 0.036677 seconds and 3 git commands to generate.