API refactoring: introduce probe context
[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, struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)),
83 size_t offset)
84 {
85 struct lttng_ust_jni_ctx_entry *jctx;
86 size_t size = 0;
87 struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv;
88 const char *ctx_name = jni_provider->name;
89 enum lttng_ust_jni_type jni_type;
90
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);
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:
103 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int32_t));
104 size += sizeof(int32_t); /* variant */
105 break;
106 case JNI_TYPE_LONG:
107 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int64_t));
108 size += sizeof(int64_t); /* variant */
109 break;
110 case JNI_TYPE_DOUBLE:
111 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(double));
112 size += sizeof(double); /* variant */
113 break;
114 case JNI_TYPE_FLOAT:
115 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(float));
116 size += sizeof(float); /* variant */
117 break;
118 case JNI_TYPE_SHORT:
119 size += lttng_ust_ring_buffer_align(offset, lttng_ust_rb_alignof(int16_t));
120 size += sizeof(int16_t); /* variant */
121 break;
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 */
126 break;
127 case JNI_TYPE_STRING:
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 }
136 break;
137 }
138 default:
139 abort();
140 }
141 return size;
142
143 }
144
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)
149 {
150 struct lttng_ust_jni_ctx_entry *jctx;
151 struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv;
152 const char *ctx_name = jni_provider->name;
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;
166 lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char));
167 break;
168 case JNI_TYPE_INTEGER:
169 {
170 int32_t v = jctx->value._integer;
171
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));
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;
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));
184 break;
185 }
186 case JNI_TYPE_DOUBLE:
187 {
188 double v = jctx->value._double;
189
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));
193 break;
194 }
195 case JNI_TYPE_FLOAT:
196 {
197 float v = jctx->value._float;
198
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));
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 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));
211 break;
212 }
213 case JNI_TYPE_BYTE:
214 {
215 char v = jctx->value._byte;
216
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));
220 break;
221 }
222 case JNI_TYPE_BOOLEAN:
223 {
224 char v = jctx->value._boolean;
225
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));
229 break;
230 }
231 case JNI_TYPE_STRING:
232 {
233 int32_t offset = jctx->value._string_offset;
234 const char *str = get_ctx_string_at_offset(offset);
235
236 if (str) {
237 sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING;
238 } else {
239 sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
240 }
241 lttng_chan_buf->ops->event_write(ctx, &sel_char, sizeof(sel_char), lttng_ust_rb_alignof(char));
242 if (str) {
243 lttng_chan_buf->ops->event_write(ctx, str, strlen(str) + 1, 1);
244 }
245 break;
246 }
247 default:
248 abort();
249 }
250 }
251
252 static void get_value_cb(void *priv, struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)),
253 struct lttng_ust_ctx_value *value)
254 {
255 struct lttng_ust_jni_provider *jni_provider = (struct lttng_ust_jni_provider *) priv;
256 struct lttng_ust_jni_ctx_entry *jctx;
257 const char *ctx_name = jni_provider->name;
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:
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 }
310 break;
311 }
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 */
323 JNIEXPORT jlong JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv *env,
324 jobject jobj __attribute__((unused)),
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;
331 struct lttng_ust_jni_provider *jni_provider;
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 }
348 jni_provider = zmalloc(sizeof(*jni_provider));
349 if (!jni_provider) {
350 goto error_provider;
351 }
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;
360
361 jni_provider->reg_provider = lttng_ust_context_provider_register(provider);
362 if (!jni_provider->reg_provider) {
363 goto error_register;
364 }
365
366 provider_ref = (jlong) (long) jni_provider;
367 return provider_ref;
368
369 /* Error handling. */
370 error_register:
371 free(jni_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 __attribute__((unused)),
386 jobject jobj __attribute__((unused)),
387 jlong provider_ref)
388 {
389 struct lttng_ust_jni_provider *jni_provider =
390 (struct lttng_ust_jni_provider *) (unsigned long) provider_ref;
391
392 if (!jni_provider) {
393 return;
394 }
395
396 lttng_ust_context_provider_unregister(jni_provider->reg_provider);
397
398 free(jni_provider->name);
399 free(jni_provider);
400 }
This page took 0.037293 seconds and 4 git commands to generate.