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>
27 #include <urcu/tls-compat.h>
30 #include "lttng_ust_context.h"
32 enum lttng_ust_jni_type
{
44 struct lttng_ust_jni_ctx_entry
{
45 int32_t context_name_offset
;
46 char type
; /* enum lttng_ust_jni_type */
55 int32_t _string_offset
;
57 } __attribute__((packed
));
59 /* TLS passing context info from JNI to callbacks. */
60 DEFINE_URCU_TLS_IE(struct lttng_ust_jni_tls
, lttng_ust_context_info_tls
);
62 static const char *get_ctx_string_at_offset(int32_t offset
)
64 signed char *ctx_strings_array
= lttng_ust_context_info_tls
.ctx_strings
;
66 if (offset
< 0 || offset
>= lttng_ust_context_info_tls
.ctx_strings_len
) {
69 return (const char *) (ctx_strings_array
+ offset
);
72 static struct lttng_ust_jni_ctx_entry
*lookup_ctx_by_name(const char *ctx_name
)
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
);
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
);
81 if (string
&& strcmp(string
, ctx_name
) == 0) {
82 return &ctx_entries_array
[i
];
88 static size_t get_size_cb(struct lttng_ctx_field
*field
, size_t offset
)
90 struct lttng_ust_jni_ctx_entry
*jctx
;
92 const char *ctx_name
= field
->event_field
.name
;
93 enum lttng_ust_jni_type jni_type
;
96 size
+= lib_ring_buffer_align(offset
, lttng_alignof(char));
97 size
+= sizeof(char); /* tag */
98 jctx
= lookup_ctx_by_name(ctx_name
);
100 jni_type
= JNI_TYPE_NULL
;
102 jni_type
= jctx
->type
;
107 case JNI_TYPE_INTEGER
:
108 size
+= lib_ring_buffer_align(offset
, lttng_alignof(int32_t));
109 size
+= sizeof(int32_t); /* variant */
112 size
+= lib_ring_buffer_align(offset
, lttng_alignof(int64_t));
113 size
+= sizeof(int64_t); /* variant */
115 case JNI_TYPE_DOUBLE
:
116 size
+= lib_ring_buffer_align(offset
, lttng_alignof(double));
117 size
+= sizeof(double); /* variant */
120 size
+= lib_ring_buffer_align(offset
, lttng_alignof(float));
121 size
+= sizeof(float); /* variant */
124 size
+= lib_ring_buffer_align(offset
, lttng_alignof(int16_t));
125 size
+= sizeof(int16_t); /* variant */
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 */
132 case JNI_TYPE_STRING
:
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
);
139 size
+= strlen(string
) + 1;
150 static void record_cb(struct lttng_ctx_field
*field
,
151 struct lttng_ust_lib_ring_buffer_ctx
*ctx
,
152 struct lttng_channel
*chan
)
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
;
159 jctx
= lookup_ctx_by_name(ctx_name
);
161 jni_type
= JNI_TYPE_NULL
;
163 jni_type
= jctx
->type
;
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
));
172 case JNI_TYPE_INTEGER
:
174 int32_t v
= jctx
->value
._integer
;
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
));
185 int64_t v
= jctx
->value
._long
;
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
));
194 case JNI_TYPE_DOUBLE
:
196 double v
= jctx
->value
._double
;
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
));
207 float v
= jctx
->value
._float
;
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
));
218 int16_t v
= jctx
->value
._short
;
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
));
229 char v
= jctx
->value
._byte
;
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
));
238 case JNI_TYPE_BOOLEAN
:
240 char v
= jctx
->value
._boolean
;
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
));
249 case JNI_TYPE_STRING
:
251 int32_t offset
= jctx
->value
._string_offset
;
252 const char *str
= get_ctx_string_at_offset(offset
);
255 sel_char
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
257 sel_char
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
259 lib_ring_buffer_align_ctx(ctx
, lttng_alignof(char));
260 chan
->ops
->event_write(ctx
, &sel_char
, sizeof(sel_char
));
262 chan
->ops
->event_write(ctx
, str
, strlen(str
) + 1);
271 static void get_value_cb(struct lttng_ctx_field
*field
,
272 struct lttng_ctx_value
*value
)
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
;
278 jctx
= lookup_ctx_by_name(ctx_name
);
280 jni_type
= JNI_TYPE_NULL
;
282 jni_type
= jctx
->type
;
287 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
289 case JNI_TYPE_INTEGER
:
290 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
291 value
->u
.s64
= (int64_t) jctx
->value
._integer
;
294 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
295 value
->u
.s64
= jctx
->value
._long
;
297 case JNI_TYPE_DOUBLE
:
298 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
299 value
->u
.d
= jctx
->value
._double
;
302 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_DOUBLE
;
303 value
->u
.d
= (double) jctx
->value
._float
;
306 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
307 value
->u
.s64
= (int64_t) jctx
->value
._short
;
310 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
311 value
->u
.s64
= (int64_t) jctx
->value
._byte
;
313 case JNI_TYPE_BOOLEAN
:
314 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_S64
;
315 value
->u
.s64
= (int64_t) jctx
->value
._boolean
;
317 case JNI_TYPE_STRING
:
319 int32_t offset
= jctx
->value
._string_offset
;
320 const char *str
= get_ctx_string_at_offset(offset
);
323 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_STRING
;
326 value
->sel
= LTTNG_UST_DYNAMIC_TYPE_NONE
;
336 * Register a context provider to UST.
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.
341 JNIEXPORT jlong JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv
*env
,
343 jstring provider_name
)
346 const char *provider_name_jstr
;
347 char *provider_name_cstr
;
348 struct lttng_ust_context_provider
*provider
;
350 * Note: a "jlong" is 8 bytes on all architectures, whereas a
355 provider_name_jstr
= (*env
)->GetStringUTFChars(env
, provider_name
, &iscopy
);
356 if (!provider_name_jstr
) {
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
) {
365 provider
= zmalloc(sizeof(*provider
));
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
;
374 if (lttng_ust_context_provider_register(provider
)) {
378 provider_ref
= (jlong
) (long) provider
;
381 /* Error handling. */
385 free(provider_name_cstr
);
392 * Unregister a previously-registered context provider.
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.
397 JNIEXPORT
void JNICALL
Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv
*env
,
401 struct lttng_ust_context_provider
*provider
=
402 (struct lttng_ust_context_provider
*) (unsigned long) provider_ref
;
408 lttng_ust_context_provider_unregister(provider
);
410 free(provider
->name
);