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