Move to kernel style SPDX license identifiers
[lttng-ust.git] / liblttng-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/ringbuffer-config.h>
15 #include <lttng/ust-context-provider.h>
16
17 #include "helper.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 /* TLS passing context info from JNI to callbacks. */
48 __thread struct lttng_ust_jni_tls lttng_ust_context_info_tls;
49
50 static const char *get_ctx_string_at_offset(int32_t offset)
51 {
52 signed char *ctx_strings_array = lttng_ust_context_info_tls.ctx_strings;
53
54 if (offset < 0 || offset >= lttng_ust_context_info_tls.ctx_strings_len) {
55 return NULL;
56 }
57 return (const char *) (ctx_strings_array + offset);
58 }
59
60 static struct lttng_ust_jni_ctx_entry *lookup_ctx_by_name(const char *ctx_name)
61 {
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);
64
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);
68
69 if (string && strcmp(string, ctx_name) == 0) {
70 return &ctx_entries_array[i];
71 }
72 }
73 return NULL;
74 }
75
76 static size_t get_size_cb(struct lttng_ctx_field *field, size_t offset)
77 {
78 struct lttng_ust_jni_ctx_entry *jctx;
79 size_t size = 0;
80 const char *ctx_name = field->event_field.name;
81 enum lttng_ust_jni_type jni_type;
82
83
84 size += lib_ring_buffer_align(offset, lttng_alignof(char));
85 size += sizeof(char); /* tag */
86 jctx = lookup_ctx_by_name(ctx_name);
87 if (!jctx) {
88 jni_type = JNI_TYPE_NULL;
89 } else {
90 jni_type = jctx->type;
91 }
92 switch (jni_type) {
93 case JNI_TYPE_NULL:
94 break;
95 case JNI_TYPE_INTEGER:
96 size += lib_ring_buffer_align(offset, lttng_alignof(int32_t));
97 size += sizeof(int32_t); /* variant */
98 break;
99 case JNI_TYPE_LONG:
100 size += lib_ring_buffer_align(offset, lttng_alignof(int64_t));
101 size += sizeof(int64_t); /* variant */
102 break;
103 case JNI_TYPE_DOUBLE:
104 size += lib_ring_buffer_align(offset, lttng_alignof(double));
105 size += sizeof(double); /* variant */
106 break;
107 case JNI_TYPE_FLOAT:
108 size += lib_ring_buffer_align(offset, lttng_alignof(float));
109 size += sizeof(float); /* variant */
110 break;
111 case JNI_TYPE_SHORT:
112 size += lib_ring_buffer_align(offset, lttng_alignof(int16_t));
113 size += sizeof(int16_t); /* variant */
114 break;
115 case JNI_TYPE_BYTE: /* Fall-through. */
116 case JNI_TYPE_BOOLEAN:
117 size += lib_ring_buffer_align(offset, lttng_alignof(char));
118 size += sizeof(char); /* variant */
119 break;
120 case JNI_TYPE_STRING:
121 {
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);
125
126 if (string) {
127 size += strlen(string) + 1;
128 }
129 break;
130 }
131 default:
132 abort();
133 }
134 return size;
135
136 }
137
138 static void record_cb(struct lttng_ctx_field *field,
139 struct lttng_ust_lib_ring_buffer_ctx *ctx,
140 struct lttng_channel *chan)
141 {
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;
145 char sel_char;
146
147 jctx = lookup_ctx_by_name(ctx_name);
148 if (!jctx) {
149 jni_type = JNI_TYPE_NULL;
150 } else {
151 jni_type = jctx->type;
152 }
153
154 switch (jni_type) {
155 case JNI_TYPE_NULL:
156 sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
157 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
158 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
159 break;
160 case JNI_TYPE_INTEGER:
161 {
162 int32_t v = jctx->value._integer;
163
164 sel_char = LTTNG_UST_DYNAMIC_TYPE_S32;
165 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
166 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
167 lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
168 chan->ops->event_write(ctx, &v, sizeof(v));
169 break;
170 }
171 case JNI_TYPE_LONG:
172 {
173 int64_t v = jctx->value._long;
174
175 sel_char = LTTNG_UST_DYNAMIC_TYPE_S64;
176 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
177 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
178 lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
179 chan->ops->event_write(ctx, &v, sizeof(v));
180 break;
181 }
182 case JNI_TYPE_DOUBLE:
183 {
184 double v = jctx->value._double;
185
186 sel_char = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
187 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
188 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
189 lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
190 chan->ops->event_write(ctx, &v, sizeof(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 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
199 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
200 lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
201 chan->ops->event_write(ctx, &v, sizeof(v));
202 break;
203 }
204 case JNI_TYPE_SHORT:
205 {
206 int16_t v = jctx->value._short;
207
208 sel_char = LTTNG_UST_DYNAMIC_TYPE_S16;
209 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
210 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
211 lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
212 chan->ops->event_write(ctx, &v, sizeof(v));
213 break;
214 }
215 case JNI_TYPE_BYTE:
216 {
217 char v = jctx->value._byte;
218
219 sel_char = LTTNG_UST_DYNAMIC_TYPE_S8;
220 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
221 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
222 lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
223 chan->ops->event_write(ctx, &v, sizeof(v));
224 break;
225 }
226 case JNI_TYPE_BOOLEAN:
227 {
228 char v = jctx->value._boolean;
229
230 sel_char = LTTNG_UST_DYNAMIC_TYPE_S8;
231 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
232 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
233 lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
234 chan->ops->event_write(ctx, &v, sizeof(v));
235 break;
236 }
237 case JNI_TYPE_STRING:
238 {
239 int32_t offset = jctx->value._string_offset;
240 const char *str = get_ctx_string_at_offset(offset);
241
242 if (str) {
243 sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING;
244 } else {
245 sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
246 }
247 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
248 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
249 if (str) {
250 chan->ops->event_write(ctx, str, strlen(str) + 1);
251 }
252 break;
253 }
254 default:
255 abort();
256 }
257 }
258
259 static void get_value_cb(struct lttng_ctx_field *field,
260 struct lttng_ctx_value *value)
261 {
262 struct lttng_ust_jni_ctx_entry *jctx;
263 const char *ctx_name = field->event_field.name;
264 enum lttng_ust_jni_type jni_type;
265
266 jctx = lookup_ctx_by_name(ctx_name);
267 if (!jctx) {
268 jni_type = JNI_TYPE_NULL;
269 } else {
270 jni_type = jctx->type;
271 }
272
273 switch (jni_type) {
274 case JNI_TYPE_NULL:
275 value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
276 break;
277 case JNI_TYPE_INTEGER:
278 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
279 value->u.s64 = (int64_t) jctx->value._integer;
280 break;
281 case JNI_TYPE_LONG:
282 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
283 value->u.s64 = jctx->value._long;
284 break;
285 case JNI_TYPE_DOUBLE:
286 value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
287 value->u.d = jctx->value._double;
288 break;
289 case JNI_TYPE_FLOAT:
290 value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
291 value->u.d = (double) jctx->value._float;
292 break;
293 case JNI_TYPE_SHORT:
294 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
295 value->u.s64 = (int64_t) jctx->value._short;
296 break;
297 case JNI_TYPE_BYTE:
298 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
299 value->u.s64 = (int64_t) jctx->value._byte;
300 break;
301 case JNI_TYPE_BOOLEAN:
302 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
303 value->u.s64 = (int64_t) jctx->value._boolean;
304 break;
305 case JNI_TYPE_STRING:
306 {
307 int32_t offset = jctx->value._string_offset;
308 const char *str = get_ctx_string_at_offset(offset);
309
310 if (str) {
311 value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING;
312 value->u.str = str;
313 } else {
314 value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
315 }
316 break;
317 }
318 default:
319 abort();
320 }
321 }
322
323 /*
324 * Register a context provider to UST.
325 *
326 * Called from the Java side when an application registers a context retriever,
327 * so we create and register a corresponding provider on the C side.
328 */
329 JNIEXPORT jlong JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv *env,
330 jobject jobj,
331 jstring provider_name)
332 {
333 jboolean iscopy;
334 const char *provider_name_jstr;
335 char *provider_name_cstr;
336 struct lttng_ust_context_provider *provider;
337 /*
338 * Note: a "jlong" is 8 bytes on all architectures, whereas a
339 * C "long" varies.
340 */
341 jlong provider_ref;
342
343 provider_name_jstr = (*env)->GetStringUTFChars(env, provider_name, &iscopy);
344 if (!provider_name_jstr) {
345 goto error_jstr;
346 }
347 /* Keep our own copy of the string so UST can use it. */
348 provider_name_cstr = strdup(provider_name_jstr);
349 (*env)->ReleaseStringUTFChars(env, provider_name, provider_name_jstr);
350 if (!provider_name_cstr) {
351 goto error_strdup;
352 }
353 provider = zmalloc(sizeof(*provider));
354 if (!provider) {
355 goto error_provider;
356 }
357 provider->name = provider_name_cstr;
358 provider->get_size = get_size_cb;
359 provider->record = record_cb;
360 provider->get_value = get_value_cb;
361
362 if (lttng_ust_context_provider_register(provider)) {
363 goto error_register;
364 }
365
366 provider_ref = (jlong) (long) provider;
367 return provider_ref;
368
369 /* Error handling. */
370 error_register:
371 free(provider);
372 error_provider:
373 free(provider_name_cstr);
374 error_strdup:
375 error_jstr:
376 return 0;
377 }
378
379 /*
380 * Unregister a previously-registered context provider.
381 *
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.
384 */
385 JNIEXPORT void JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv *env,
386 jobject jobj,
387 jlong provider_ref)
388 {
389 struct lttng_ust_context_provider *provider =
390 (struct lttng_ust_context_provider*) (unsigned long) provider_ref;
391
392 if (!provider) {
393 return;
394 }
395
396 lttng_ust_context_provider_unregister(provider);
397
398 free(provider->name);
399 free(provider);
400 }
This page took 0.037067 seconds and 4 git commands to generate.