fork test needs to link to libustfork
[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
MD
190 free(objd_table.array);
191}
192
193/*
194 * This is LTTng's own personal way to create an ABI for sessiond.
195 * We send commands over a socket.
196 */
197
198static const struct objd_ops lttng_ops;
199static const struct objd_ops lttng_session_ops;
200static const struct objd_ops lttng_channel_ops;
201static const struct objd_ops lttng_metadata_ops;
202static const struct objd_ops lttng_event_ops;
203
204enum channel_type {
205 PER_CPU_CHANNEL,
206 METADATA_CHANNEL,
207};
208
46050b1a
MD
209int lttng_abi_create_root_handle(void)
210{
211 int root_handle;
212
213 root_handle = objd_alloc(NULL, &lttng_ops);
214 assert(root_handle == 0);
215 return root_handle;
216}
217
818173b9 218static
f4681817
MD
219int lttng_abi_create_session(void)
220{
221 struct ltt_session *session;
222 int session_objd, ret;
223
224 session = ltt_session_create();
225 if (!session)
226 return -ENOMEM;
227 session_objd = objd_alloc(session, &lttng_session_ops);
228 if (session_objd < 0) {
229 ret = session_objd;
230 goto objd_error;
231 }
232 session->objd = session_objd;
233 return session_objd;
234
235objd_error:
236 ltt_session_destroy(session);
237 return ret;
238}
239
240#if 0
241static
242int lttng_abi_tracepoint_list(void)
243{
244 int list_objd, ret;
245
246 /* TODO: Create list private data */
247 list_objd = objd_alloc(NULL, &lttng_tracepoint_list_ops);
248 if (list_objd < 0) {
249 ret = list_objd;
250 goto objd_error;
251 }
252
253 return list_objd;
254
255objd_error:
256 return ret;
257}
258#endif //0
259
260static
261long lttng_abi_tracer_version(int objd,
262 struct lttng_ust_tracer_version *v)
263{
264 v->version = LTTNG_UST_VERSION;
265 v->patchlevel = LTTNG_UST_PATCHLEVEL;
266 v->sublevel = LTTNG_UST_SUBLEVEL;
267 return 0;
268}
269
270static
271long lttng_abi_add_context(int objd,
272 struct lttng_ust_context *context_param,
273 struct lttng_ctx **ctx, struct ltt_session *session)
274{
275 if (session->been_active)
276 return -EPERM;
277
278 switch (context_param->ctx) {
279 case LTTNG_UST_CONTEXT_VTID:
438bc215 280 //TODO return lttng_add_vtid_to_ctx(ctx);
f4681817
MD
281 default:
282 return -EINVAL;
283 }
284}
285
286/**
287 * lttng_cmd - lttng control through socket commands
288 *
289 * @objd: the object descriptor
290 * @cmd: the command
291 * @arg: command arg
292 *
293 * This descriptor implements lttng commands:
294 * LTTNG_UST_SESSION
295 * Returns a LTTng trace session object descriptor
296 * LTTNG_UST_TRACER_VERSION
297 * Returns the LTTng kernel tracer version
298 * LTTNG_UST_TRACEPOINT_LIST
299 * Returns a file descriptor listing available tracepoints
300 * LTTNG_UST_WAIT_QUIESCENT
301 * Returns after all previously running probes have completed
302 *
303 * The returned session will be deleted when its file descriptor is closed.
304 */
305static
306long lttng_cmd(int objd, unsigned int cmd, unsigned long arg)
307{
308 switch (cmd) {
309 case LTTNG_UST_SESSION:
310 return lttng_abi_create_session();
311 case LTTNG_UST_TRACER_VERSION:
312 return lttng_abi_tracer_version(objd,
313 (struct lttng_ust_tracer_version *) arg);
314 case LTTNG_UST_TRACEPOINT_LIST:
315 return -ENOSYS; //TODO
316 //return lttng_abi_tracepoint_list();
317 case LTTNG_UST_WAIT_QUIESCENT:
318 synchronize_trace();
319 return 0;
320 default:
321 return -EINVAL;
322 }
323}
324
325static const struct objd_ops lttng_ops = {
326 .cmd = lttng_cmd,
327};
328
329/*
330 * We tolerate no failure in this function (if one happens, we print a dmesg
331 * error, but cannot return any error, because the channel information is
332 * invariant.
333 */
334static
335void lttng_metadata_create_events(int channel_objd)
336{
337 struct ltt_channel *channel = objd_private(channel_objd);
338 static struct lttng_ust_event metadata_params = {
339 .instrumentation = LTTNG_UST_TRACEPOINT,
340 .name = "lttng_metadata",
341 };
342 struct ltt_event *event;
343 int ret;
344
345 /*
346 * We tolerate no failure path after event creation. It will stay
347 * invariant for the rest of the session.
348 */
349 event = ltt_event_create(channel, &metadata_params, NULL);
350 if (!event) {
351 ret = -EINVAL;
352 goto create_error;
353 }
354 return;
355
356create_error:
357 WARN_ON(1);
358 return; /* not allowed to return error */
359}
360
f4681817
MD
361int lttng_abi_create_channel(int session_objd,
362 struct lttng_ust_channel *chan_param,
363 enum channel_type channel_type)
364{
365 struct ltt_session *session = objd_private(session_objd);
366 const struct objd_ops *ops;
367 const char *transport_name;
368 struct ltt_channel *chan;
369 int chan_objd;
370 int ret = 0;
371
372 chan_objd = objd_alloc(NULL, &lttng_channel_ops);
373 if (chan_objd < 0) {
374 ret = chan_objd;
375 goto objd_error;
376 }
377 switch (channel_type) {
378 case PER_CPU_CHANNEL:
379 if (chan_param->output == LTTNG_UST_MMAP) {
380 transport_name = chan_param->overwrite ?
381 "relay-overwrite-mmap" : "relay-discard-mmap";
382 } else {
383 return -EINVAL;
384 }
385 ops = &lttng_channel_ops;
386 break;
387 case METADATA_CHANNEL:
388 if (chan_param->output == LTTNG_UST_MMAP)
389 transport_name = "relay-metadata-mmap";
390 else
391 return -EINVAL;
392 ops = &lttng_metadata_ops;
393 break;
394 default:
395 transport_name = "<unknown>";
396 break;
397 }
398 /*
399 * We tolerate no failure path after channel creation. It will stay
400 * invariant for the rest of the session.
401 */
402 chan = ltt_channel_create(session, transport_name, NULL,
403 chan_param->subbuf_size,
404 chan_param->num_subbuf,
405 chan_param->switch_timer_interval,
406 chan_param->read_timer_interval);
407 if (!chan) {
408 ret = -EINVAL;
409 goto chan_error;
410 }
411 objd_set_private(chan_objd, chan);
412 chan->objd = chan_objd;
413 if (channel_type == METADATA_CHANNEL) {
414 session->metadata = chan;
415 lttng_metadata_create_events(chan_objd);
416 }
417
418 /* The channel created holds a reference on the session */
419 objd_ref(session_objd);
420
421 return chan_objd;
422
423chan_error:
1ea11eab
MD
424 {
425 int err;
426
427 err = objd_unref(chan_objd);
428 assert(!err);
429 }
f4681817
MD
430objd_error:
431 return ret;
432}
433
434/**
435 * lttng_session_cmd - lttng session object command
436 *
437 * @obj: the object
438 * @cmd: the command
439 * @arg: command arg
440 *
441 * This descriptor implements lttng commands:
442 * LTTNG_UST_CHANNEL
443 * Returns a LTTng channel object descriptor
444 * LTTNG_UST_ENABLE
445 * Enables tracing for a session (weak enable)
446 * LTTNG_UST_DISABLE
447 * Disables tracing for a session (strong disable)
448 * LTTNG_UST_METADATA
449 * Returns a LTTng metadata object descriptor
450 *
451 * The returned channel will be deleted when its file descriptor is closed.
452 */
453static
454long lttng_session_cmd(int objd, unsigned int cmd, unsigned long arg)
455{
456 struct ltt_session *session = objd_private(objd);
457
458 switch (cmd) {
459 case LTTNG_UST_CHANNEL:
460 return lttng_abi_create_channel(objd,
461 (struct lttng_ust_channel *) arg,
462 PER_CPU_CHANNEL);
463 case LTTNG_UST_SESSION_START:
464 case LTTNG_UST_ENABLE:
465 return ltt_session_enable(session);
466 case LTTNG_UST_SESSION_STOP:
467 case LTTNG_UST_DISABLE:
468 return ltt_session_disable(session);
469 case LTTNG_UST_METADATA:
470 return lttng_abi_create_channel(objd,
471 (struct lttng_ust_channel *) arg,
472 METADATA_CHANNEL);
473 default:
474 return -EINVAL;
475 }
476}
477
478/*
479 * Called when the last file reference is dropped.
480 *
481 * Big fat note: channels and events are invariant for the whole session after
482 * their creation. So this session destruction also destroys all channel and
483 * event structures specific to this session (they are not destroyed when their
484 * individual file is released).
485 */
486static
1ea11eab 487int lttng_release_session(int objd)
f4681817
MD
488{
489 struct ltt_session *session = objd_private(objd);
490
1ea11eab 491 if (session) {
f4681817 492 ltt_session_destroy(session);
1ea11eab
MD
493 return 0;
494 } else {
495 return -EINVAL;
496 }
f4681817
MD
497}
498
499static const struct objd_ops lttng_session_ops = {
1ea11eab 500 .release = lttng_release_session,
f4681817
MD
501 .cmd = lttng_session_cmd,
502};
503
504#if 0
505static
506int lttng_abi_open_stream(int channel_objd)
507{
508 struct ltt_channel *channel = objd_private(channel_objd);
509 struct lib_ring_buffer *buf;
510 int stream_objd, ret;
511
512 buf = channel->ops->buffer_read_open(channel->chan);
513 if (!buf)
514 return -ENOENT;
515
516 stream_objd = objd_alloc(buf, &lib_ring_buffer_objd_ops);
517 if (stream_objd < 0) {
518 ret = stream_objd;
519 goto objd_error;
520 }
521 /*
522 * The stream holds a reference to the channel within the generic ring
523 * buffer library, so no need to hold a refcount on the channel and
524 * session files here.
525 */
526 return stream_objd;
527
528objd_error:
529 channel->ops->buffer_read_close(buf);
530 return ret;
531}
532#endif //0
533
534static
535int lttng_abi_create_event(int channel_objd,
536 struct lttng_ust_event *event_param)
537{
538 struct ltt_channel *channel = objd_private(channel_objd);
539 struct ltt_event *event;
540 int event_objd, ret;
541
542 event_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
543 event_objd = objd_alloc(NULL, &lttng_event_ops);
544 if (event_objd < 0) {
545 ret = event_objd;
546 goto objd_error;
547 }
548 /*
549 * We tolerate no failure path after event creation. It will stay
550 * invariant for the rest of the session.
551 */
552 event = ltt_event_create(channel, event_param, NULL);
553 if (!event) {
554 ret = -EINVAL;
555 goto event_error;
556 }
557 objd_set_private(event_objd, event);
558 /* The event holds a reference on the channel */
559 objd_ref(channel_objd);
560 return event_objd;
561
562event_error:
1ea11eab
MD
563 {
564 int err;
565
566 err = objd_unref(event_objd);
567 assert(!err);
568 }
f4681817
MD
569objd_error:
570 return ret;
571}
572
573/**
574 * lttng_channel_cmd - lttng control through object descriptors
575 *
576 * @objd: the object descriptor
577 * @cmd: the command
578 * @arg: command arg
579 *
580 * This object descriptor implements lttng commands:
581 * LTTNG_UST_STREAM
582 * Returns an event stream object descriptor or failure.
583 * (typically, one event stream records events from one CPU)
584 * LTTNG_UST_EVENT
585 * Returns an event object descriptor or failure.
586 * LTTNG_UST_CONTEXT
587 * Prepend a context field to each event in the channel
588 * LTTNG_UST_ENABLE
589 * Enable recording for events in this channel (weak enable)
590 * LTTNG_UST_DISABLE
591 * Disable recording for events in this channel (strong disable)
592 *
593 * Channel and event file descriptors also hold a reference on the session.
594 */
595static
596long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg)
597{
598 struct ltt_channel *channel = objd_private(objd);
599
600 switch (cmd) {
601 case LTTNG_UST_STREAM:
602 return -ENOSYS; //TODO
603 //return lttng_abi_open_stream(objd);
604 case LTTNG_UST_EVENT:
605 return lttng_abi_create_event(objd, (struct lttng_ust_event *) arg);
606 case LTTNG_UST_CONTEXT:
607 return lttng_abi_add_context(objd,
608 (struct lttng_ust_context *) arg,
609 &channel->ctx, channel->session);
610 case LTTNG_UST_ENABLE:
611 return ltt_channel_enable(channel);
612 case LTTNG_UST_DISABLE:
613 return ltt_channel_disable(channel);
614 default:
615 return -EINVAL;
616 }
617}
618
619/**
620 * lttng_metadata_cmd - lttng control through object descriptors
621 *
622 * @objd: the object descriptor
623 * @cmd: the command
624 * @arg: command arg
625 *
626 * This object descriptor implements lttng commands:
627 * LTTNG_UST_STREAM
628 * Returns an event stream file descriptor or failure.
629 *
630 * Channel and event file descriptors also hold a reference on the session.
631 */
632static
633long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg)
634{
635 switch (cmd) {
636 case LTTNG_UST_STREAM:
637 return -ENOSYS; //TODO
638 //return lttng_abi_open_stream(objd);
639 default:
640 return -EINVAL;
641 }
642}
643
644#if 0
645/**
646 * lttng_channel_poll - lttng stream addition/removal monitoring
647 *
648 * @file: the file
649 * @wait: poll table
650 */
651unsigned int lttng_channel_poll(struct file *file, poll_table *wait)
652{
653 struct ltt_channel *channel = file->private_data;
654 unsigned int mask = 0;
655
656 if (file->f_mode & FMODE_READ) {
657 poll_wait_set_exclusive(wait);
658 poll_wait(file, channel->ops->get_hp_wait_queue(channel->chan),
659 wait);
660
661 if (channel->ops->is_disabled(channel->chan))
662 return POLLERR;
663 if (channel->ops->is_finalized(channel->chan))
664 return POLLHUP;
665 if (channel->ops->buffer_has_read_closed_stream(channel->chan))
666 return POLLIN | POLLRDNORM;
667 return 0;
668 }
669 return mask;
670
671}
672#endif //0
673
674static
675int lttng_channel_release(int objd)
676{
677 struct ltt_channel *channel = objd_private(objd);
678
679 if (channel)
1ea11eab 680 return objd_unref(channel->session->objd);
f4681817
MD
681 return 0;
682}
683
684static const struct objd_ops lttng_channel_ops = {
685 .release = lttng_channel_release,
686 //.poll = lttng_channel_poll,
687 .cmd = lttng_channel_cmd,
688};
689
690static const struct objd_ops lttng_metadata_ops = {
691 .release = lttng_channel_release,
692 .cmd = lttng_metadata_cmd,
693};
694
695/**
696 * lttng_event_cmd - lttng control through object descriptors
697 *
698 * @objd: the object descriptor
699 * @cmd: the command
700 * @arg: command arg
701 *
702 * This object descriptor implements lttng commands:
703 * LTTNG_UST_CONTEXT
704 * Prepend a context field to each record of this event
705 * LTTNG_UST_ENABLE
706 * Enable recording for this event (weak enable)
707 * LTTNG_UST_DISABLE
708 * Disable recording for this event (strong disable)
709 */
710static
711long lttng_event_cmd(int objd, unsigned int cmd, unsigned long arg)
712{
713 struct ltt_event *event = objd_private(objd);
714
715 switch (cmd) {
716 case LTTNG_UST_CONTEXT:
717 return lttng_abi_add_context(objd,
718 (struct lttng_ust_context *) arg,
719 &event->ctx, event->chan->session);
720 case LTTNG_UST_ENABLE:
721 return ltt_event_enable(event);
722 case LTTNG_UST_DISABLE:
723 return ltt_event_disable(event);
724 default:
725 return -EINVAL;
726 }
727}
728
729static
730int lttng_event_release(int objd)
731{
732 struct ltt_event *event = objd_private(objd);
733
734 if (event)
1ea11eab 735 return objd_unref(event->chan->objd);
f4681817
MD
736 return 0;
737}
738
739/* TODO: filter control ioctl */
740static const struct objd_ops lttng_event_ops = {
741 .release = lttng_event_release,
742 .cmd = lttng_event_cmd,
743};
744
b35d179d 745void lttng_ust_abi_exit(void)
f4681817 746{
f4681817
MD
747 objd_table_destroy();
748}
This page took 0.050248 seconds and 4 git commands to generate.