API refactoring: introduce probe context
[lttng-ust.git] / src / lib / lttng-ust-java-agent / jni / common / lttng_ust_context.c
CommitLineData
8ab5c06b 1/*
c0c0989a 2 * SPDX-License-Identifier: LGPL-2.1-only
8ab5c06b 3 *
c0c0989a
MJ
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>
8ab5c06b
AM
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>
0b4b8811 14#include <lttng/ust-ringbuffer-context.h>
9d315d6d 15#include <common/ust-context-provider.h>
8ab5c06b 16
9d315d6d 17#include "common/macros.h"
8ab5c06b
AM
18#include "lttng_ust_context.h"
19
8ab5c06b
AM
20enum 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
b1ca4c5f
AM
32struct lttng_ust_jni_ctx_entry {
33 int32_t context_name_offset;
8ab5c06b
AM
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;
b1ca4c5f 43 int32_t _string_offset;
8ab5c06b
AM
44 } value;
45} __attribute__((packed));
46
4e48b5d2
MD
47struct 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
8ab5c06b 53/* TLS passing context info from JNI to callbacks. */
16adecf1 54__thread struct lttng_ust_jni_tls lttng_ust_context_info_tls;
8ab5c06b 55
b1ca4c5f
AM
56static 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
66static struct lttng_ust_jni_ctx_entry *lookup_ctx_by_name(const char *ctx_name)
8ab5c06b 67{
b1ca4c5f
AM
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);
8ab5c06b
AM
70
71 for (i = 0; i < len; i++) {
b1ca4c5f
AM
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 }
8ab5c06b
AM
78 }
79 return NULL;
8ab5c06b
AM
80}
81
b2e37d27
MD
82static size_t get_size_cb(void *priv, struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)),
83 size_t offset)
8ab5c06b 84{
b1ca4c5f 85 struct lttng_ust_jni_ctx_entry *jctx;
8ab5c06b 86 size_t size = 0;
4e48b5d2
MD
87 struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv;
88 const char *ctx_name = jni_provider->name;
8ab5c06b
AM
89 enum lttng_ust_jni_type jni_type;
90
b5457df5 91 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(char));
8ab5c06b
AM
92 size += sizeof(char); /* tag */
93 jctx = lookup_ctx_by_name(ctx_name);
94 if (!jctx) {
95 jni_type = JNI_TYPE_NULL;
96 } else {
97 jni_type = jctx->type;
98 }
99 switch (jni_type) {
100 case JNI_TYPE_NULL:
101 break;
102 case JNI_TYPE_INTEGER:
b5457df5 103 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int32_t));
8ab5c06b
AM
104 size += sizeof(int32_t); /* variant */
105 break;
106 case JNI_TYPE_LONG:
b5457df5 107 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int64_t));
8ab5c06b
AM
108 size += sizeof(int64_t); /* variant */
109 break;
110 case JNI_TYPE_DOUBLE:
b5457df5 111 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(double));
8ab5c06b
AM
112 size += sizeof(double); /* variant */
113 break;
114 case JNI_TYPE_FLOAT:
b5457df5 115 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(float));
8ab5c06b
AM
116 size += sizeof(float); /* variant */
117 break;
118 case JNI_TYPE_SHORT:
b5457df5 119 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int16_t));
8ab5c06b
AM
120 size += sizeof(int16_t); /* variant */
121 break;
122 case JNI_TYPE_BYTE: /* Fall-through. */
123 case JNI_TYPE_BOOLEAN:
b5457df5 124 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(char));
8ab5c06b
AM
125 size += sizeof(char); /* variant */
126 break;
127 case JNI_TYPE_STRING:
b1ca4c5f
AM
128 {
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);
132
133 if (string) {
134 size += strlen(string) + 1;
135 }
8ab5c06b 136 break;
b1ca4c5f 137 }
8ab5c06b
AM
138 default:
139 abort();
140 }
141 return size;
142
143}
144
4e48b5d2 145static void record_cb(void *priv,
b2e37d27 146 struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)),
b5457df5 147 struct lttng_ust_ring_buffer_ctx *ctx,
e016c06a 148 struct lttng_ust_channel_buffer *lttng_chan_buf)
8ab5c06b 149{
b1ca4c5f 150 struct lttng_ust_jni_ctx_entry *jctx;
4e48b5d2
MD
151 struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv;
152 const char *ctx_name = jni_provider->name;
8ab5c06b
AM
153 enum lttng_ust_jni_type jni_type;
154 char sel_char;
155
156 jctx = lookup_ctx_by_name(ctx_name);
157 if (!jctx) {
158 jni_type = JNI_TYPE_NULL;
159 } else {
160 jni_type = jctx->type;
161 }
162
163 switch (jni_type) {
164 case JNI_TYPE_NULL:
165 sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
8936b6c0 166 lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char));
8ab5c06b
AM
167 break;
168 case JNI_TYPE_INTEGER:
169 {
170 int32_t v = jctx->value._integer;
171
172 sel_char = LTTNG_UST_DYNAMIC_TYPE_S32;
8936b6c0
MD
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));
8ab5c06b
AM
175 break;
176 }
177 case JNI_TYPE_LONG:
178 {
179 int64_t v = jctx->value._long;
180
181 sel_char = LTTNG_UST_DYNAMIC_TYPE_S64;
8936b6c0
MD
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));
8ab5c06b
AM
184 break;
185 }
186 case JNI_TYPE_DOUBLE:
187 {
188 double v = jctx->value._double;
189
190 sel_char = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
8936b6c0
MD
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));
8ab5c06b
AM
193 break;
194 }
195 case JNI_TYPE_FLOAT:
196 {
197 float v = jctx->value._float;
198
199 sel_char = LTTNG_UST_DYNAMIC_TYPE_FLOAT;
8936b6c0
MD
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));
8ab5c06b
AM
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;
8936b6c0
MD
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));
8ab5c06b
AM
211 break;
212 }
213 case JNI_TYPE_BYTE:
214 {
215 char v = jctx->value._byte;
216
217 sel_char = LTTNG_UST_DYNAMIC_TYPE_S8;
8936b6c0
MD
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));
8ab5c06b
AM
220 break;
221 }
222 case JNI_TYPE_BOOLEAN:
223 {
224 char v = jctx->value._boolean;
225
226 sel_char = LTTNG_UST_DYNAMIC_TYPE_S8;
8936b6c0
MD
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));
8ab5c06b
AM
229 break;
230 }
231 case JNI_TYPE_STRING:
232 {
b1ca4c5f
AM
233 int32_t offset = jctx->value._string_offset;
234 const char *str = get_ctx_string_at_offset(offset);
8ab5c06b 235
b1ca4c5f
AM
236 if (str) {
237 sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING;
238 } else {
239 sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
240 }
8936b6c0 241 lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char));
b1ca4c5f 242 if (str) {
8936b6c0 243 lttng_chan_buf->ops->event_write(ctx, str, strlen(str) + 1, 1);
b1ca4c5f 244 }
8ab5c06b
AM
245 break;
246 }
247 default:
248 abort();
249 }
250}
251
b2e37d27
MD
252static void get_value_cb(void *priv, struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)),
253 struct lttng_ust_ctx_value *value)
8ab5c06b 254{
4e48b5d2 255 struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv;
b1ca4c5f 256 struct lttng_ust_jni_ctx_entry *jctx;
4e48b5d2 257 const char *ctx_name = jni_provider->name;
8ab5c06b
AM
258 enum lttng_ust_jni_type jni_type;
259
260 jctx = lookup_ctx_by_name(ctx_name);
261 if (!jctx) {
262 jni_type = JNI_TYPE_NULL;
263 } else {
264 jni_type = jctx->type;
265 }
266
267 switch (jni_type) {
268 case JNI_TYPE_NULL:
269 value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
270 break;
271 case JNI_TYPE_INTEGER:
272 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
273 value->u.s64 = (int64_t) jctx->value._integer;
274 break;
275 case JNI_TYPE_LONG:
276 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
277 value->u.s64 = jctx->value._long;
278 break;
279 case JNI_TYPE_DOUBLE:
280 value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
281 value->u.d = jctx->value._double;
282 break;
283 case JNI_TYPE_FLOAT:
284 value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
285 value->u.d = (double) jctx->value._float;
286 break;
287 case JNI_TYPE_SHORT:
288 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
289 value->u.s64 = (int64_t) jctx->value._short;
290 break;
291 case JNI_TYPE_BYTE:
292 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
293 value->u.s64 = (int64_t) jctx->value._byte;
294 break;
295 case JNI_TYPE_BOOLEAN:
296 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
297 value->u.s64 = (int64_t) jctx->value._boolean;
298 break;
299 case JNI_TYPE_STRING:
b1ca4c5f
AM
300 {
301 int32_t offset = jctx->value._string_offset;
302 const char *str = get_ctx_string_at_offset(offset);
303
304 if (str) {
305 value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING;
306 value->u.str = str;
307 } else {
308 value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
309 }
8ab5c06b 310 break;
b1ca4c5f 311 }
8ab5c06b
AM
312 default:
313 abort();
314 }
315}
316
317/*
318 * Register a context provider to UST.
319 *
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.
322 */
323JNIEXPORT jlong JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv *env,
2208d8b5 324 jobject jobj __attribute__((unused)),
8ab5c06b
AM
325 jstring provider_name)
326{
327 jboolean iscopy;
328 const char *provider_name_jstr;
329 char *provider_name_cstr;
330 struct lttng_ust_context_provider *provider;
4e48b5d2 331 struct lttng_ust_jni_provider *jni_provider;
8ab5c06b
AM
332 /*
333 * Note: a "jlong" is 8 bytes on all architectures, whereas a
334 * C "long" varies.
335 */
336 jlong provider_ref;
337
338 provider_name_jstr = (*env)->GetStringUTFChars(env, provider_name, &iscopy);
339 if (!provider_name_jstr) {
340 goto error_jstr;
341 }
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) {
346 goto error_strdup;
347 }
4e48b5d2
MD
348 jni_provider = zmalloc(sizeof(*jni_provider));
349 if (!jni_provider) {
8ab5c06b
AM
350 goto error_provider;
351 }
4e48b5d2 352 provider = &jni_provider->provider;
daacdbfc 353 provider->struct_size = sizeof(*provider);
4e48b5d2
MD
354 jni_provider->name = provider_name_cstr;
355 provider->name = jni_provider->name;
8ab5c06b
AM
356 provider->get_size = get_size_cb;
357 provider->record = record_cb;
358 provider->get_value = get_value_cb;
4e48b5d2 359 provider->priv = jni_provider;
8ab5c06b 360
4e48b5d2
MD
361 jni_provider->reg_provider = lttng_ust_context_provider_register(provider);
362 if (!jni_provider->reg_provider) {
8ab5c06b
AM
363 goto error_register;
364 }
365
4e48b5d2 366 provider_ref = (jlong) (long) jni_provider;
8ab5c06b
AM
367 return provider_ref;
368
369 /* Error handling. */
370error_register:
4e48b5d2 371 free(jni_provider);
8ab5c06b
AM
372error_provider:
373 free(provider_name_cstr);
374error_strdup:
375error_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 */
2208d8b5
MJ
385JNIEXPORT void JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv *env __attribute__((unused)),
386 jobject jobj __attribute__((unused)),
8ab5c06b
AM
387 jlong provider_ref)
388{
4e48b5d2
MD
389 struct lttng_ust_jni_provider *jni_provider =
390 (struct lttng_ust_jni_provider *) (unsigned long) provider_ref;
8ab5c06b 391
4e48b5d2 392 if (!jni_provider) {
8ab5c06b
AM
393 return;
394 }
395
4e48b5d2 396 lttng_ust_context_provider_unregister(jni_provider->reg_provider);
8ab5c06b 397
4e48b5d2
MD
398 free(jni_provider->name);
399 free(jni_provider);
8ab5c06b 400}
This page took 0.044526 seconds and 4 git commands to generate.