Add UST_DEBUG env. var. support
[lttng-ust.git] / libust / ltt-events.c
CommitLineData
8020ceb5
MD
1/*
2 * ltt-events.c
3 *
4 * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * Holds LTTng per-session event registry.
7 *
8 * Dual LGPL v2.1/GPL v2 license.
9 */
10
b5234c06
MD
11#define _GNU_SOURCE
12#include <stdio.h>
13#include <urcu/list.h>
14#include <pthread.h>
15#include <urcu-bp.h>
16#include <urcu/compiler.h>
17#include <urcu/uatomic.h>
18#include <uuid/uuid.h>
19#include <ust/tracepoint.h>
20#include <errno.h>
f4681817
MD
21#include <sys/shm.h>
22#include <sys/ipc.h>
23#include <ust/lttng-events.h>
b5234c06
MD
24#include "usterr_signal_safe.h"
25#include "ust/core.h"
8020ceb5 26#include "ltt-tracer.h"
b5234c06 27#include "ust/wait.h"
8d8a24c8 28#include "../libringbuffer/shm.h"
8020ceb5 29
b5234c06
MD
30static CDS_LIST_HEAD(sessions);
31static CDS_LIST_HEAD(ltt_transport_list);
8020ceb5 32static DEFINE_MUTEX(sessions_mutex);
8020ceb5
MD
33
34static void _ltt_event_destroy(struct ltt_event *event);
35static void _ltt_channel_destroy(struct ltt_channel *chan);
36static int _ltt_event_unregister(struct ltt_event *event);
37static
38int _ltt_event_metadata_statedump(struct ltt_session *session,
39 struct ltt_channel *chan,
40 struct ltt_event *event);
41static
42int _ltt_session_metadata_statedump(struct ltt_session *session);
43
8020ceb5
MD
44void synchronize_trace(void)
45{
8020ceb5 46 synchronize_rcu();
8020ceb5
MD
47}
48
49struct ltt_session *ltt_session_create(void)
50{
51 struct ltt_session *session;
52
b5234c06
MD
53 pthread_mutex_lock(&sessions_mutex);
54 session = zmalloc(sizeof(struct ltt_session));
8020ceb5
MD
55 if (!session)
56 return NULL;
b5234c06
MD
57 CDS_INIT_LIST_HEAD(&session->chan);
58 CDS_INIT_LIST_HEAD(&session->events);
59 uuid_generate(session->uuid);
60 cds_list_add(&session->list, &sessions);
61 pthread_mutex_unlock(&sessions_mutex);
8020ceb5
MD
62 return session;
63}
64
65void ltt_session_destroy(struct ltt_session *session)
66{
67 struct ltt_channel *chan, *tmpchan;
68 struct ltt_event *event, *tmpevent;
69 int ret;
70
b5234c06
MD
71 pthread_mutex_lock(&sessions_mutex);
72 CMM_ACCESS_ONCE(session->active) = 0;
73 cds_list_for_each_entry(event, &session->events, list) {
8020ceb5
MD
74 ret = _ltt_event_unregister(event);
75 WARN_ON(ret);
76 }
77 synchronize_trace(); /* Wait for in-flight events to complete */
b5234c06 78 cds_list_for_each_entry_safe(event, tmpevent, &session->events, list)
8020ceb5 79 _ltt_event_destroy(event);
b5234c06 80 cds_list_for_each_entry_safe(chan, tmpchan, &session->chan, list)
8020ceb5 81 _ltt_channel_destroy(chan);
b5234c06
MD
82 cds_list_del(&session->list);
83 pthread_mutex_unlock(&sessions_mutex);
84 free(session);
8020ceb5
MD
85}
86
976fe9ea 87int ltt_session_enable(struct ltt_session *session)
8020ceb5
MD
88{
89 int ret = 0;
90 struct ltt_channel *chan;
91
b5234c06 92 pthread_mutex_lock(&sessions_mutex);
8020ceb5
MD
93 if (session->active) {
94 ret = -EBUSY;
95 goto end;
96 }
97
98 /*
99 * Snapshot the number of events per channel to know the type of header
100 * we need to use.
101 */
b5234c06 102 cds_list_for_each_entry(chan, &session->chan, list) {
8020ceb5
MD
103 if (chan->header_type)
104 continue; /* don't change it if session stop/restart */
105 if (chan->free_event_id < 31)
106 chan->header_type = 1; /* compact */
107 else
108 chan->header_type = 2; /* large */
109 }
110
b5234c06
MD
111 CMM_ACCESS_ONCE(session->active) = 1;
112 CMM_ACCESS_ONCE(session->been_active) = 1;
8020ceb5 113 ret = _ltt_session_metadata_statedump(session);
4b4de73e 114 if (ret)
b5234c06 115 CMM_ACCESS_ONCE(session->active) = 0;
8020ceb5 116end:
b5234c06 117 pthread_mutex_unlock(&sessions_mutex);
8020ceb5
MD
118 return ret;
119}
120
976fe9ea 121int ltt_session_disable(struct ltt_session *session)
8020ceb5
MD
122{
123 int ret = 0;
124
b5234c06 125 pthread_mutex_lock(&sessions_mutex);
8020ceb5
MD
126 if (!session->active) {
127 ret = -EBUSY;
128 goto end;
129 }
b5234c06 130 CMM_ACCESS_ONCE(session->active) = 0;
8020ceb5 131end:
b5234c06 132 pthread_mutex_unlock(&sessions_mutex);
8020ceb5
MD
133 return ret;
134}
135
976fe9ea
MD
136int ltt_channel_enable(struct ltt_channel *channel)
137{
138 int old;
139
9beb36ba
MD
140 if (channel == channel->session->metadata)
141 return -EPERM;
b5234c06 142 old = uatomic_xchg(&channel->enabled, 1);
976fe9ea
MD
143 if (old)
144 return -EEXIST;
145 return 0;
146}
147
148int ltt_channel_disable(struct ltt_channel *channel)
149{
150 int old;
151
9beb36ba
MD
152 if (channel == channel->session->metadata)
153 return -EPERM;
b5234c06 154 old = uatomic_xchg(&channel->enabled, 0);
976fe9ea
MD
155 if (!old)
156 return -EEXIST;
157 return 0;
158}
159
160int ltt_event_enable(struct ltt_event *event)
161{
162 int old;
163
9beb36ba
MD
164 if (event->chan == event->chan->session->metadata)
165 return -EPERM;
b5234c06 166 old = uatomic_xchg(&event->enabled, 1);
976fe9ea
MD
167 if (old)
168 return -EEXIST;
169 return 0;
170}
171
172int ltt_event_disable(struct ltt_event *event)
173{
174 int old;
175
9beb36ba
MD
176 if (event->chan == event->chan->session->metadata)
177 return -EPERM;
b5234c06 178 old = uatomic_xchg(&event->enabled, 0);
976fe9ea
MD
179 if (!old)
180 return -EEXIST;
181 return 0;
182}
183
8020ceb5
MD
184static struct ltt_transport *ltt_transport_find(const char *name)
185{
186 struct ltt_transport *transport;
187
b5234c06 188 cds_list_for_each_entry(transport, &ltt_transport_list, node) {
8020ceb5
MD
189 if (!strcmp(transport->name, name))
190 return transport;
191 }
192 return NULL;
193}
194
195struct ltt_channel *ltt_channel_create(struct ltt_session *session,
196 const char *transport_name,
197 void *buf_addr,
198 size_t subbuf_size, size_t num_subbuf,
199 unsigned int switch_timer_interval,
f4681817 200 unsigned int read_timer_interval)
8020ceb5
MD
201{
202 struct ltt_channel *chan;
203 struct ltt_transport *transport;
204
b5234c06 205 pthread_mutex_lock(&sessions_mutex);
8020ceb5
MD
206 if (session->been_active)
207 goto active; /* Refuse to add channel to active session */
208 transport = ltt_transport_find(transport_name);
209 if (!transport) {
b5234c06 210 DBG("LTTng transport %s not found\n",
8020ceb5
MD
211 transport_name);
212 goto notransport;
213 }
b5234c06 214 chan = zmalloc(sizeof(struct ltt_channel));
8020ceb5
MD
215 if (!chan)
216 goto nomem;
217 chan->session = session;
218 chan->id = session->free_chan_id++;
219 /*
220 * Note: the channel creation op already writes into the packet
221 * headers. Therefore the "chan" information used as input
222 * should be already accessible.
223 */
8d8a24c8 224 chan->handle = transport->ops.channel_create("[lttng]", chan, buf_addr,
8020ceb5 225 subbuf_size, num_subbuf, switch_timer_interval,
8d8a24c8
MD
226 read_timer_interval);
227 chan->chan = shmp(chan->handle->header->chan);
8020ceb5
MD
228 if (!chan->chan)
229 goto create_error;
976fe9ea 230 chan->enabled = 1;
8020ceb5 231 chan->ops = &transport->ops;
b5234c06
MD
232 cds_list_add(&chan->list, &session->chan);
233 pthread_mutex_unlock(&sessions_mutex);
8020ceb5
MD
234 return chan;
235
236create_error:
b5234c06 237 free(chan);
8020ceb5
MD
238nomem:
239notransport:
240active:
b5234c06 241 pthread_mutex_unlock(&sessions_mutex);
8020ceb5
MD
242 return NULL;
243}
244
245/*
246 * Only used internally at session destruction.
247 */
248static
249void _ltt_channel_destroy(struct ltt_channel *chan)
250{
8d8a24c8 251 chan->ops->channel_destroy(chan->handle);
b5234c06 252 cds_list_del(&chan->list);
8020ceb5 253 lttng_destroy_context(chan->ctx);
b5234c06 254 free(chan);
8020ceb5
MD
255}
256
257/*
258 * Supports event creation while tracing session is active.
259 */
260struct ltt_event *ltt_event_create(struct ltt_channel *chan,
b5234c06 261 struct lttng_ust_event *event_param,
8020ceb5
MD
262 void *filter)
263{
264 struct ltt_event *event;
265 int ret;
266
b5234c06 267 pthread_mutex_lock(&sessions_mutex);
8020ceb5
MD
268 if (chan->free_event_id == -1UL)
269 goto full;
270 /*
271 * This is O(n^2) (for each event, the loop is called at event
272 * creation). Might require a hash if we have lots of events.
273 */
b5234c06 274 cds_list_for_each_entry(event, &chan->session->events, list)
8020ceb5
MD
275 if (!strcmp(event->desc->name, event_param->name))
276 goto exist;
b5234c06 277 event = zmalloc(sizeof(struct ltt_event));
8020ceb5
MD
278 if (!event)
279 goto cache_error;
280 event->chan = chan;
281 event->filter = filter;
282 event->id = chan->free_event_id++;
976fe9ea 283 event->enabled = 1;
8020ceb5
MD
284 event->instrumentation = event_param->instrumentation;
285 /* Populate ltt_event structure before tracepoint registration. */
b5234c06 286 cmm_smp_wmb();
8020ceb5 287 switch (event_param->instrumentation) {
b5234c06 288 case LTTNG_UST_TRACEPOINT:
8020ceb5
MD
289 event->desc = ltt_event_get(event_param->name);
290 if (!event->desc)
291 goto register_error;
b5234c06 292 ret = __tracepoint_probe_register(event_param->name,
8020ceb5
MD
293 event->desc->probe_callback,
294 event);
295 if (ret)
296 goto register_error;
297 break;
8020ceb5
MD
298 default:
299 WARN_ON_ONCE(1);
300 }
301 ret = _ltt_event_metadata_statedump(chan->session, chan, event);
302 if (ret)
303 goto statedump_error;
b5234c06
MD
304 cds_list_add(&event->list, &chan->session->events);
305 pthread_mutex_unlock(&sessions_mutex);
8020ceb5
MD
306 return event;
307
308statedump_error:
b5234c06 309 WARN_ON_ONCE(__tracepoint_probe_unregister(event_param->name,
8020ceb5
MD
310 event->desc->probe_callback,
311 event));
312 ltt_event_put(event->desc);
313register_error:
b5234c06 314 free(event);
8020ceb5
MD
315cache_error:
316exist:
317full:
b5234c06 318 pthread_mutex_unlock(&sessions_mutex);
8020ceb5
MD
319 return NULL;
320}
321
322/*
323 * Only used internally at session destruction.
324 */
325int _ltt_event_unregister(struct ltt_event *event)
326{
327 int ret = -EINVAL;
328
329 switch (event->instrumentation) {
b5234c06
MD
330 case LTTNG_UST_TRACEPOINT:
331 ret = __tracepoint_probe_unregister(event->desc->name,
8020ceb5
MD
332 event->desc->probe_callback,
333 event);
334 if (ret)
335 return ret;
336 break;
8020ceb5
MD
337 default:
338 WARN_ON_ONCE(1);
339 }
340 return ret;
341}
342
343/*
344 * Only used internally at session destruction.
345 */
346static
347void _ltt_event_destroy(struct ltt_event *event)
348{
349 switch (event->instrumentation) {
b5234c06 350 case LTTNG_UST_TRACEPOINT:
8020ceb5
MD
351 ltt_event_put(event->desc);
352 break;
8020ceb5
MD
353 default:
354 WARN_ON_ONCE(1);
355 }
b5234c06 356 cds_list_del(&event->list);
8020ceb5 357 lttng_destroy_context(event->ctx);
b5234c06 358 free(event);
8020ceb5
MD
359}
360
361/*
362 * We have exclusive access to our metadata buffer (protected by the
363 * sessions_mutex), so we can do racy operations such as looking for
364 * remaining space left in packet and write, since mutual exclusion
365 * protects us from concurrent writes.
366 */
367int lttng_metadata_printf(struct ltt_session *session,
368 const char *fmt, ...)
369{
370 struct lib_ring_buffer_ctx ctx;
371 struct ltt_channel *chan = session->metadata;
b5234c06 372 char *str = NULL;
8020ceb5
MD
373 int ret = 0, waitret;
374 size_t len, reserve_len, pos;
375 va_list ap;
376
b5234c06 377 WARN_ON_ONCE(!CMM_ACCESS_ONCE(session->active));
8020ceb5
MD
378
379 va_start(ap, fmt);
b5234c06 380 ret = vasprintf(&str, fmt, ap);
8020ceb5 381 va_end(ap);
b5234c06 382 if (ret < 0)
8020ceb5
MD
383 return -ENOMEM;
384
385 len = strlen(str);
386 pos = 0;
387
388 for (pos = 0; pos < len; pos += reserve_len) {
389 reserve_len = min_t(size_t,
390 chan->ops->packet_avail_size(chan->chan),
391 len - pos);
392 lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len,
393 sizeof(char), -1);
394 /*
395 * We don't care about metadata buffer's records lost
396 * count, because we always retry here. Report error if
397 * we need to bail out after timeout or being
398 * interrupted.
399 */
b5234c06 400 waitret = wait_cond_interruptible_timeout(
8020ceb5
MD
401 ({
402 ret = chan->ops->event_reserve(&ctx, 0);
403 ret != -ENOBUFS || !ret;
404 }),
b5234c06
MD
405 LTTNG_METADATA_TIMEOUT_MSEC);
406 if (!waitret || waitret == -EINTR || ret) {
407 DBG("LTTng: Failure to write metadata to buffers (%s)\n",
408 waitret == -EINTR ? "interrupted" :
8020ceb5 409 (ret == -ENOBUFS ? "timeout" : "I/O error"));
b5234c06 410 if (waitret == -EINTR)
8020ceb5
MD
411 ret = waitret;
412 goto end;
413 }
414 chan->ops->event_write(&ctx, &str[pos], reserve_len);
415 chan->ops->event_commit(&ctx);
416 }
417end:
b5234c06 418 free(str);
8020ceb5
MD
419 return ret;
420}
421
422static
423int _ltt_field_statedump(struct ltt_session *session,
424 const struct lttng_event_field *field)
425{
426 int ret = 0;
427
428 switch (field->type.atype) {
429 case atype_integer:
430 ret = lttng_metadata_printf(session,
431 " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s;\n",
432 field->type.u.basic.integer.size,
433 field->type.u.basic.integer.alignment,
434 field->type.u.basic.integer.signedness,
435 (field->type.u.basic.integer.encoding == lttng_encode_none)
436 ? "none"
437 : (field->type.u.basic.integer.encoding == lttng_encode_UTF8)
438 ? "UTF8"
439 : "ASCII",
440 field->type.u.basic.integer.base,
403c40b4
MD
441#ifdef __BIG_ENDIAN
442 field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
443#else
444 field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
445#endif
446 field->name);
447 break;
448 case atype_float:
449 ret = lttng_metadata_printf(session,
450 " floating_point { exp_dig = %u; mant_dig = %u; align = %u; } %s;\n",
451 field->type.u.basic._float.exp_dig,
452 field->type.u.basic._float.mant_dig,
453 field->type.u.basic._float.alignment,
454#ifdef __BIG_ENDIAN
8020ceb5
MD
455 field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
456#else
457 field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
458#endif
459 field->name);
460 break;
461 case atype_enum:
462 ret = lttng_metadata_printf(session,
463 " %s %s;\n",
464 field->type.u.basic.enumeration.name,
465 field->name);
466 break;
467 case atype_array:
468 {
469 const struct lttng_basic_type *elem_type;
470
471 elem_type = &field->type.u.array.elem_type;
472 ret = lttng_metadata_printf(session,
473 " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[%u];\n",
474 elem_type->u.basic.integer.size,
475 elem_type->u.basic.integer.alignment,
476 elem_type->u.basic.integer.signedness,
477 (elem_type->u.basic.integer.encoding == lttng_encode_none)
478 ? "none"
479 : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8)
480 ? "UTF8"
481 : "ASCII",
482 elem_type->u.basic.integer.base,
403c40b4 483#ifdef __BIG_ENDIAN
8020ceb5
MD
484 elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
485#else
486 elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
487#endif
488 field->name, field->type.u.array.length);
489 break;
490 }
491 case atype_sequence:
492 {
493 const struct lttng_basic_type *elem_type;
494 const struct lttng_basic_type *length_type;
495
496 elem_type = &field->type.u.sequence.elem_type;
497 length_type = &field->type.u.sequence.length_type;
498 ret = lttng_metadata_printf(session,
499 " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n",
500 length_type->u.basic.integer.size,
501 (unsigned int) length_type->u.basic.integer.alignment,
502 length_type->u.basic.integer.signedness,
503 (length_type->u.basic.integer.encoding == lttng_encode_none)
504 ? "none"
505 : ((length_type->u.basic.integer.encoding == lttng_encode_UTF8)
506 ? "UTF8"
507 : "ASCII"),
508 length_type->u.basic.integer.base,
403c40b4 509#ifdef __BIG_ENDIAN
8020ceb5
MD
510 length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
511#else
512 length_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
513#endif
514 field->name);
515 if (ret)
516 return ret;
517
518 ret = lttng_metadata_printf(session,
519 " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n",
520 elem_type->u.basic.integer.size,
521 (unsigned int) elem_type->u.basic.integer.alignment,
522 elem_type->u.basic.integer.signedness,
523 (elem_type->u.basic.integer.encoding == lttng_encode_none)
524 ? "none"
525 : ((elem_type->u.basic.integer.encoding == lttng_encode_UTF8)
526 ? "UTF8"
527 : "ASCII"),
528 elem_type->u.basic.integer.base,
403c40b4 529#ifdef __BIG_ENDIAN
8020ceb5
MD
530 elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
531#else
532 elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
533#endif
534 field->name,
535 field->name);
536 break;
537 }
538
539 case atype_string:
540 /* Default encoding is UTF8 */
541 ret = lttng_metadata_printf(session,
542 " string%s %s;\n",
543 field->type.u.basic.string.encoding == lttng_encode_ASCII ?
544 " { encoding = ASCII; }" : "",
545 field->name);
546 break;
547 default:
548 WARN_ON_ONCE(1);
549 return -EINVAL;
550 }
551 return ret;
552}
553
554static
555int _ltt_context_metadata_statedump(struct ltt_session *session,
556 struct lttng_ctx *ctx)
557{
558 int ret = 0;
559 int i;
560
561 if (!ctx)
562 return 0;
563 for (i = 0; i < ctx->nr_fields; i++) {
564 const struct lttng_ctx_field *field = &ctx->fields[i];
565
566 ret = _ltt_field_statedump(session, &field->event_field);
567 if (ret)
568 return ret;
569 }
570 return ret;
571}
572
573static
574int _ltt_fields_metadata_statedump(struct ltt_session *session,
575 struct ltt_event *event)
576{
577 const struct lttng_event_desc *desc = event->desc;
578 int ret = 0;
579 int i;
580
581 for (i = 0; i < desc->nr_fields; i++) {
582 const struct lttng_event_field *field = &desc->fields[i];
583
584 ret = _ltt_field_statedump(session, field);
585 if (ret)
586 return ret;
587 }
588 return ret;
589}
590
591static
592int _ltt_event_metadata_statedump(struct ltt_session *session,
593 struct ltt_channel *chan,
594 struct ltt_event *event)
595{
596 int ret = 0;
597
b5234c06 598 if (event->metadata_dumped || !CMM_ACCESS_ONCE(session->active))
8020ceb5
MD
599 return 0;
600 if (chan == session->metadata)
601 return 0;
602
603 ret = lttng_metadata_printf(session,
604 "event {\n"
605 " name = %s;\n"
606 " id = %u;\n"
607 " stream_id = %u;\n",
608 event->desc->name,
609 event->id,
610 event->chan->id);
611 if (ret)
612 goto end;
613
614 if (event->ctx) {
615 ret = lttng_metadata_printf(session,
616 " context := struct {\n");
617 if (ret)
618 goto end;
619 }
620 ret = _ltt_context_metadata_statedump(session, event->ctx);
621 if (ret)
622 goto end;
623 if (event->ctx) {
624 ret = lttng_metadata_printf(session,
625 " };\n");
626 if (ret)
627 goto end;
628 }
629
630 ret = lttng_metadata_printf(session,
631 " fields := struct {\n"
632 );
633 if (ret)
634 goto end;
635
636 ret = _ltt_fields_metadata_statedump(session, event);
637 if (ret)
638 goto end;
639
640 /*
641 * LTTng space reservation can only reserve multiples of the
642 * byte size.
643 */
644 ret = lttng_metadata_printf(session,
645 " };\n"
646 "};\n\n");
647 if (ret)
648 goto end;
649
650 event->metadata_dumped = 1;
651end:
652 return ret;
653
654}
655
656static
657int _ltt_channel_metadata_statedump(struct ltt_session *session,
658 struct ltt_channel *chan)
659{
660 int ret = 0;
661
b5234c06 662 if (chan->metadata_dumped || !CMM_ACCESS_ONCE(session->active))
8020ceb5
MD
663 return 0;
664 if (chan == session->metadata)
665 return 0;
666
667 WARN_ON_ONCE(!chan->header_type);
668 ret = lttng_metadata_printf(session,
669 "stream {\n"
670 " id = %u;\n"
671 " event.header := %s;\n"
672 " packet.context := struct packet_context;\n",
673 chan->id,
674 chan->header_type == 1 ? "struct event_header_compact" :
675 "struct event_header_large");
676 if (ret)
677 goto end;
678
679 if (chan->ctx) {
680 ret = lttng_metadata_printf(session,
681 " event.context := struct {\n");
682 if (ret)
683 goto end;
684 }
685 ret = _ltt_context_metadata_statedump(session, chan->ctx);
686 if (ret)
687 goto end;
688 if (chan->ctx) {
689 ret = lttng_metadata_printf(session,
690 " };\n");
691 if (ret)
692 goto end;
693 }
694
695 ret = lttng_metadata_printf(session,
696 "};\n\n");
697
698 chan->metadata_dumped = 1;
699end:
700 return ret;
701}
702
703static
704int _ltt_stream_packet_context_declare(struct ltt_session *session)
705{
706 return lttng_metadata_printf(session,
707 "struct packet_context {\n"
708 " uint64_t timestamp_begin;\n"
709 " uint64_t timestamp_end;\n"
710 " uint32_t events_discarded;\n"
711 " uint32_t content_size;\n"
712 " uint32_t packet_size;\n"
713 " uint32_t cpu_id;\n"
714 "};\n\n"
715 );
716}
717
718/*
719 * Compact header:
720 * id: range: 0 - 30.
721 * id 31 is reserved to indicate an extended header.
722 *
723 * Large header:
724 * id: range: 0 - 65534.
725 * id 65535 is reserved to indicate an extended header.
726 */
727static
728int _ltt_event_header_declare(struct ltt_session *session)
729{
730 return lttng_metadata_printf(session,
731 "struct event_header_compact {\n"
732 " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n"
733 " variant <id> {\n"
734 " struct {\n"
735 " uint27_t timestamp;\n"
736 " } compact;\n"
737 " struct {\n"
738 " uint32_t id;\n"
739 " uint64_t timestamp;\n"
740 " } extended;\n"
741 " } v;\n"
742 "} align(%u);\n"
743 "\n"
744 "struct event_header_large {\n"
745 " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n"
746 " variant <id> {\n"
747 " struct {\n"
748 " uint32_t timestamp;\n"
749 " } compact;\n"
750 " struct {\n"
751 " uint32_t id;\n"
752 " uint64_t timestamp;\n"
753 " } extended;\n"
754 " } v;\n"
755 "} align(%u);\n\n",
756 ltt_alignof(uint32_t) * CHAR_BIT,
757 ltt_alignof(uint16_t) * CHAR_BIT
758 );
759}
760
761/*
762 * Output metadata into this session's metadata buffers.
763 */
764static
765int _ltt_session_metadata_statedump(struct ltt_session *session)
766{
b5234c06
MD
767 unsigned char *uuid_c = session->uuid;
768 char uuid_s[37];
8020ceb5
MD
769 struct ltt_channel *chan;
770 struct ltt_event *event;
771 int ret = 0;
772
b5234c06 773 if (!CMM_ACCESS_ONCE(session->active))
8020ceb5
MD
774 return 0;
775 if (session->metadata_dumped)
776 goto skip_session;
777 if (!session->metadata) {
b5234c06 778 DBG("LTTng: attempt to start tracing, but metadata channel is not found. Operation abort.\n");
8020ceb5
MD
779 return -EPERM;
780 }
781
782 snprintf(uuid_s, sizeof(uuid_s),
783 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
784 uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3],
785 uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7],
786 uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11],
787 uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]);
788
789 ret = lttng_metadata_printf(session,
790 "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n"
791 "typealias integer { size = 16; align = %u; signed = false; } := uint16_t;\n"
792 "typealias integer { size = 32; align = %u; signed = false; } := uint32_t;\n"
793 "typealias integer { size = 64; align = %u; signed = false; } := uint64_t;\n"
794 "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
795 "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n"
796 "\n"
797 "trace {\n"
798 " major = %u;\n"
799 " minor = %u;\n"
800 " uuid = \"%s\";\n"
801 " byte_order = %s;\n"
802 " packet.header := struct {\n"
803 " uint32_t magic;\n"
804 " uint8_t uuid[16];\n"
805 " uint32_t stream_id;\n"
806 " };\n"
807 "};\n\n",
808 ltt_alignof(uint8_t) * CHAR_BIT,
809 ltt_alignof(uint16_t) * CHAR_BIT,
810 ltt_alignof(uint32_t) * CHAR_BIT,
811 ltt_alignof(uint64_t) * CHAR_BIT,
812 CTF_VERSION_MAJOR,
813 CTF_VERSION_MINOR,
814 uuid_s,
403c40b4 815#ifdef __BIG_ENDIAN
8020ceb5
MD
816 "be"
817#else
818 "le"
819#endif
820 );
821 if (ret)
822 goto end;
823
824 ret = _ltt_stream_packet_context_declare(session);
825 if (ret)
826 goto end;
827
828 ret = _ltt_event_header_declare(session);
829 if (ret)
830 goto end;
831
832skip_session:
b5234c06 833 cds_list_for_each_entry(chan, &session->chan, list) {
8020ceb5
MD
834 ret = _ltt_channel_metadata_statedump(session, chan);
835 if (ret)
836 goto end;
837 }
838
b5234c06 839 cds_list_for_each_entry(event, &session->events, list) {
8020ceb5
MD
840 ret = _ltt_event_metadata_statedump(session, event->chan, event);
841 if (ret)
842 goto end;
843 }
844 session->metadata_dumped = 1;
845end:
846 return ret;
847}
848
849/**
850 * ltt_transport_register - LTT transport registration
851 * @transport: transport structure
852 *
853 * Registers a transport which can be used as output to extract the data out of
b5234c06 854 * LTTng.
8020ceb5
MD
855 */
856void ltt_transport_register(struct ltt_transport *transport)
857{
b5234c06
MD
858 pthread_mutex_lock(&sessions_mutex);
859 cds_list_add_tail(&transport->node, &ltt_transport_list);
860 pthread_mutex_unlock(&sessions_mutex);
8020ceb5 861}
8020ceb5
MD
862
863/**
864 * ltt_transport_unregister - LTT transport unregistration
865 * @transport: transport structure
866 */
867void ltt_transport_unregister(struct ltt_transport *transport)
868{
b5234c06
MD
869 pthread_mutex_lock(&sessions_mutex);
870 cds_list_del(&transport->node);
871 pthread_mutex_unlock(&sessions_mutex);
8020ceb5
MD
872}
873
b5234c06
MD
874static
875void __attribute__((destructor)) ltt_events_exit(void)
8020ceb5
MD
876{
877 struct ltt_session *session, *tmpsession;
878
b5234c06 879 cds_list_for_each_entry_safe(session, tmpsession, &sessions, list)
8020ceb5 880 ltt_session_destroy(session);
8020ceb5 881}
This page took 0.0592 seconds and 4 git commands to generate.