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