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