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