Prefix all field names with underscores
[lttng-ust.git] / libust / lttng-ust-abi.c
CommitLineData
f4681817
MD
1/*
2 * lttng-ust-abi.c
3 *
4 * Copyright 2010-2011 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * LTTng UST ABI
7 *
8 * Mimic system calls for:
9 * - session creation, returns an object descriptor or failure.
10 * - channel creation, returns an object descriptor or failure.
11 * - Operates on a session object descriptor
12 * - Takes all channel options as parameters.
13 * - stream get, returns an object descriptor or failure.
14 * - Operates on a channel object descriptor.
15 * - stream notifier get, returns an object descriptor or failure.
16 * - Operates on a channel object descriptor.
17 * - event creation, returns an object descriptor or failure.
18 * - Operates on a channel object descriptor
19 * - Takes an event name as parameter
20 * - Takes an instrumentation source as parameter
21 * - e.g. tracepoints, dynamic_probes...
22 * - Takes instrumentation source specific arguments.
23 *
24 * Dual LGPL v2.1/GPL v2 license.
25 */
26
27#include <ust/lttng-ust-abi.h>
28#include <urcu/compiler.h>
29#include <urcu/list.h>
30#include <ust/lttng-events.h>
1dbfff0c 31#include <ust/usterr-signal-safe.h>
f4681817
MD
32#include "ust/core.h"
33#include "ltt-tracer.h"
34
35/*
36 * Object descriptor table. Should be protected from concurrent access
37 * by the caller.
38 */
39
f4681817
MD
40struct obj {
41 union {
42 struct {
43 void *private_data;
44 const struct objd_ops *ops;
45 int f_count;
46 } s;
47 int freelist_next; /* offset freelist. end is -1. */
48 } u;
49};
50
51struct objd_table {
52 struct obj *array;
53 unsigned int len, allocated_len;
54 int freelist_head; /* offset freelist head. end is -1 */
55};
56
57static struct objd_table objd_table = {
58 .freelist_head = -1,
59};
60
61static
62int objd_alloc(void *private_data, const struct objd_ops *ops)
63{
64 struct obj *obj;
65
66 if (objd_table.freelist_head != -1) {
67 obj = &objd_table.array[objd_table.freelist_head];
68 objd_table.freelist_head = obj->u.freelist_next;
69 goto end;
70 }
71
72 if (objd_table.len >= objd_table.allocated_len) {
73 unsigned int new_allocated_len, old_allocated_len;
74 struct obj *new_table, *old_table;
75
76 old_allocated_len = objd_table.allocated_len;
77 old_table = objd_table.array;
78 if (!old_allocated_len)
79 new_allocated_len = 1;
80 else
81 new_allocated_len = old_allocated_len << 1;
82 new_table = zmalloc(sizeof(struct obj) * new_allocated_len);
83 if (!new_table)
84 return -ENOMEM;
85 memcpy(new_table, old_table,
86 sizeof(struct obj) * old_allocated_len);
87 free(old_table);
88 objd_table.array = new_table;
89 objd_table.allocated_len = new_allocated_len;
90 }
91 obj = &objd_table.array[objd_table.len];
92 objd_table.len++;
93end:
94 obj->u.s.private_data = private_data;
95 obj->u.s.ops = ops;
a4be8962
MD
96 obj->u.s.f_count = 2; /* count == 1 : object is allocated */
97 /* count == 2 : allocated + hold ref */
f4681817
MD
98 return obj - objd_table.array;
99}
100
101static
102struct obj *_objd_get(int id)
103{
104 if (id >= objd_table.len)
105 return NULL;
a4be8962
MD
106 if (!objd_table.array[id].u.s.f_count)
107 return NULL;
f4681817
MD
108 return &objd_table.array[id];
109}
110
111static
112void *objd_private(int id)
113{
114 struct obj *obj = _objd_get(id);
115 assert(obj);
116 return obj->u.s.private_data;
117}
118
119static
120void objd_set_private(int id, void *private_data)
121{
122 struct obj *obj = _objd_get(id);
123 assert(obj);
124 obj->u.s.private_data = private_data;
125}
126
f4681817
MD
127const struct objd_ops *objd_ops(int id)
128{
129 struct obj *obj = _objd_get(id);
46050b1a 130
a4be8962
MD
131 if (!obj)
132 return NULL;
f4681817
MD
133 return obj->u.s.ops;
134}
135
136static
137void objd_free(int id)
138{
139 struct obj *obj = _objd_get(id);
140
141 assert(obj);
142 obj->u.freelist_next = objd_table.freelist_head;
143 objd_table.freelist_head = obj - objd_table.array;
a4be8962
MD
144 assert(obj->u.s.f_count == 1);
145 obj->u.s.f_count = 0; /* deallocated */
f4681817
MD
146}
147
148static
149void objd_ref(int id)
150{
151 struct obj *obj = _objd_get(id);
152 obj->u.s.f_count++;
153}
154
1ea11eab 155int objd_unref(int id)
f4681817
MD
156{
157 struct obj *obj = _objd_get(id);
158
1ea11eab
MD
159 if (!obj)
160 return -EINVAL;
a4be8962
MD
161 if (obj->u.s.f_count == 1) {
162 ERR("Reference counting error\n");
163 return -EINVAL;
164 }
165 if ((--obj->u.s.f_count) == 1) {
f4681817 166 const struct objd_ops *ops = objd_ops(id);
a4be8962 167
f4681817
MD
168 if (ops->release)
169 ops->release(id);
170 objd_free(id);
171 }
1ea11eab 172 return 0;
f4681817
MD
173}
174
175static
176void objd_table_destroy(void)
177{
a4be8962
MD
178 int i;
179
180 for (i = 0; i < objd_table.allocated_len; i++) {
181 struct obj *obj = _objd_get(i);
182 const struct objd_ops *ops;
183
184 if (!obj)
185 continue;
186 ops = obj->u.s.ops;
187 if (ops->release)
188 ops->release(i);
189 }
f4681817 190 free(objd_table.array);
02fb3381
MD
191 objd_table.array = NULL;
192 objd_table.len = 0;
193 objd_table.allocated_len = 0;
17dfb34b 194 objd_table.freelist_head = -1;
f4681817
MD
195}
196
197/*
198 * This is LTTng's own personal way to create an ABI for sessiond.
199 * We send commands over a socket.
200 */
201
202static const struct objd_ops lttng_ops;
203static const struct objd_ops lttng_session_ops;
204static const struct objd_ops lttng_channel_ops;
205static const struct objd_ops lttng_metadata_ops;
206static const struct objd_ops lttng_event_ops;
207
208enum channel_type {
209 PER_CPU_CHANNEL,
210 METADATA_CHANNEL,
211};
212
46050b1a
MD
213int lttng_abi_create_root_handle(void)
214{
215 int root_handle;
216
217 root_handle = objd_alloc(NULL, &lttng_ops);
218 assert(root_handle == 0);
219 return root_handle;
220}
221
818173b9 222static
f4681817
MD
223int lttng_abi_create_session(void)
224{
225 struct ltt_session *session;
226 int session_objd, ret;
227
228 session = ltt_session_create();
229 if (!session)
230 return -ENOMEM;
231 session_objd = objd_alloc(session, &lttng_session_ops);
232 if (session_objd < 0) {
233 ret = session_objd;
234 goto objd_error;
235 }
236 session->objd = session_objd;
237 return session_objd;
238
239objd_error:
240 ltt_session_destroy(session);
241 return ret;
242}
243
244#if 0
245static
246int lttng_abi_tracepoint_list(void)
247{
248 int list_objd, ret;
249
250 /* TODO: Create list private data */
251 list_objd = objd_alloc(NULL, &lttng_tracepoint_list_ops);
252 if (list_objd < 0) {
253 ret = list_objd;
254 goto objd_error;
255 }
256
257 return list_objd;
258
259objd_error:
260 return ret;
261}
262#endif //0
263
264static
265long lttng_abi_tracer_version(int objd,
266 struct lttng_ust_tracer_version *v)
267{
268 v->version = LTTNG_UST_VERSION;
269 v->patchlevel = LTTNG_UST_PATCHLEVEL;
270 v->sublevel = LTTNG_UST_SUBLEVEL;
271 return 0;
272}
273
274static
275long lttng_abi_add_context(int objd,
276 struct lttng_ust_context *context_param,
277 struct lttng_ctx **ctx, struct ltt_session *session)
278{
279 if (session->been_active)
280 return -EPERM;
281
282 switch (context_param->ctx) {
283 case LTTNG_UST_CONTEXT_VTID:
438bc215 284 //TODO return lttng_add_vtid_to_ctx(ctx);
f4681817
MD
285 default:
286 return -EINVAL;
287 }
288}
289
290/**
291 * lttng_cmd - lttng control through socket commands
292 *
293 * @objd: the object descriptor
294 * @cmd: the command
295 * @arg: command arg
296 *
297 * This descriptor implements lttng commands:
298 * LTTNG_UST_SESSION
299 * Returns a LTTng trace session object descriptor
300 * LTTNG_UST_TRACER_VERSION
301 * Returns the LTTng kernel tracer version
302 * LTTNG_UST_TRACEPOINT_LIST
303 * Returns a file descriptor listing available tracepoints
304 * LTTNG_UST_WAIT_QUIESCENT
305 * Returns after all previously running probes have completed
306 *
307 * The returned session will be deleted when its file descriptor is closed.
308 */
309static
310long lttng_cmd(int objd, unsigned int cmd, unsigned long arg)
311{
312 switch (cmd) {
313 case LTTNG_UST_SESSION:
314 return lttng_abi_create_session();
315 case LTTNG_UST_TRACER_VERSION:
316 return lttng_abi_tracer_version(objd,
317 (struct lttng_ust_tracer_version *) arg);
318 case LTTNG_UST_TRACEPOINT_LIST:
319 return -ENOSYS; //TODO
320 //return lttng_abi_tracepoint_list();
321 case LTTNG_UST_WAIT_QUIESCENT:
322 synchronize_trace();
323 return 0;
324 default:
325 return -EINVAL;
326 }
327}
328
329static const struct objd_ops lttng_ops = {
330 .cmd = lttng_cmd,
331};
332
333/*
334 * We tolerate no failure in this function (if one happens, we print a dmesg
335 * error, but cannot return any error, because the channel information is
336 * invariant.
337 */
338static
339void lttng_metadata_create_events(int channel_objd)
340{
341 struct ltt_channel *channel = objd_private(channel_objd);
342 static struct lttng_ust_event metadata_params = {
343 .instrumentation = LTTNG_UST_TRACEPOINT,
344 .name = "lttng_metadata",
345 };
346 struct ltt_event *event;
347 int ret;
348
349 /*
350 * We tolerate no failure path after event creation. It will stay
351 * invariant for the rest of the session.
352 */
353 event = ltt_event_create(channel, &metadata_params, NULL);
354 if (!event) {
355 ret = -EINVAL;
356 goto create_error;
357 }
358 return;
359
360create_error:
361 WARN_ON(1);
362 return; /* not allowed to return error */
363}
364
f4681817
MD
365int lttng_abi_create_channel(int session_objd,
366 struct lttng_ust_channel *chan_param,
367 enum channel_type channel_type)
368{
369 struct ltt_session *session = objd_private(session_objd);
370 const struct objd_ops *ops;
371 const char *transport_name;
372 struct ltt_channel *chan;
373 int chan_objd;
374 int ret = 0;
375
376 chan_objd = objd_alloc(NULL, &lttng_channel_ops);
377 if (chan_objd < 0) {
378 ret = chan_objd;
379 goto objd_error;
380 }
381 switch (channel_type) {
382 case PER_CPU_CHANNEL:
383 if (chan_param->output == LTTNG_UST_MMAP) {
384 transport_name = chan_param->overwrite ?
385 "relay-overwrite-mmap" : "relay-discard-mmap";
386 } else {
387 return -EINVAL;
388 }
389 ops = &lttng_channel_ops;
390 break;
391 case METADATA_CHANNEL:
392 if (chan_param->output == LTTNG_UST_MMAP)
393 transport_name = "relay-metadata-mmap";
394 else
395 return -EINVAL;
396 ops = &lttng_metadata_ops;
397 break;
398 default:
399 transport_name = "<unknown>";
400 break;
401 }
402 /*
403 * We tolerate no failure path after channel creation. It will stay
404 * invariant for the rest of the session.
405 */
406 chan = ltt_channel_create(session, transport_name, NULL,
407 chan_param->subbuf_size,
408 chan_param->num_subbuf,
409 chan_param->switch_timer_interval,
410 chan_param->read_timer_interval);
411 if (!chan) {
412 ret = -EINVAL;
413 goto chan_error;
414 }
415 objd_set_private(chan_objd, chan);
416 chan->objd = chan_objd;
417 if (channel_type == METADATA_CHANNEL) {
418 session->metadata = chan;
419 lttng_metadata_create_events(chan_objd);
420 }
421
422 /* The channel created holds a reference on the session */
423 objd_ref(session_objd);
424
425 return chan_objd;
426
427chan_error:
1ea11eab
MD
428 {
429 int err;
430
431 err = objd_unref(chan_objd);
432 assert(!err);
433 }
f4681817
MD
434objd_error:
435 return ret;
436}
437
438/**
439 * lttng_session_cmd - lttng session object command
440 *
441 * @obj: the object
442 * @cmd: the command
443 * @arg: command arg
444 *
445 * This descriptor implements lttng commands:
446 * LTTNG_UST_CHANNEL
447 * Returns a LTTng channel object descriptor
448 * LTTNG_UST_ENABLE
449 * Enables tracing for a session (weak enable)
450 * LTTNG_UST_DISABLE
451 * Disables tracing for a session (strong disable)
452 * LTTNG_UST_METADATA
453 * Returns a LTTng metadata object descriptor
454 *
455 * The returned channel will be deleted when its file descriptor is closed.
456 */
457static
458long lttng_session_cmd(int objd, unsigned int cmd, unsigned long arg)
459{
460 struct ltt_session *session = objd_private(objd);
461
462 switch (cmd) {
463 case LTTNG_UST_CHANNEL:
464 return lttng_abi_create_channel(objd,
465 (struct lttng_ust_channel *) arg,
466 PER_CPU_CHANNEL);
467 case LTTNG_UST_SESSION_START:
468 case LTTNG_UST_ENABLE:
469 return ltt_session_enable(session);
470 case LTTNG_UST_SESSION_STOP:
471 case LTTNG_UST_DISABLE:
472 return ltt_session_disable(session);
473 case LTTNG_UST_METADATA:
474 return lttng_abi_create_channel(objd,
475 (struct lttng_ust_channel *) arg,
476 METADATA_CHANNEL);
477 default:
478 return -EINVAL;
479 }
480}
481
482/*
483 * Called when the last file reference is dropped.
484 *
485 * Big fat note: channels and events are invariant for the whole session after
486 * their creation. So this session destruction also destroys all channel and
487 * event structures specific to this session (they are not destroyed when their
488 * individual file is released).
489 */
490static
1ea11eab 491int lttng_release_session(int objd)
f4681817
MD
492{
493 struct ltt_session *session = objd_private(objd);
494
1ea11eab 495 if (session) {
f4681817 496 ltt_session_destroy(session);
1ea11eab
MD
497 return 0;
498 } else {
499 return -EINVAL;
500 }
f4681817
MD
501}
502
503static const struct objd_ops lttng_session_ops = {
1ea11eab 504 .release = lttng_release_session,
f4681817
MD
505 .cmd = lttng_session_cmd,
506};
507
508#if 0
509static
510int lttng_abi_open_stream(int channel_objd)
511{
512 struct ltt_channel *channel = objd_private(channel_objd);
513 struct lib_ring_buffer *buf;
514 int stream_objd, ret;
515
516 buf = channel->ops->buffer_read_open(channel->chan);
517 if (!buf)
518 return -ENOENT;
519
520 stream_objd = objd_alloc(buf, &lib_ring_buffer_objd_ops);
521 if (stream_objd < 0) {
522 ret = stream_objd;
523 goto objd_error;
524 }
525 /*
526 * The stream holds a reference to the channel within the generic ring
527 * buffer library, so no need to hold a refcount on the channel and
528 * session files here.
529 */
530 return stream_objd;
531
532objd_error:
533 channel->ops->buffer_read_close(buf);
534 return ret;
535}
536#endif //0
537
538static
539int lttng_abi_create_event(int channel_objd,
540 struct lttng_ust_event *event_param)
541{
542 struct ltt_channel *channel = objd_private(channel_objd);
543 struct ltt_event *event;
544 int event_objd, ret;
545
546 event_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
547 event_objd = objd_alloc(NULL, &lttng_event_ops);
548 if (event_objd < 0) {
549 ret = event_objd;
550 goto objd_error;
551 }
552 /*
553 * We tolerate no failure path after event creation. It will stay
554 * invariant for the rest of the session.
555 */
556 event = ltt_event_create(channel, event_param, NULL);
557 if (!event) {
558 ret = -EINVAL;
559 goto event_error;
560 }
561 objd_set_private(event_objd, event);
562 /* The event holds a reference on the channel */
563 objd_ref(channel_objd);
564 return event_objd;
565
566event_error:
1ea11eab
MD
567 {
568 int err;
569
570 err = objd_unref(event_objd);
571 assert(!err);
572 }
f4681817
MD
573objd_error:
574 return ret;
575}
576
577/**
578 * lttng_channel_cmd - lttng control through object descriptors
579 *
580 * @objd: the object descriptor
581 * @cmd: the command
582 * @arg: command arg
583 *
584 * This object descriptor implements lttng commands:
585 * LTTNG_UST_STREAM
586 * Returns an event stream object descriptor or failure.
587 * (typically, one event stream records events from one CPU)
588 * LTTNG_UST_EVENT
589 * Returns an event object descriptor or failure.
590 * LTTNG_UST_CONTEXT
591 * Prepend a context field to each event in the channel
592 * LTTNG_UST_ENABLE
593 * Enable recording for events in this channel (weak enable)
594 * LTTNG_UST_DISABLE
595 * Disable recording for events in this channel (strong disable)
596 *
597 * Channel and event file descriptors also hold a reference on the session.
598 */
599static
600long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg)
601{
602 struct ltt_channel *channel = objd_private(objd);
603
604 switch (cmd) {
605 case LTTNG_UST_STREAM:
606 return -ENOSYS; //TODO
607 //return lttng_abi_open_stream(objd);
608 case LTTNG_UST_EVENT:
609 return lttng_abi_create_event(objd, (struct lttng_ust_event *) arg);
610 case LTTNG_UST_CONTEXT:
611 return lttng_abi_add_context(objd,
612 (struct lttng_ust_context *) arg,
613 &channel->ctx, channel->session);
614 case LTTNG_UST_ENABLE:
615 return ltt_channel_enable(channel);
616 case LTTNG_UST_DISABLE:
617 return ltt_channel_disable(channel);
618 default:
619 return -EINVAL;
620 }
621}
622
623/**
624 * lttng_metadata_cmd - lttng control through object descriptors
625 *
626 * @objd: the object descriptor
627 * @cmd: the command
628 * @arg: command arg
629 *
630 * This object descriptor implements lttng commands:
631 * LTTNG_UST_STREAM
632 * Returns an event stream file descriptor or failure.
633 *
634 * Channel and event file descriptors also hold a reference on the session.
635 */
636static
637long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg)
638{
639 switch (cmd) {
640 case LTTNG_UST_STREAM:
641 return -ENOSYS; //TODO
642 //return lttng_abi_open_stream(objd);
643 default:
644 return -EINVAL;
645 }
646}
647
648#if 0
649/**
650 * lttng_channel_poll - lttng stream addition/removal monitoring
651 *
652 * @file: the file
653 * @wait: poll table
654 */
655unsigned int lttng_channel_poll(struct file *file, poll_table *wait)
656{
657 struct ltt_channel *channel = file->private_data;
658 unsigned int mask = 0;
659
660 if (file->f_mode & FMODE_READ) {
661 poll_wait_set_exclusive(wait);
662 poll_wait(file, channel->ops->get_hp_wait_queue(channel->chan),
663 wait);
664
665 if (channel->ops->is_disabled(channel->chan))
666 return POLLERR;
667 if (channel->ops->is_finalized(channel->chan))
668 return POLLHUP;
669 if (channel->ops->buffer_has_read_closed_stream(channel->chan))
670 return POLLIN | POLLRDNORM;
671 return 0;
672 }
673 return mask;
674
675}
676#endif //0
677
678static
679int lttng_channel_release(int objd)
680{
681 struct ltt_channel *channel = objd_private(objd);
682
683 if (channel)
1ea11eab 684 return objd_unref(channel->session->objd);
f4681817
MD
685 return 0;
686}
687
688static const struct objd_ops lttng_channel_ops = {
689 .release = lttng_channel_release,
690 //.poll = lttng_channel_poll,
691 .cmd = lttng_channel_cmd,
692};
693
694static const struct objd_ops lttng_metadata_ops = {
695 .release = lttng_channel_release,
696 .cmd = lttng_metadata_cmd,
697};
698
699/**
700 * lttng_event_cmd - lttng control through object descriptors
701 *
702 * @objd: the object descriptor
703 * @cmd: the command
704 * @arg: command arg
705 *
706 * This object descriptor implements lttng commands:
707 * LTTNG_UST_CONTEXT
708 * Prepend a context field to each record of this event
709 * LTTNG_UST_ENABLE
710 * Enable recording for this event (weak enable)
711 * LTTNG_UST_DISABLE
712 * Disable recording for this event (strong disable)
713 */
714static
715long lttng_event_cmd(int objd, unsigned int cmd, unsigned long arg)
716{
717 struct ltt_event *event = objd_private(objd);
718
719 switch (cmd) {
720 case LTTNG_UST_CONTEXT:
721 return lttng_abi_add_context(objd,
722 (struct lttng_ust_context *) arg,
723 &event->ctx, event->chan->session);
724 case LTTNG_UST_ENABLE:
725 return ltt_event_enable(event);
726 case LTTNG_UST_DISABLE:
727 return ltt_event_disable(event);
728 default:
729 return -EINVAL;
730 }
731}
732
733static
734int lttng_event_release(int objd)
735{
736 struct ltt_event *event = objd_private(objd);
737
738 if (event)
1ea11eab 739 return objd_unref(event->chan->objd);
f4681817
MD
740 return 0;
741}
742
743/* TODO: filter control ioctl */
744static const struct objd_ops lttng_event_ops = {
745 .release = lttng_event_release,
746 .cmd = lttng_event_cmd,
747};
748
b35d179d 749void lttng_ust_abi_exit(void)
f4681817 750{
f4681817
MD
751 objd_table_destroy();
752}
This page took 0.051163 seconds and 4 git commands to generate.