ust comm: more resilient handle table, fix size of reply
[lttng-ust.git] / libust / lttng-ust-abi.c
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>
31 #include <ust/usterr-signal-safe.h>
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
40 struct obj;
41
42 struct objd_ops {
43 long (*cmd)(int objd, unsigned int cmd, unsigned long arg);
44 int (*release)(int objd);
45 };
46
47 struct 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
58 struct objd_table {
59 struct obj *array;
60 unsigned int len, allocated_len;
61 int freelist_head; /* offset freelist head. end is -1 */
62 };
63
64 static struct objd_table objd_table = {
65 .freelist_head = -1,
66 };
67
68 static
69 int 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++;
100 end:
101 obj->u.s.private_data = private_data;
102 obj->u.s.ops = ops;
103 obj->u.s.f_count = 2; /* count == 1 : object is allocated */
104 /* count == 2 : allocated + hold ref */
105 return obj - objd_table.array;
106 }
107
108 static
109 struct obj *_objd_get(int id)
110 {
111 if (id >= objd_table.len)
112 return NULL;
113 if (!objd_table.array[id].u.s.f_count)
114 return NULL;
115 return &objd_table.array[id];
116 }
117
118 static
119 void *objd_private(int id)
120 {
121 struct obj *obj = _objd_get(id);
122 assert(obj);
123 return obj->u.s.private_data;
124 }
125
126 static
127 void 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
134 static
135 const struct objd_ops *objd_ops(int id)
136 {
137 struct obj *obj = _objd_get(id);
138 if (!obj)
139 return NULL;
140 return obj->u.s.ops;
141 }
142
143 static
144 void 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;
151 assert(obj->u.s.f_count == 1);
152 obj->u.s.f_count = 0; /* deallocated */
153 }
154
155 static
156 void objd_ref(int id)
157 {
158 struct obj *obj = _objd_get(id);
159 obj->u.s.f_count++;
160 }
161
162 int objd_unref(int id)
163 {
164 struct obj *obj = _objd_get(id);
165
166 if (!obj)
167 return -EINVAL;
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) {
173 const struct objd_ops *ops = objd_ops(id);
174
175 if (ops->release)
176 ops->release(id);
177 objd_free(id);
178 }
179 return 0;
180 }
181
182 static
183 void objd_table_destroy(void)
184 {
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 }
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
205 static const struct objd_ops lttng_ops;
206 static const struct objd_ops lttng_session_ops;
207 static const struct objd_ops lttng_channel_ops;
208 static const struct objd_ops lttng_metadata_ops;
209 static const struct objd_ops lttng_event_ops;
210
211 enum channel_type {
212 PER_CPU_CHANNEL,
213 METADATA_CHANNEL,
214 };
215
216 int 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
232 objd_error:
233 ltt_session_destroy(session);
234 return ret;
235 }
236
237 #if 0
238 static
239 int 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
252 objd_error:
253 return ret;
254 }
255 #endif //0
256
257 static
258 long 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
267 static
268 long 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:
277 //TODO return lttng_add_vtid_to_ctx(ctx);
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 */
302 static
303 long 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
322 static 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 */
331 static
332 void 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
353 create_error:
354 WARN_ON(1);
355 return; /* not allowed to return error */
356 }
357
358 static
359 int 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
421 chan_error:
422 {
423 int err;
424
425 err = objd_unref(chan_objd);
426 assert(!err);
427 }
428 objd_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 */
451 static
452 long 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 */
484 static
485 int lttng_release_session(int objd)
486 {
487 struct ltt_session *session = objd_private(objd);
488
489 if (session) {
490 ltt_session_destroy(session);
491 return 0;
492 } else {
493 return -EINVAL;
494 }
495 }
496
497 static const struct objd_ops lttng_session_ops = {
498 .release = lttng_release_session,
499 .cmd = lttng_session_cmd,
500 };
501
502 #if 0
503 static
504 int 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
526 objd_error:
527 channel->ops->buffer_read_close(buf);
528 return ret;
529 }
530 #endif //0
531
532 static
533 int 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
560 event_error:
561 {
562 int err;
563
564 err = objd_unref(event_objd);
565 assert(!err);
566 }
567 objd_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 */
593 static
594 long 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 */
630 static
631 long 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 */
649 unsigned 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
672 static
673 int lttng_channel_release(int objd)
674 {
675 struct ltt_channel *channel = objd_private(objd);
676
677 if (channel)
678 return objd_unref(channel->session->objd);
679 return 0;
680 }
681
682 static const struct objd_ops lttng_channel_ops = {
683 .release = lttng_channel_release,
684 //.poll = lttng_channel_poll,
685 .cmd = lttng_channel_cmd,
686 };
687
688 static 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 */
708 static
709 long 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
727 static
728 int lttng_event_release(int objd)
729 {
730 struct ltt_event *event = objd_private(objd);
731
732 if (event)
733 return objd_unref(event->chan->objd);
734 return 0;
735 }
736
737 /* TODO: filter control ioctl */
738 static const struct objd_ops lttng_event_ops = {
739 .release = lttng_event_release,
740 .cmd = lttng_event_cmd,
741 };
742
743 void lttng_ust_abi_exit(void)
744 {
745 objd_table_destroy();
746 }
This page took 0.04521 seconds and 4 git commands to generate.