From f4681817263e0d8daa2839da41ea3ef666d6bc1b Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 4 Aug 2011 10:20:00 -0400 Subject: [PATCH] Commit changes prior to shmp read-only header Signed-off-by: Mathieu Desnoyers --- libust/Makefile.am | 3 +- libust/ltt-context.c | 2 +- libust/ltt-events.c | 8 +- libust/ltt-probes.c | 3 +- libust/ltt-ring-buffer-metadata-client.h | 2 +- libust/ltt-tracer.h | 8 +- libust/lttng-ust-abi.c | 717 +++++++++++++++++++++++ 7 files changed, 731 insertions(+), 12 deletions(-) create mode 100644 libust/lttng-ust-abi.c diff --git a/libust/Makefile.am b/libust/Makefile.am index dfd96361..7e5a0df9 100644 --- a/libust/Makefile.am +++ b/libust/Makefile.am @@ -13,7 +13,8 @@ libust_la_SOURCES = \ ltt-ring-buffer-client-overwrite.c \ ltt-ring-buffer-metadata-client.h \ ltt-ring-buffer-metadata-client.c \ - ltt-events.c + ltt-events.c \ + lttng-ust-abi.c #removed: buffers.c buffers.h diff --git a/libust/ltt-context.c b/libust/ltt-context.c index 402f0c48..dd526542 100644 --- a/libust/ltt-context.c +++ b/libust/ltt-context.c @@ -12,8 +12,8 @@ #include #include #include +#include #include "wrapper/vmalloc.h" /* for wrapper_vmalloc_sync_all() */ -#include "ltt-events.h" #include "ltt-tracer.h" /* diff --git a/libust/ltt-events.c b/libust/ltt-events.c index d28a430d..f048e278 100644 --- a/libust/ltt-events.c +++ b/libust/ltt-events.c @@ -18,9 +18,11 @@ #include #include #include +#include +#include +#include #include "usterr_signal_safe.h" #include "ust/core.h" -#include "ltt-events.h" #include "ltt-tracer.h" #include "ust/wait.h" @@ -194,8 +196,7 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, void *buf_addr, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, - unsigned int read_timer_interval, - int *shmid) + unsigned int read_timer_interval) { struct ltt_channel *chan; struct ltt_transport *transport; @@ -214,6 +215,7 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, goto nomem; chan->session = session; chan->id = session->free_chan_id++; + //chan->shmid = shmget(getpid(), shmlen, IPC_CREAT | IPC_EXCL | 0700); /* * Note: the channel creation op already writes into the packet * headers. Therefore the "chan" information used as input diff --git a/libust/ltt-probes.c b/libust/ltt-probes.c index 45d2dabd..789d8bd0 100644 --- a/libust/ltt-probes.c +++ b/libust/ltt-probes.c @@ -12,8 +12,7 @@ #include #include #include - -#include "ltt-events.h" +#include static LIST_HEAD(probe_list); static DEFINE_MUTEX(probe_mutex); diff --git a/libust/ltt-ring-buffer-metadata-client.h b/libust/ltt-ring-buffer-metadata-client.h index 1ea41176..52479b4b 100644 --- a/libust/ltt-ring-buffer-metadata-client.h +++ b/libust/ltt-ring-buffer-metadata-client.h @@ -9,8 +9,8 @@ */ #include +#include #include "ust/bitfield.h" -#include "ltt-events.h" #include "ltt-tracer.h" #include "../libringbuffer/frontend_types.h" diff --git a/libust/ltt-tracer.h b/libust/ltt-tracer.h index 0a94daa8..a79c5f76 100644 --- a/libust/ltt-tracer.h +++ b/libust/ltt-tracer.h @@ -27,12 +27,12 @@ #include #include #include +#include #include "ltt-tracer-core.h" -#include "ltt-events.h" -#define LTTNG_VERSION 0 -#define LTTNG_PATCHLEVEL 9 -#define LTTNG_SUBLEVEL 1 +#define LTTNG_UST_VERSION 0 +#define LTTNG_UST_PATCHLEVEL 9 +#define LTTNG_UST_SUBLEVEL 1 #ifndef CHAR_BIT #define CHAR_BIT 8 diff --git a/libust/lttng-ust-abi.c b/libust/lttng-ust-abi.c new file mode 100644 index 00000000..31eaa2a7 --- /dev/null +++ b/libust/lttng-ust-abi.c @@ -0,0 +1,717 @@ +/* + * lttng-ust-abi.c + * + * Copyright 2010-2011 (c) - Mathieu Desnoyers + * + * LTTng UST ABI + * + * Mimic system calls for: + * - session creation, returns an object descriptor or failure. + * - channel creation, returns an object descriptor or failure. + * - Operates on a session object descriptor + * - Takes all channel options as parameters. + * - stream get, returns an object descriptor or failure. + * - Operates on a channel object descriptor. + * - stream notifier get, returns an object descriptor or failure. + * - Operates on a channel object descriptor. + * - event creation, returns an object descriptor or failure. + * - Operates on a channel object descriptor + * - Takes an event name as parameter + * - Takes an instrumentation source as parameter + * - e.g. tracepoints, dynamic_probes... + * - Takes instrumentation source specific arguments. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include +#include "usterr_signal_safe.h" +#include "ust/core.h" +#include "ltt-tracer.h" + +/* + * Object descriptor table. Should be protected from concurrent access + * by the caller. + */ + +struct obj; + +struct objd_ops { + long (*cmd)(int objd, unsigned int cmd, unsigned long arg); + int (*release)(int objd); +}; + +struct obj { + union { + struct { + void *private_data; + const struct objd_ops *ops; + int f_count; + } s; + int freelist_next; /* offset freelist. end is -1. */ + } u; +}; + +struct objd_table { + struct obj *array; + unsigned int len, allocated_len; + int freelist_head; /* offset freelist head. end is -1 */ +}; + +static struct objd_table objd_table = { + .freelist_head = -1, +}; + +static +int objd_alloc(void *private_data, const struct objd_ops *ops) +{ + struct obj *obj; + + if (objd_table.freelist_head != -1) { + obj = &objd_table.array[objd_table.freelist_head]; + objd_table.freelist_head = obj->u.freelist_next; + goto end; + } + + if (objd_table.len >= objd_table.allocated_len) { + unsigned int new_allocated_len, old_allocated_len; + struct obj *new_table, *old_table; + + old_allocated_len = objd_table.allocated_len; + old_table = objd_table.array; + if (!old_allocated_len) + new_allocated_len = 1; + else + new_allocated_len = old_allocated_len << 1; + new_table = zmalloc(sizeof(struct obj) * new_allocated_len); + if (!new_table) + return -ENOMEM; + memcpy(new_table, old_table, + sizeof(struct obj) * old_allocated_len); + free(old_table); + objd_table.array = new_table; + objd_table.allocated_len = new_allocated_len; + } + obj = &objd_table.array[objd_table.len]; + objd_table.len++; +end: + obj->u.s.private_data = private_data; + obj->u.s.ops = ops; + obj->u.s.f_count = 1; + return obj - objd_table.array; +} + +static +struct obj *_objd_get(int id) +{ + if (id >= objd_table.len) + return NULL; + return &objd_table.array[id]; +} + +static +void *objd_private(int id) +{ + struct obj *obj = _objd_get(id); + assert(obj); + return obj->u.s.private_data; +} + +static +void objd_set_private(int id, void *private_data) +{ + struct obj *obj = _objd_get(id); + assert(obj); + obj->u.s.private_data = private_data; +} + +static +const struct objd_ops *objd_ops(int id) +{ + struct obj *obj = _objd_get(id); + assert(obj); + return obj->u.s.ops; +} + +static +void objd_free(int id) +{ + struct obj *obj = _objd_get(id); + + assert(obj); + obj->u.freelist_next = objd_table.freelist_head; + objd_table.freelist_head = obj - objd_table.array; +} + +static +void objd_ref(int id) +{ + struct obj *obj = _objd_get(id); + obj->u.s.f_count++; +} + +static +void objd_unref(int id) +{ + struct obj *obj = _objd_get(id); + + if (!(--obj->u.s.f_count)) { + const struct objd_ops *ops = objd_ops(id); + + if (ops->release) + ops->release(id); + objd_free(id); + } +} + +static +void objd_table_destroy(void) +{ + free(objd_table.array); +} + +/* + * This is LTTng's own personal way to create an ABI for sessiond. + * We send commands over a socket. + */ + +static const struct objd_ops lttng_ops; +static const struct objd_ops lttng_session_ops; +static const struct objd_ops lttng_channel_ops; +static const struct objd_ops lttng_metadata_ops; +static const struct objd_ops lttng_event_ops; + +enum channel_type { + PER_CPU_CHANNEL, + METADATA_CHANNEL, +}; + +static +int lttng_abi_create_session(void) +{ + struct ltt_session *session; + int session_objd, ret; + + session = ltt_session_create(); + if (!session) + return -ENOMEM; + session_objd = objd_alloc(session, <tng_session_ops); + if (session_objd < 0) { + ret = session_objd; + goto objd_error; + } + session->objd = session_objd; + return session_objd; + +objd_error: + ltt_session_destroy(session); + return ret; +} + +#if 0 +static +int lttng_abi_tracepoint_list(void) +{ + int list_objd, ret; + + /* TODO: Create list private data */ + list_objd = objd_alloc(NULL, <tng_tracepoint_list_ops); + if (list_objd < 0) { + ret = list_objd; + goto objd_error; + } + + return list_objd; + +objd_error: + return ret; +} +#endif //0 + +static +long lttng_abi_tracer_version(int objd, + struct lttng_ust_tracer_version *v) +{ + v->version = LTTNG_UST_VERSION; + v->patchlevel = LTTNG_UST_PATCHLEVEL; + v->sublevel = LTTNG_UST_SUBLEVEL; + return 0; +} + +static +long lttng_abi_add_context(int objd, + struct lttng_ust_context *context_param, + struct lttng_ctx **ctx, struct ltt_session *session) +{ + if (session->been_active) + return -EPERM; + + switch (context_param->ctx) { + case LTTNG_UST_CONTEXT_VTID: + return lttng_add_vtid_to_ctx(ctx); + default: + return -EINVAL; + } +} + +/** + * lttng_cmd - lttng control through socket commands + * + * @objd: the object descriptor + * @cmd: the command + * @arg: command arg + * + * This descriptor implements lttng commands: + * LTTNG_UST_SESSION + * Returns a LTTng trace session object descriptor + * LTTNG_UST_TRACER_VERSION + * Returns the LTTng kernel tracer version + * LTTNG_UST_TRACEPOINT_LIST + * Returns a file descriptor listing available tracepoints + * LTTNG_UST_WAIT_QUIESCENT + * Returns after all previously running probes have completed + * + * The returned session will be deleted when its file descriptor is closed. + */ +static +long lttng_cmd(int objd, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case LTTNG_UST_SESSION: + return lttng_abi_create_session(); + case LTTNG_UST_TRACER_VERSION: + return lttng_abi_tracer_version(objd, + (struct lttng_ust_tracer_version *) arg); + case LTTNG_UST_TRACEPOINT_LIST: + return -ENOSYS; //TODO + //return lttng_abi_tracepoint_list(); + case LTTNG_UST_WAIT_QUIESCENT: + synchronize_trace(); + return 0; + default: + return -EINVAL; + } +} + +static const struct objd_ops lttng_ops = { + .cmd = lttng_cmd, +}; + +/* + * We tolerate no failure in this function (if one happens, we print a dmesg + * error, but cannot return any error, because the channel information is + * invariant. + */ +static +void lttng_metadata_create_events(int channel_objd) +{ + struct ltt_channel *channel = objd_private(channel_objd); + static struct lttng_ust_event metadata_params = { + .instrumentation = LTTNG_UST_TRACEPOINT, + .name = "lttng_metadata", + }; + struct ltt_event *event; + int ret; + + /* + * We tolerate no failure path after event creation. It will stay + * invariant for the rest of the session. + */ + event = ltt_event_create(channel, &metadata_params, NULL); + if (!event) { + ret = -EINVAL; + goto create_error; + } + return; + +create_error: + WARN_ON(1); + return; /* not allowed to return error */ +} + +static +int lttng_abi_create_channel(int session_objd, + struct lttng_ust_channel *chan_param, + enum channel_type channel_type) +{ + struct ltt_session *session = objd_private(session_objd); + const struct objd_ops *ops; + const char *transport_name; + struct ltt_channel *chan; + int chan_objd; + int ret = 0; + + chan_objd = objd_alloc(NULL, <tng_channel_ops); + if (chan_objd < 0) { + ret = chan_objd; + goto objd_error; + } + switch (channel_type) { + case PER_CPU_CHANNEL: + if (chan_param->output == LTTNG_UST_MMAP) { + transport_name = chan_param->overwrite ? + "relay-overwrite-mmap" : "relay-discard-mmap"; + } else { + return -EINVAL; + } + ops = <tng_channel_ops; + break; + case METADATA_CHANNEL: + if (chan_param->output == LTTNG_UST_MMAP) + transport_name = "relay-metadata-mmap"; + else + return -EINVAL; + ops = <tng_metadata_ops; + break; + default: + transport_name = ""; + break; + } + /* + * We tolerate no failure path after channel creation. It will stay + * invariant for the rest of the session. + */ + chan = ltt_channel_create(session, transport_name, NULL, + chan_param->subbuf_size, + chan_param->num_subbuf, + chan_param->switch_timer_interval, + chan_param->read_timer_interval); + if (!chan) { + ret = -EINVAL; + goto chan_error; + } + objd_set_private(chan_objd, chan); + chan->objd = chan_objd; + if (channel_type == METADATA_CHANNEL) { + session->metadata = chan; + lttng_metadata_create_events(chan_objd); + } + + /* The channel created holds a reference on the session */ + objd_ref(session_objd); + + return chan_objd; + +chan_error: + objd_unref(chan_objd); +objd_error: + return ret; +} + +/** + * lttng_session_cmd - lttng session object command + * + * @obj: the object + * @cmd: the command + * @arg: command arg + * + * This descriptor implements lttng commands: + * LTTNG_UST_CHANNEL + * Returns a LTTng channel object descriptor + * LTTNG_UST_ENABLE + * Enables tracing for a session (weak enable) + * LTTNG_UST_DISABLE + * Disables tracing for a session (strong disable) + * LTTNG_UST_METADATA + * Returns a LTTng metadata object descriptor + * + * The returned channel will be deleted when its file descriptor is closed. + */ +static +long lttng_session_cmd(int objd, unsigned int cmd, unsigned long arg) +{ + struct ltt_session *session = objd_private(objd); + + switch (cmd) { + case LTTNG_UST_CHANNEL: + return lttng_abi_create_channel(objd, + (struct lttng_ust_channel *) arg, + PER_CPU_CHANNEL); + case LTTNG_UST_SESSION_START: + case LTTNG_UST_ENABLE: + return ltt_session_enable(session); + case LTTNG_UST_SESSION_STOP: + case LTTNG_UST_DISABLE: + return ltt_session_disable(session); + case LTTNG_UST_METADATA: + return lttng_abi_create_channel(objd, + (struct lttng_ust_channel *) arg, + METADATA_CHANNEL); + default: + return -EINVAL; + } +} + +/* + * Called when the last file reference is dropped. + * + * Big fat note: channels and events are invariant for the whole session after + * their creation. So this session destruction also destroys all channel and + * event structures specific to this session (they are not destroyed when their + * individual file is released). + */ +static +int lttng_session_release(int objd) +{ + struct ltt_session *session = objd_private(objd); + + if (session) + ltt_session_destroy(session); + return 0; +} + +static const struct objd_ops lttng_session_ops = { + .release = lttng_session_release, + .cmd = lttng_session_cmd, +}; + +#if 0 +static +int lttng_abi_open_stream(int channel_objd) +{ + struct ltt_channel *channel = objd_private(channel_objd); + struct lib_ring_buffer *buf; + int stream_objd, ret; + + buf = channel->ops->buffer_read_open(channel->chan); + if (!buf) + return -ENOENT; + + stream_objd = objd_alloc(buf, &lib_ring_buffer_objd_ops); + if (stream_objd < 0) { + ret = stream_objd; + goto objd_error; + } + /* + * The stream holds a reference to the channel within the generic ring + * buffer library, so no need to hold a refcount on the channel and + * session files here. + */ + return stream_objd; + +objd_error: + channel->ops->buffer_read_close(buf); + return ret; +} +#endif //0 + +static +int lttng_abi_create_event(int channel_objd, + struct lttng_ust_event *event_param) +{ + struct ltt_channel *channel = objd_private(channel_objd); + struct ltt_event *event; + int event_objd, ret; + + event_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + event_objd = objd_alloc(NULL, <tng_event_ops); + if (event_objd < 0) { + ret = event_objd; + goto objd_error; + } + /* + * We tolerate no failure path after event creation. It will stay + * invariant for the rest of the session. + */ + event = ltt_event_create(channel, event_param, NULL); + if (!event) { + ret = -EINVAL; + goto event_error; + } + objd_set_private(event_objd, event); + /* The event holds a reference on the channel */ + objd_ref(channel_objd); + return event_objd; + +event_error: + objd_unref(event_objd); +objd_error: + return ret; +} + +/** + * lttng_channel_cmd - lttng control through object descriptors + * + * @objd: the object descriptor + * @cmd: the command + * @arg: command arg + * + * This object descriptor implements lttng commands: + * LTTNG_UST_STREAM + * Returns an event stream object descriptor or failure. + * (typically, one event stream records events from one CPU) + * LTTNG_UST_EVENT + * Returns an event object descriptor or failure. + * LTTNG_UST_CONTEXT + * Prepend a context field to each event in the channel + * LTTNG_UST_ENABLE + * Enable recording for events in this channel (weak enable) + * LTTNG_UST_DISABLE + * Disable recording for events in this channel (strong disable) + * + * Channel and event file descriptors also hold a reference on the session. + */ +static +long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg) +{ + struct ltt_channel *channel = objd_private(objd); + + switch (cmd) { + case LTTNG_UST_STREAM: + return -ENOSYS; //TODO + //return lttng_abi_open_stream(objd); + case LTTNG_UST_EVENT: + return lttng_abi_create_event(objd, (struct lttng_ust_event *) arg); + case LTTNG_UST_CONTEXT: + return lttng_abi_add_context(objd, + (struct lttng_ust_context *) arg, + &channel->ctx, channel->session); + case LTTNG_UST_ENABLE: + return ltt_channel_enable(channel); + case LTTNG_UST_DISABLE: + return ltt_channel_disable(channel); + default: + return -EINVAL; + } +} + +/** + * lttng_metadata_cmd - lttng control through object descriptors + * + * @objd: the object descriptor + * @cmd: the command + * @arg: command arg + * + * This object descriptor implements lttng commands: + * LTTNG_UST_STREAM + * Returns an event stream file descriptor or failure. + * + * Channel and event file descriptors also hold a reference on the session. + */ +static +long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case LTTNG_UST_STREAM: + return -ENOSYS; //TODO + //return lttng_abi_open_stream(objd); + default: + return -EINVAL; + } +} + +#if 0 +/** + * lttng_channel_poll - lttng stream addition/removal monitoring + * + * @file: the file + * @wait: poll table + */ +unsigned int lttng_channel_poll(struct file *file, poll_table *wait) +{ + struct ltt_channel *channel = file->private_data; + unsigned int mask = 0; + + if (file->f_mode & FMODE_READ) { + poll_wait_set_exclusive(wait); + poll_wait(file, channel->ops->get_hp_wait_queue(channel->chan), + wait); + + if (channel->ops->is_disabled(channel->chan)) + return POLLERR; + if (channel->ops->is_finalized(channel->chan)) + return POLLHUP; + if (channel->ops->buffer_has_read_closed_stream(channel->chan)) + return POLLIN | POLLRDNORM; + return 0; + } + return mask; + +} +#endif //0 + +static +int lttng_channel_release(int objd) +{ + struct ltt_channel *channel = objd_private(objd); + + if (channel) + objd_unref(channel->session->objd); + return 0; +} + +static const struct objd_ops lttng_channel_ops = { + .release = lttng_channel_release, + //.poll = lttng_channel_poll, + .cmd = lttng_channel_cmd, +}; + +static const struct objd_ops lttng_metadata_ops = { + .release = lttng_channel_release, + .cmd = lttng_metadata_cmd, +}; + +/** + * lttng_event_cmd - lttng control through object descriptors + * + * @objd: the object descriptor + * @cmd: the command + * @arg: command arg + * + * This object descriptor implements lttng commands: + * LTTNG_UST_CONTEXT + * Prepend a context field to each record of this event + * LTTNG_UST_ENABLE + * Enable recording for this event (weak enable) + * LTTNG_UST_DISABLE + * Disable recording for this event (strong disable) + */ +static +long lttng_event_cmd(int objd, unsigned int cmd, unsigned long arg) +{ + struct ltt_event *event = objd_private(objd); + + switch (cmd) { + case LTTNG_UST_CONTEXT: + return lttng_abi_add_context(objd, + (struct lttng_ust_context *) arg, + &event->ctx, event->chan->session); + case LTTNG_UST_ENABLE: + return ltt_event_enable(event); + case LTTNG_UST_DISABLE: + return ltt_event_disable(event); + default: + return -EINVAL; + } +} + +static +int lttng_event_release(int objd) +{ + struct ltt_event *event = objd_private(objd); + + if (event) + objd_unref(event->chan->objd); + return 0; +} + +/* TODO: filter control ioctl */ +static const struct objd_ops lttng_event_ops = { + .release = lttng_event_release, + .cmd = lttng_event_cmd, +}; + +void __attribute__((constructor)) lttng_ust_abi_init(void) +{ + /* TODO: initialize socket */ +} + +static +void __attribute__((destructor)) lttng_ust_abi_exit(void) +{ + /* TODO: teardown socket */ + objd_table_destroy(); +} -- 2.34.1