2 * Copyright (C) 2016 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
3 * 2016 - EfficiOS Inc., Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
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.
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.
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
20 #include "org_lttng_ust_agent_context_LttngContextApi.h"
24 #include <lttng/ust-events.h>
25 #include <lttng/ringbuffer-config.h>
26 #include <lttng/ust-context-provider.h>
29 #include "lttng_ust_context.h"
31 enum lttng_ust_jni_type
{
43 struct lttng_ust_jni_ctx_entry
{
44 int32_t context_name_offset
;
45 char type
; /* enum lttng_ust_jni_type */
54 int32_t _string_offset
;
56 } __attribute__((packed
));
58 /* TLS passing context info from JNI to callbacks. */
59 __thread
struct lttng_ust_jni_tls lttng_ust_context_info_tls
;
61 static const char *get_ctx_string_at_offset(int32_t offset
)
63 signed char *ctx_strings_array
= lttng_ust_context_info_tls
.ctx_strings
;
65 if (offset
< 0 || offset
>= lttng_ust_context_info_tls
.ctx_strings_len
) {
68 return (const char *) (ctx_strings_array
+ offset
);
71 static struct lttng_ust_jni_ctx_entry
*lookup_ctx_by_name(const char *ctx_name
)
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
);
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
);
80 if (string
&& strcmp(string
, ctx_name
) == 0) {
81 return &ctx_entries_array
[i
];
87 static size_t get_size_cb(struct lttng_ctx_field
*field
, size_t offset
)
89 struct lttng_ust_jni_ctx_entry
*jctx
;
91 const char *ctx_name
= field
->event_field
.name
;
92 enum lttng_ust_jni_type jni_type
;
95 size
+= lib_ring_buffer_align(offset
, lttng_alignof(char));
96 size
+= sizeof(char); /* tag */
97 jctx
= lookup_ctx_by_name(ctx_name
);
99 jni_type
= JNI_TYPE_NULL
;
101 jni_type
= jctx
->type
;
106 case JNI_TYPE_INTEGER
:
107 size
+= lib_ring_buffer_align(offset
, lttng_alignof(int32_t));
108 size
+= sizeof(int32_t); /* variant */
111 size
+= lib_ring_buffer_align(offset
, lttng_alignof(int64_t));
112 size
+= sizeof(int64_t); /* variant */
114 case JNI_TYPE_DOUBLE
:
115 size
+= lib_ring_buffer_align(offset
, lttng_alignof(double));
116 size
+= sizeof(double); /* variant */
119 size
+= lib_ring_buffer_align(offset
, lttng_alignof(float));
120 size
+= sizeof(float); /* variant */
123 size
+= lib_ring_buffer_align(offset
, lttng_alignof(int16_t));
124 size
+= sizeof(int16_t); /* variant */
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 */
131 case JNI_TYPE_STRING
:
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
);
138 size
+= strlen(string
) + 1;
149 static void record_cb(struct lttng_ctx_field
*field
,
150 struct lttng_ust_lib_ring_buffer_ctx
*ctx
,
151 struct lttng_channel
*chan
)
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
;
158 jctx
= lookup_ctx_by_name(ctx_name
);
160 jni_type
= JNI_TYPE_NULL
;
162 jni_type
= jctx
->type
;
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
));
171 case JNI_TYPE_INTEGER
:
173 int32_t v
= jctx
->value
._integer
;
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
));
184 int64_t v
= jctx
->value
._long
;
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
));
193 case JNI_TYPE_DOUBLE
:
195 double v
= jctx
->value
._double
;
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
));
206 float v
= jctx
->value
._float
;
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
));
217 int16_t v
= jctx
->value
._short
;
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
));
228 char v
= jctx
->value
._byte
;
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
));
237 case JNI_TYPE_BOOLEAN
:
239 char v
= jctx
->value
._boolean
;
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
));
248 case JNI_TYPE_STRING
:
250 int32_t offset
= jctx
->value
._string_offset
;
251 const char *str
= get_ctx_string_at_offset(offset
);
254 sel_char
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
256 sel_char
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
258 lib_ring_buffer_align_ctx(ctx
, lttng_alignof(char));
259 chan
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
));
261 chan
->ops
->event_write(ctx
, str
, strlen(str
) + 1);
270 static void get_value_cb(struct lttng_ctx_field
*field
,
271 struct lttng_ctx_value
*value
)
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
;
277 jctx
= lookup_ctx_by_name(ctx_name
);
279 jni_type
= JNI_TYPE_NULL
;
281 jni_type
= jctx
->type
;
286 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
288 case JNI_TYPE_INTEGER
:
289 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
290 value
->u
.s64
= (int64_t) jctx
->value
._integer
;
293 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
294 value
->u
.s64
= jctx
->value
._long
;
296 case JNI_TYPE_DOUBLE
:
297 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
298 value
->u
.d
= jctx
->value
._double
;
301 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
302 value
->u
.d
= (double) jctx
->value
._float
;
305 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
306 value
->u
.s64
= (int64_t) jctx
->value
._short
;
309 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
310 value
->u
.s64
= (int64_t) jctx
->value
._byte
;
312 case JNI_TYPE_BOOLEAN
:
313 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
314 value
->u
.s64
= (int64_t) jctx
->value
._boolean
;
316 case JNI_TYPE_STRING
:
318 int32_t offset
= jctx
->value
._string_offset
;
319 const char *str
= get_ctx_string_at_offset(offset
);
322 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
325 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
335 * Register a context provider to UST.
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.
340 JNIEXPORT jlong JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv
*env
,
342 jstring provider_name
)
345 const char *provider_name_jstr
;
346 char *provider_name_cstr
;
347 struct lttng_ust_context_provider
*provider
;
349 * Note: a "jlong" is 8 bytes on all architectures, whereas a
354 provider_name_jstr
= (*env
)->GetStringUTFChars(env
, provider_name
, &iscopy
);
355 if (!provider_name_jstr
) {
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
) {
364 provider
= zmalloc(sizeof(*provider
));
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
;
373 if (lttng_ust_context_provider_register(provider
)) {
377 provider_ref
= (jlong
) (long) provider
;
380 /* Error handling. */
384 free(provider_name_cstr
);
391 * Unregister a previously-registered context provider.
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.
396 JNIEXPORT
void JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv
*env
,
400 struct lttng_ust_context_provider
*provider
=
401 (struct lttng_ust_context_provider
*) (unsigned long) provider_ref
;
407 lttng_ust_context_provider_unregister(provider
);
409 free(provider
->name
);