3bed11ec8ff435768259a460d9dffbfb0636efc0
[lttng-ust.git] / liblttng-ust-java-agent / jni / common / lttng_ust_context.c
1 /*
2 * Copyright (C) 2016 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
3 * 2016 - EfficiOS Inc., Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; only
8 * version 2.1 of the License.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "org_lttng_ust_agent_context_LttngContextApi.h"
21
22 #include <string.h>
23 #include <inttypes.h>
24 #include <lttng/ust-events.h>
25 #include <lttng/ringbuffer-config.h>
26 #include <lttng/ust-context-provider.h>
27
28 #include "helper.h"
29 #include "lttng_ust_context.h"
30
31 enum lttng_ust_jni_type {
32 JNI_TYPE_NULL = 0,
33 JNI_TYPE_INTEGER = 1,
34 JNI_TYPE_LONG = 2,
35 JNI_TYPE_DOUBLE = 3,
36 JNI_TYPE_FLOAT = 4,
37 JNI_TYPE_BYTE = 5,
38 JNI_TYPE_SHORT = 6,
39 JNI_TYPE_BOOLEAN = 7,
40 JNI_TYPE_STRING = 8,
41 };
42
43 struct lttng_ust_jni_ctx_entry {
44 int32_t context_name_offset;
45 char type; /* enum lttng_ust_jni_type */
46 union {
47 int32_t _integer;
48 int64_t _long;
49 double _double;
50 float _float;
51 signed char _byte;
52 int16_t _short;
53 signed char _boolean;
54 int32_t _string_offset;
55 } value;
56 } __attribute__((packed));
57
58 /* TLS passing context info from JNI to callbacks. */
59 __thread struct lttng_ust_jni_tls lttng_ust_context_info_tls;
60
61 static const char *get_ctx_string_at_offset(int32_t offset)
62 {
63 signed char *ctx_strings_array = lttng_ust_context_info_tls.ctx_strings;
64
65 if (offset < 0 || offset >= lttng_ust_context_info_tls.ctx_strings_len) {
66 return NULL;
67 }
68 return (const char *) (ctx_strings_array + offset);
69 }
70
71 static struct lttng_ust_jni_ctx_entry *lookup_ctx_by_name(const char *ctx_name)
72 {
73 struct lttng_ust_jni_ctx_entry *ctx_entries_array = lttng_ust_context_info_tls.ctx_entries;
74 int i, len = lttng_ust_context_info_tls.ctx_entries_len / sizeof(struct lttng_ust_jni_ctx_entry);
75
76 for (i = 0; i < len; i++) {
77 int32_t offset = ctx_entries_array[i].context_name_offset;
78 const char *string = get_ctx_string_at_offset(offset);
79
80 if (string && strcmp(string, ctx_name) == 0) {
81 return &ctx_entries_array[i];
82 }
83 }
84 return NULL;
85 }
86
87 static size_t get_size_cb(struct lttng_ctx_field *field, size_t offset)
88 {
89 struct lttng_ust_jni_ctx_entry *jctx;
90 size_t size = 0;
91 const char *ctx_name = field->event_field.name;
92 enum lttng_ust_jni_type jni_type;
93
94
95 size += lib_ring_buffer_align(offset, lttng_alignof(char));
96 size += sizeof(char); /* tag */
97 jctx = lookup_ctx_by_name(ctx_name);
98 if (!jctx) {
99 jni_type = JNI_TYPE_NULL;
100 } else {
101 jni_type = jctx->type;
102 }
103 switch (jni_type) {
104 case JNI_TYPE_NULL:
105 break;
106 case JNI_TYPE_INTEGER:
107 size += lib_ring_buffer_align(offset, lttng_alignof(int32_t));
108 size += sizeof(int32_t); /* variant */
109 break;
110 case JNI_TYPE_LONG:
111 size += lib_ring_buffer_align(offset, lttng_alignof(int64_t));
112 size += sizeof(int64_t); /* variant */
113 break;
114 case JNI_TYPE_DOUBLE:
115 size += lib_ring_buffer_align(offset, lttng_alignof(double));
116 size += sizeof(double); /* variant */
117 break;
118 case JNI_TYPE_FLOAT:
119 size += lib_ring_buffer_align(offset, lttng_alignof(float));
120 size += sizeof(float); /* variant */
121 break;
122 case JNI_TYPE_SHORT:
123 size += lib_ring_buffer_align(offset, lttng_alignof(int16_t));
124 size += sizeof(int16_t); /* variant */
125 break;
126 case JNI_TYPE_BYTE: /* Fall-through. */
127 case JNI_TYPE_BOOLEAN:
128 size += lib_ring_buffer_align(offset, lttng_alignof(char));
129 size += sizeof(char); /* variant */
130 break;
131 case JNI_TYPE_STRING:
132 {
133 /* The value is an offset, the string is in the "strings" array */
134 int32_t string_offset = jctx->value._string_offset;
135 const char *string = get_ctx_string_at_offset(string_offset);
136
137 if (string) {
138 size += strlen(string) + 1;
139 }
140 break;
141 }
142 default:
143 abort();
144 }
145 return size;
146
147 }
148
149 static void record_cb(struct lttng_ctx_field *field,
150 struct lttng_ust_lib_ring_buffer_ctx *ctx,
151 struct lttng_channel *chan)
152 {
153 struct lttng_ust_jni_ctx_entry *jctx;
154 const char *ctx_name = field->event_field.name;
155 enum lttng_ust_jni_type jni_type;
156 char sel_char;
157
158 jctx = lookup_ctx_by_name(ctx_name);
159 if (!jctx) {
160 jni_type = JNI_TYPE_NULL;
161 } else {
162 jni_type = jctx->type;
163 }
164
165 switch (jni_type) {
166 case JNI_TYPE_NULL:
167 sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
168 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
169 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
170 break;
171 case JNI_TYPE_INTEGER:
172 {
173 int32_t v = jctx->value._integer;
174
175 sel_char = LTTNG_UST_DYNAMIC_TYPE_S32;
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_LONG:
183 {
184 int64_t v = jctx->value._long;
185
186 sel_char = LTTNG_UST_DYNAMIC_TYPE_S64;
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_DOUBLE:
194 {
195 double v = jctx->value._double;
196
197 sel_char = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
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_FLOAT:
205 {
206 float v = jctx->value._float;
207
208 sel_char = LTTNG_UST_DYNAMIC_TYPE_FLOAT;
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_SHORT:
216 {
217 int16_t v = jctx->value._short;
218
219 sel_char = LTTNG_UST_DYNAMIC_TYPE_S16;
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_BYTE:
227 {
228 char v = jctx->value._byte;
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_BOOLEAN:
238 {
239 char v = jctx->value._boolean;
240
241 sel_char = LTTNG_UST_DYNAMIC_TYPE_S8;
242 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
243 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
244 lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
245 chan->ops->event_write(ctx, &v, sizeof(v));
246 break;
247 }
248 case JNI_TYPE_STRING:
249 {
250 int32_t offset = jctx->value._string_offset;
251 const char *str = get_ctx_string_at_offset(offset);
252
253 if (str) {
254 sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING;
255 } else {
256 sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
257 }
258 lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
259 chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
260 if (str) {
261 chan->ops->event_write(ctx, str, strlen(str) + 1);
262 }
263 break;
264 }
265 default:
266 abort();
267 }
268 }
269
270 static void get_value_cb(struct lttng_ctx_field *field,
271 struct lttng_ctx_value *value)
272 {
273 struct lttng_ust_jni_ctx_entry *jctx;
274 const char *ctx_name = field->event_field.name;
275 enum lttng_ust_jni_type jni_type;
276
277 jctx = lookup_ctx_by_name(ctx_name);
278 if (!jctx) {
279 jni_type = JNI_TYPE_NULL;
280 } else {
281 jni_type = jctx->type;
282 }
283
284 switch (jni_type) {
285 case JNI_TYPE_NULL:
286 value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
287 break;
288 case JNI_TYPE_INTEGER:
289 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
290 value->u.s64 = (int64_t) jctx->value._integer;
291 break;
292 case JNI_TYPE_LONG:
293 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
294 value->u.s64 = jctx->value._long;
295 break;
296 case JNI_TYPE_DOUBLE:
297 value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
298 value->u.d = jctx->value._double;
299 break;
300 case JNI_TYPE_FLOAT:
301 value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
302 value->u.d = (double) jctx->value._float;
303 break;
304 case JNI_TYPE_SHORT:
305 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
306 value->u.s64 = (int64_t) jctx->value._short;
307 break;
308 case JNI_TYPE_BYTE:
309 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
310 value->u.s64 = (int64_t) jctx->value._byte;
311 break;
312 case JNI_TYPE_BOOLEAN:
313 value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
314 value->u.s64 = (int64_t) jctx->value._boolean;
315 break;
316 case JNI_TYPE_STRING:
317 {
318 int32_t offset = jctx->value._string_offset;
319 const char *str = get_ctx_string_at_offset(offset);
320
321 if (str) {
322 value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING;
323 value->u.str = str;
324 } else {
325 value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
326 }
327 break;
328 }
329 default:
330 abort();
331 }
332 }
333
334 /*
335 * Register a context provider to UST.
336 *
337 * Called from the Java side when an application registers a context retriever,
338 * so we create and register a corresponding provider on the C side.
339 */
340 JNIEXPORT jlong JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv *env,
341 jobject jobj,
342 jstring provider_name)
343 {
344 jboolean iscopy;
345 const char *provider_name_jstr;
346 char *provider_name_cstr;
347 struct lttng_ust_context_provider *provider;
348 /*
349 * Note: a "jlong" is 8 bytes on all architectures, whereas a
350 * C "long" varies.
351 */
352 jlong provider_ref;
353
354 provider_name_jstr = (*env)->GetStringUTFChars(env, provider_name, &iscopy);
355 if (!provider_name_jstr) {
356 goto error_jstr;
357 }
358 /* Keep our own copy of the string so UST can use it. */
359 provider_name_cstr = strdup(provider_name_jstr);
360 (*env)->ReleaseStringUTFChars(env, provider_name, provider_name_jstr);
361 if (!provider_name_cstr) {
362 goto error_strdup;
363 }
364 provider = zmalloc(sizeof(*provider));
365 if (!provider) {
366 goto error_provider;
367 }
368 provider->name = provider_name_cstr;
369 provider->get_size = get_size_cb;
370 provider->record = record_cb;
371 provider->get_value = get_value_cb;
372
373 if (lttng_ust_context_provider_register(provider)) {
374 goto error_register;
375 }
376
377 provider_ref = (jlong) (long) provider;
378 return provider_ref;
379
380 /* Error handling. */
381 error_register:
382 free(provider);
383 error_provider:
384 free(provider_name_cstr);
385 error_strdup:
386 error_jstr:
387 return 0;
388 }
389
390 /*
391 * Unregister a previously-registered context provider.
392 *
393 * Called from the Java side when an application unregisters a context retriever,
394 * so we unregister and delete the corresponding provider on the C side.
395 */
396 JNIEXPORT void JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv *env,
397 jobject jobj,
398 jlong provider_ref)
399 {
400 struct lttng_ust_context_provider *provider =
401 (struct lttng_ust_context_provider*) (unsigned long) provider_ref;
402
403 if (!provider) {
404 return;
405 }
406
407 lttng_ust_context_provider_unregister(provider);
408
409 free(provider->name);
410 free(provider);
411 }
This page took 0.036941 seconds and 3 git commands to generate.