From: Mathieu Desnoyers Date: Thu, 3 Nov 2011 16:35:30 +0000 (-0400) Subject: library mass rename: add lttng- prefix X-Git-Tag: v1.9.1~143 X-Git-Url: https://git.liburcu.org/?a=commitdiff_plain;h=69400ac4a4e6575f749c6326df7c2a2c8ac3bdc5;p=lttng-ust.git library mass rename: add lttng- prefix Signed-off-by: Mathieu Desnoyers --- diff --git a/Makefile.am b/Makefile.am index b9cc1e7d..f966498b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,14 @@ ACLOCAL_AMFLAGS = -I config -SUBDIRS = . snprintf liblttng-ust-comm libringbuffer libust libustctl \ - include doc libustjava libustfork tests +SUBDIRS = . include doc snprintf libringbuffer liblttng-ust-comm \ + liblttng-ust \ + liblttng-ust-ctl \ + liblttng-ust-fork \ + liblttng-ust-java \ + tests #temporarily disabled -# . libustinstr-malloc +# liblttng-ust-malloc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = ust.pc diff --git a/configure.ac b/configure.ac index be93880c..88a31e9c 100644 --- a/configure.ac +++ b/configure.ac @@ -189,14 +189,19 @@ AM_CONDITIONAL(BUILD_JNI_INTERFACE, test "$with_jni_interface" = "yes") AC_CONFIG_FILES([ Makefile + include/Makefile + include/lttng/version.h doc/Makefile doc/man/Makefile doc/info/Makefile - include/Makefile - liblttng-ust-comm/Makefile + snprintf/Makefile libringbuffer/Makefile - libust/Makefile - libustctl/Makefile + liblttng-ust-comm/Makefile + liblttng-ust/Makefile + liblttng-ust-ctl/Makefile + liblttng-ust-fork/Makefile + liblttng-ust-java/Makefile + liblttng-ust-malloc/Makefile tests/Makefile tests/hello/Makefile tests/ust-basic-tracing/Makefile @@ -217,11 +222,6 @@ AC_CONFIG_FILES([ tests/register_test/Makefile tests/libustctl_function_tests/Makefile tests/exit-fast/Makefile - libustinstr-malloc/Makefile - libustfork/Makefile - snprintf/Makefile ust.pc - include/lttng/version.h - libustjava/Makefile ]) AC_OUTPUT diff --git a/include/lttng/ust-comm.h b/include/lttng/ust-comm.h index 5fa417ee..e2a46617 100644 --- a/include/lttng/ust-comm.h +++ b/include/lttng/ust-comm.h @@ -33,7 +33,7 @@ /* * Default timeout the application waits for the sessiond to send its * "register done" command. Can be overridden with the environment - * variable "UST_REGISTER_TIMEOUT". Note that if the sessiond is not + * variable "LTTNG_UST_REGISTER_TIMEOUT". Note that if the sessiond is not * found, the application proceeds directly without any delay. */ #define LTTNG_UST_DEFAULT_CONSTRUCTOR_TIMEOUT_MS 3000 diff --git a/include/lttng/usterr-signal-safe.h b/include/lttng/usterr-signal-safe.h index 894149a3..b8e03dbd 100644 --- a/include/lttng/usterr-signal-safe.h +++ b/include/lttng/usterr-signal-safe.h @@ -102,7 +102,7 @@ static inline void __attribute__ ((format (printf, 1, 2))) fflush(stderr); \ } while(0) -#ifdef UST_DEBUG +#ifdef LTTNG_UST_DEBUG # define DBG(fmt, args...) ERRMSG(fmt, ## args) # define DBG_raw(fmt, args...) \ do { \ diff --git a/include/usterr.h b/include/usterr.h index 820d4f03..fd5c80ae 100644 --- a/include/usterr.h +++ b/include/usterr.h @@ -63,7 +63,7 @@ static inline int ust_debug(void) __func__); \ } while(0) -#ifdef UST_DEBUG +#ifdef LTTNG_UST_DEBUG # define DBG(fmt, args...) ERRMSG(fmt, ## args) # define DBG_raw(fmt, args...) \ do { \ diff --git a/liblttng-ust-ctl/Makefile.am b/liblttng-ust-ctl/Makefile.am new file mode 100644 index 00000000..69d747df --- /dev/null +++ b/liblttng-ust-ctl/Makefile.am @@ -0,0 +1,11 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/liblttng-ust-comm +AM_CFLAGS = -fno-strict-aliasing + +lib_LTLIBRARIES = liblttng-ust-ctl.la + +liblttng_ust_ctl_la_SOURCES = ustctl.c + +liblttng_ust_ctl_la_LIBADD = \ + $(top_builddir)/liblttng-ust-comm/liblttng-ust-comm.la \ + $(top_builddir)/libringbuffer/libringbuffer.la \ + $(top_builddir)/snprintf/libustsnprintf.la diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c new file mode 100644 index 00000000..6f3d1ed9 --- /dev/null +++ b/liblttng-ust-ctl/ustctl.c @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2011 - Julien Desfossez + * Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; only version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include "../libringbuffer/backend.h" +#include "../libringbuffer/frontend.h" + +volatile enum ust_loglevel ust_loglevel; + +static +void init_object(struct lttng_ust_object_data *data) +{ + data->handle = -1; + data->shm_fd = -1; + data->wait_fd = -1; + data->memory_map_size = 0; +} + +void release_object(int sock, struct lttng_ust_object_data *data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + if (data->shm_fd >= 0) + close(data->shm_fd); + if (data->wait_fd >= 0) + close(data->wait_fd); + memset(&lum, 0, sizeof(lum)); + lum.handle = data->handle; + lum.cmd = LTTNG_UST_RELEASE; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + assert(!ret); + free(data); +} + +/* + * Send registration done packet to the application. + */ +int ustctl_register_done(int sock) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + DBG("Sending register done command to %d", sock); + memset(&lum, 0, sizeof(lum)); + lum.handle = LTTNG_UST_ROOT_HANDLE; + lum.cmd = LTTNG_UST_REGISTER_DONE; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + if (lur.ret_code != USTCOMM_OK) { + DBG("Return code: %s", ustcomm_get_readable_code(lur.ret_code)); + goto error; + } + return 0; + +error: + return -1; +} + +/* + * returns session handle. + */ +int ustctl_create_session(int sock) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret, session_handle; + + /* Create session */ + memset(&lum, 0, sizeof(lum)); + lum.handle = LTTNG_UST_ROOT_HANDLE; + lum.cmd = LTTNG_UST_SESSION; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + session_handle = lur.ret_val; + DBG("received session handle %u", session_handle); + return session_handle; +} + +/* open the metadata global channel */ +int ustctl_open_metadata(int sock, int session_handle, + struct lttng_ust_channel_attr *chops, + struct lttng_ust_object_data **_metadata_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + struct lttng_ust_object_data *metadata_data; + int ret; + + metadata_data = malloc(sizeof(*metadata_data)); + if (!metadata_data) + return -ENOMEM; + init_object(metadata_data); + /* Create metadata channel */ + memset(&lum, 0, sizeof(lum)); + lum.handle = session_handle; + lum.cmd = LTTNG_UST_METADATA; + lum.u.channel.overwrite = chops->overwrite; + lum.u.channel.subbuf_size = chops->subbuf_size; + lum.u.channel.num_subbuf = chops->num_subbuf; + lum.u.channel.switch_timer_interval = chops->switch_timer_interval; + lum.u.channel.read_timer_interval = chops->read_timer_interval; + lum.u.channel.output = chops->output; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) { + free(metadata_data); + return ret; + } + if (lur.ret_code != USTCOMM_OK) { + free(metadata_data); + return lur.ret_code; + } + metadata_data->handle = lur.ret_val; + DBG("received metadata handle %u", metadata_data->handle); + metadata_data->memory_map_size = lur.u.channel.memory_map_size; + /* get shm fd */ + ret = ustcomm_recv_fd(sock); + if (ret < 0) + goto error; + metadata_data->shm_fd = ret; + /* get wait fd */ + ret = ustcomm_recv_fd(sock); + if (ret < 0) + goto error; + metadata_data->wait_fd = ret; + *_metadata_data = metadata_data; + return 0; + +error: + release_object(sock, metadata_data); + return -EINVAL; +} + +int ustctl_create_channel(int sock, int session_handle, + struct lttng_ust_channel_attr *chops, + struct lttng_ust_object_data **_channel_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + struct lttng_ust_object_data *channel_data; + int ret; + + channel_data = malloc(sizeof(*channel_data)); + if (!channel_data) + return -ENOMEM; + init_object(channel_data); + /* Create metadata channel */ + memset(&lum, 0, sizeof(lum)); + lum.handle = session_handle; + lum.cmd = LTTNG_UST_CHANNEL; + lum.u.channel.overwrite = chops->overwrite; + lum.u.channel.subbuf_size = chops->subbuf_size; + lum.u.channel.num_subbuf = chops->num_subbuf; + lum.u.channel.switch_timer_interval = chops->switch_timer_interval; + lum.u.channel.read_timer_interval = chops->read_timer_interval; + lum.u.channel.output = chops->output; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) { + free(channel_data); + return ret; + } + if (lur.ret_code != USTCOMM_OK) { + free(channel_data); + return lur.ret_code; + } + channel_data->handle = lur.ret_val; + DBG("received channel handle %u", channel_data->handle); + channel_data->memory_map_size = lur.u.channel.memory_map_size; + /* get shm fd */ + ret = ustcomm_recv_fd(sock); + if (ret < 0) + goto error; + channel_data->shm_fd = ret; + /* get wait fd */ + ret = ustcomm_recv_fd(sock); + if (ret < 0) + goto error; + channel_data->wait_fd = ret; + *_channel_data = channel_data; + return 0; + +error: + release_object(sock, channel_data); + return -EINVAL; +} + +/* + * Return -ENOENT if no more stream is available for creation. + * Return 0 on success. + * Return negative error value on error. + */ +int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, + struct lttng_ust_object_data **_stream_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + struct lttng_ust_object_data *stream_data; + int ret, fd; + + stream_data = malloc(sizeof(*stream_data)); + if (!stream_data) + return -ENOMEM; + init_object(stream_data); + memset(&lum, 0, sizeof(lum)); + lum.handle = channel_data->handle; + lum.cmd = LTTNG_UST_STREAM; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) { + free(stream_data); + return ret; + } + if (lur.ret_code != USTCOMM_OK) { + free(stream_data); + return lur.ret_code; + } + + stream_data->handle = lur.ret_val; + DBG("received stream handle %u", stream_data->handle); + stream_data->memory_map_size = lur.u.stream.memory_map_size; + /* get shm fd */ + fd = ustcomm_recv_fd(sock); + if (fd < 0) + goto error; + stream_data->shm_fd = fd; + /* get wait fd */ + fd = ustcomm_recv_fd(sock); + if (fd < 0) + goto error; + stream_data->wait_fd = fd; + *_stream_data = stream_data; + return ret; + +error: + release_object(sock, stream_data); + return -EINVAL; +} + +int ustctl_create_event(int sock, struct lttng_ust_event *ev, + struct lttng_ust_object_data *channel_data, + struct lttng_ust_object_data **_event_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + struct lttng_ust_object_data *event_data; + int ret; + + event_data = malloc(sizeof(*event_data)); + if (!event_data) + return -ENOMEM; + init_object(event_data); + memset(&lum, 0, sizeof(lum)); + lum.handle = channel_data->handle; + lum.cmd = LTTNG_UST_EVENT; + strncpy(lum.u.event.name, ev->name, + LTTNG_UST_SYM_NAME_LEN); + lum.u.event.instrumentation = ev->instrumentation; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) { + free(event_data); + return ret; + } + event_data->handle = lur.ret_val; + DBG("received event handle %u", event_data->handle); + *_event_data = event_data; + return 0; +} + +int ustctl_add_context(int sock, struct lttng_ust_context *ctx, + struct lttng_ust_object_data *obj_data, + struct lttng_ust_object_data **_context_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + struct lttng_ust_object_data *context_data; + int ret; + + context_data = malloc(sizeof(*context_data)); + if (!context_data) + return -ENOMEM; + init_object(context_data); + memset(&lum, 0, sizeof(lum)); + lum.handle = obj_data->handle; + lum.cmd = LTTNG_UST_CONTEXT; + lum.u.context.ctx = ctx->ctx; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) { + free(context_data); + return ret; + } + context_data->handle = lur.ret_val; + DBG("received context handle %u", context_data->handle); + *_context_data = context_data; + return ret; +} + +/* Enable event, channel and session ioctl */ +int ustctl_enable(int sock, struct lttng_ust_object_data *object) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + memset(&lum, 0, sizeof(lum)); + lum.handle = object->handle; + lum.cmd = LTTNG_UST_ENABLE; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + DBG("enabled handle %u", object->handle); + return 0; +} + +/* Disable event, channel and session ioctl */ +int ustctl_disable(int sock, struct lttng_ust_object_data *object) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + memset(&lum, 0, sizeof(lum)); + lum.handle = object->handle; + lum.cmd = LTTNG_UST_DISABLE; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + DBG("disable handle %u", object->handle); + return 0; +} + +int ustctl_start_session(int sock, int handle) +{ + struct lttng_ust_object_data obj; + + obj.handle = handle; + return ustctl_enable(sock, &obj); +} + +int ustctl_stop_session(int sock, int handle) +{ + struct lttng_ust_object_data obj; + + obj.handle = handle; + return ustctl_disable(sock, &obj); +} + + +int ustctl_tracepoint_list(int sock) +{ + return -ENOSYS; /* not implemented */ +} + +int ustctl_tracer_version(int sock, struct lttng_ust_tracer_version *v) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + memset(&lum, 0, sizeof(lum)); + lum.handle = LTTNG_UST_ROOT_HANDLE; + lum.cmd = LTTNG_UST_TRACER_VERSION; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + memcpy(v, &lur.u.version, sizeof(*v)); + DBG("received tracer version"); + return 0; +} + +int ustctl_wait_quiescent(int sock) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + memset(&lum, 0, sizeof(lum)); + lum.handle = LTTNG_UST_ROOT_HANDLE; + lum.cmd = LTTNG_UST_WAIT_QUIESCENT; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + DBG("waited for quiescent state"); + return 0; +} + +int ustctl_flush_buffer(int sock, struct lttng_ust_object_data *channel_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + + memset(&lum, 0, sizeof(lum)); + lum.handle = channel_data->handle; + lum.cmd = LTTNG_UST_FLUSH_BUFFER; + return ustcomm_send_app_cmd(sock, &lum, &lur); +} + +int ustctl_calibrate(int sock, struct lttng_ust_calibrate *calibrate) +{ + return -ENOSYS; +} + +/* Buffer operations */ + +/* Map channel shm into process memory */ +struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *chan_data) +{ + struct lttng_ust_shm_handle *handle; + struct channel *chan; + size_t chan_size; + + handle = channel_handle_create(chan_data->shm_fd, + chan_data->wait_fd, + chan_data->memory_map_size); + if (!handle) { + ERR("create handle error"); + return NULL; + } + /* + * Set to -1 because the lttng_ust_shm_handle destruction will take care + * of closing shm_fd and wait_fd. + */ + chan_data->shm_fd = -1; + chan_data->wait_fd = -1; + + /* + * TODO: add consistency checks to be resilient if the + * application try to feed us with incoherent channel structure + * values. + */ + chan = shmp(handle, handle->chan); + /* chan is object 0. This is hardcoded. */ + chan_size = handle->table->objects[0].allocated_len; + handle->shadow_chan = malloc(chan_size); + if (!handle->shadow_chan) { + channel_destroy(chan, handle, 1); + return NULL; + } + memcpy(handle->shadow_chan, chan, chan_size); + return handle; +} + +/* Add stream to channel shm and map its shm into process memory */ +int ustctl_add_stream(struct lttng_ust_shm_handle *handle, + struct lttng_ust_object_data *stream_data) +{ + int ret; + + if (!stream_data->handle) + return -ENOENT; + /* map stream */ + ret = channel_handle_add_stream(handle, + stream_data->shm_fd, + stream_data->wait_fd, + stream_data->memory_map_size); + if (ret) { + ERR("add stream error\n"); + return ret; + } + /* + * Set to -1 because the lttng_ust_shm_handle destruction will take care + * of closing shm_fd and wait_fd. + */ + stream_data->shm_fd = -1; + stream_data->wait_fd = -1; + return 0; +} + +void ustctl_unmap_channel(struct lttng_ust_shm_handle *handle) +{ + struct channel *chan; + + chan = shmp(handle, handle->chan); + channel_destroy(chan, handle, 1); +} + +struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_handle *handle, + int cpu) +{ + struct channel *chan = handle->shadow_chan; + int shm_fd, wait_fd; + uint64_t memory_map_size; + struct lttng_ust_lib_ring_buffer *buf; + int ret; + + buf = channel_get_ring_buffer(&chan->backend.config, + chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); + if (!buf) + return NULL; + ret = lib_ring_buffer_open_read(buf, handle, 1); + if (ret) + return NULL; + return buf; +} + +void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf) +{ + lib_ring_buffer_release_read(buf, handle, 1); +} + +/* For mmap mode, readable without "get" operation */ + +void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf) +{ + return shmp(handle, buf->backend.memory_map); +} + +/* returns the length to mmap. */ +int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf, + unsigned long *len) +{ + unsigned long mmap_buf_len; + struct channel *chan = handle->shadow_chan; + + if (chan->backend.config.output != RING_BUFFER_MMAP) + return -EINVAL; + mmap_buf_len = chan->backend.buf_size; + if (chan->backend.extra_reader_sb) + mmap_buf_len += chan->backend.subbuf_size; + if (mmap_buf_len > INT_MAX) + return -EFBIG; + *len = mmap_buf_len; + return 0; +} + +/* returns the maximum size for sub-buffers. */ +int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf, + unsigned long *len) +{ + struct channel *chan = handle->shadow_chan; + + *len = chan->backend.subbuf_size; + return 0; +} + +/* + * For mmap mode, operate on the current packet (between get/put or + * get_next/put_next). + */ + +/* returns the offset of the subbuffer belonging to the mmap reader. */ +int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf, unsigned long *off) +{ + struct channel *chan = handle->shadow_chan; + unsigned long sb_bindex; + + if (chan->backend.config.output != RING_BUFFER_MMAP) + return -EINVAL; + sb_bindex = subbuffer_id_get_index(&chan->backend.config, + buf->backend.buf_rsb.id); + *off = shmp(handle, shmp_index(handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; + return 0; +} + +/* returns the size of the current sub-buffer, without padding (for mmap). */ +int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) +{ + struct channel *chan = handle->shadow_chan; + + *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, + handle); + return 0; +} + +/* returns the size of the current sub-buffer, without padding (for mmap). */ +int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) +{ + struct channel *chan = handle->shadow_chan; + + *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, + handle); + *len = PAGE_ALIGN(*len); + return 0; +} + +/* Get exclusive read access to the next sub-buffer that can be read. */ +int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf) +{ + return lib_ring_buffer_get_next_subbuf(buf, handle); +} + + +/* Release exclusive sub-buffer access, move consumer forward. */ +int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf) +{ + lib_ring_buffer_put_next_subbuf(buf, handle); + return 0; +} + +/* snapshot */ + +/* Get a snapshot of the current ring buffer producer and consumer positions */ +int ustctl_snapshot(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf) +{ + return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot, + &buf->prod_snapshot, handle); +} + +/* Get the consumer position (iteration start) */ +int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) +{ + *pos = buf->cons_snapshot; + return 0; +} + +/* Get the producer position (iteration end) */ +int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) +{ + *pos = buf->prod_snapshot; + return 0; +} + +/* Get exclusive read access to the specified sub-buffer position */ +int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) +{ + return lib_ring_buffer_get_subbuf(buf, *pos, handle); +} + +/* Release exclusive sub-buffer access */ +int ustctl_put_subbuf(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf) +{ + lib_ring_buffer_put_subbuf(buf, handle); + return 0; +} + +int ustctl_buffer_flush(struct lttng_ust_shm_handle *handle, + struct lttng_ust_lib_ring_buffer *buf) +{ + lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE, handle); + return 0; +} diff --git a/liblttng-ust-fork/Makefile.am b/liblttng-ust-fork/Makefile.am new file mode 100644 index 00000000..e0e42a3f --- /dev/null +++ b/liblttng-ust-fork/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = -fno-strict-aliasing + +lib_LTLIBRARIES = liblttng-ust-fork.la +liblttng_ust_fork_la_SOURCES = ustfork.c +liblttng_ust_fork_la_LIBADD = \ + -ldl \ + $(top_builddir)/liblttng-ust/liblttng-ust.la +libustfork_CFLAGS = -DUST_COMPONENT=liblttng-ust-fork -fno-strict-aliasing diff --git a/liblttng-ust-fork/ustfork.c b/liblttng-ust-fork/ustfork.c new file mode 100644 index 00000000..5e6acba1 --- /dev/null +++ b/liblttng-ust-fork/ustfork.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2009 Pierre-Marc Fournier + * Copyright (C) 2011 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 of + * the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "usterr.h" + +#include + +struct user_desc; + +pid_t fork(void) +{ + static pid_t (*plibc_func)(void) = NULL; + ust_fork_info_t fork_info; + pid_t retval; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "fork"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"fork\" symbol\n"); + return -1; + } + } + + ust_before_fork(&fork_info); + /* Do the real fork */ + retval = plibc_func(); + if (retval == 0) { + /* child */ + ust_after_fork_child(&fork_info); + } else { + ust_after_fork_parent(&fork_info); + } + return retval; +} + +struct ustfork_clone_info { + int (*fn)(void *); + void *arg; + ust_fork_info_t fork_info; +}; + +static int clone_fn(void *arg) +{ + struct ustfork_clone_info *info = (struct ustfork_clone_info *) arg; + + /* clone is now done and we are in child */ + ust_after_fork_child(&info->fork_info); + return info->fn(info->arg); +} + +int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) +{ + static int (*plibc_func)(int (*fn)(void *), void *child_stack, + int flags, void *arg, pid_t *ptid, + struct user_desc *tls, pid_t *ctid) = NULL; + /* var args */ + pid_t *ptid; + struct user_desc *tls; + pid_t *ctid; + /* end of var args */ + va_list ap; + int retval; + + va_start(ap, arg); + ptid = va_arg(ap, pid_t *); + tls = va_arg(ap, struct user_desc *); + ctid = va_arg(ap, pid_t *); + va_end(ap); + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "clone"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"clone\" symbol.\n"); + return -1; + } + } + + if (flags & CLONE_VM) { + /* + * Creating a thread, no need to intervene, just pass on + * the arguments. + */ + retval = plibc_func(fn, child_stack, flags, arg, ptid, + tls, ctid); + } else { + /* Creating a real process, we need to intervene. */ + struct ustfork_clone_info info = { fn: fn, arg: arg }; + + ust_before_fork(&info.fork_info); + retval = plibc_func(clone_fn, child_stack, flags, &info, + ptid, tls, ctid); + /* The child doesn't get here. */ + ust_after_fork_parent(&info.fork_info); + } + return retval; +} diff --git a/liblttng-ust-java/.gitignore b/liblttng-ust-java/.gitignore new file mode 100644 index 00000000..ab97d041 --- /dev/null +++ b/liblttng-ust-java/.gitignore @@ -0,0 +1,2 @@ +UST.class +UST.h diff --git a/liblttng-ust-java/Makefile.am b/liblttng-ust-java/Makefile.am new file mode 100644 index 00000000..fb25cb7b --- /dev/null +++ b/liblttng-ust-java/Makefile.am @@ -0,0 +1,21 @@ +if BUILD_JNI_INTERFACE + +AM_CPPFLAGS = -I$(top_srcdir)/include + +lib_LTLIBRARIES = liblttng-ust-java.la +liblttng_ust_java_la_SOURCES = UST.c UST.h ust_java.h +dist_noinst_DATA = UST.java +liblttng_ust_java_la_LIBADD = -lc -L$(top_builddir)/liblttng-ust/.libs -llttng-ust + +all: UST.class UST.h + +clean-local: + rm -rf UST.h UST.class + +UST.class: UST.java + javac -d "$(builddir)" "$(srcdir)/UST.java" + +UST.h: UST.class + javah -jni UST + +endif diff --git a/liblttng-ust-java/README b/liblttng-ust-java/README new file mode 100644 index 00000000..37834e69 --- /dev/null +++ b/liblttng-ust-java/README @@ -0,0 +1,12 @@ +This directory contains a simple API for instrumenting java applications. + +Configuration examples to build this library: + +dependency: sun-java6-jdk +./configure --with-java-jdk=/usr/lib/jvm/java-6-sun --with-jni-interface + +dependency: openjdk-6-jdk +./configure --with-java-jdk=/usr/lib/jvm/java-6-openjdk --with-jni-interface + +dependency: gcj-4.4-jdk +./configure --with-java-jdk=/usr/lib/jvm/java-gcj --with-jni-interface diff --git a/liblttng-ust-java/UST.c b/liblttng-ust-java/UST.c new file mode 100644 index 00000000..7ad1c717 --- /dev/null +++ b/liblttng-ust-java/UST.c @@ -0,0 +1,15 @@ +#include + +#define TRACEPOINT_CREATE_PROBES +#include "ust_java.h" + +JNIEXPORT void JNICALL Java_UST_ust_1java_1event (JNIEnv *env, jobject jobj, + jstring ev_name, jstring args) +{ + jboolean iscopy; + const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, + &iscopy); + const char *args_cstr = (*env)->GetStringUTFChars(env, args, &iscopy); + + tracepoint(ust_java_event, ev_name_cstr, args_cstr); +} diff --git a/liblttng-ust-java/UST.java b/liblttng-ust-java/UST.java new file mode 100644 index 00000000..be5f7c73 --- /dev/null +++ b/liblttng-ust-java/UST.java @@ -0,0 +1,9 @@ +import java.util.*; + +class UST { + public static native void ust_java_event(String name, String arg); + static { + System.loadLibrary("ustjava"); + } +} + diff --git a/liblttng-ust-java/ust_java.h b/liblttng-ust-java/ust_java.h new file mode 100644 index 00000000..366b3737 --- /dev/null +++ b/liblttng-ust-java/ust_java.h @@ -0,0 +1,44 @@ +#undef TRACEPOINT_SYSTEM +#define TRACEPOINT_SYSTEM ust_java + +#if !defined(_TRACEPOINT_UST_JAVA_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define _TRACEPOINT_UST_JAVA_H + +/* + * Copyright (C) 2011 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 of + * the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +TRACEPOINT_EVENT(ust_java_event, + TP_PROTO(const char *name, const char *args), + TP_ARGS(name, args), + TP_FIELDS( + ctf_string(name, name) + ctf_string(args, args) + ) +) + +#endif /* _TRACEPOINT_UST_JAVA_H */ + +#undef TRACEPOINT_INCLUDE_PATH +#define TRACEPOINT_INCLUDE_PATH . +#undef TRACEPOINT_INCLUDE_FILE +#define TRACEPOINT_INCLUDE_FILE ust_java + +/* This part must be outside protection */ +#include diff --git a/liblttng-ust-malloc/Makefile.am b/liblttng-ust-malloc/Makefile.am new file mode 100644 index 00000000..eb2ea753 --- /dev/null +++ b/liblttng-ust-malloc/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = -fno-strict-aliasing + +lib_LTLIBRARIES = liblttng-ust-malloc.la +liblttng_ust_malloc_la_SOURCES = mallocwrap.c +liblttng_ust_malloc_la_LIBADD = -ldl + +noinst_SCRIPTS = run +EXTRA_DIST = run diff --git a/liblttng-ust-malloc/README b/liblttng-ust-malloc/README new file mode 100644 index 00000000..c58a7e6a --- /dev/null +++ b/liblttng-ust-malloc/README @@ -0,0 +1,9 @@ +libustinstr-malloc is used for instrumenting calls to malloc(3) in a program, +without need for recompiling it. + +libustinstr-malloc defines a malloc() function that is instrumented with a +marker. It also calls the libc malloc afterwards. When loaded with LD_PRELOAD, +it replaces the libc malloc() function, in effect instrumenting all calls to +malloc(). + +See the "run" script for a usage example. diff --git a/liblttng-ust-malloc/mallocwrap.c b/liblttng-ust-malloc/mallocwrap.c new file mode 100644 index 00000000..6e668569 --- /dev/null +++ b/liblttng-ust-malloc/mallocwrap.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2009 Pierre-Marc Fournier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +void *malloc(size_t size) +{ + static void *(*plibc_malloc)(size_t size) = NULL; + void *retval; + + if (plibc_malloc == NULL) { + plibc_malloc = dlsym(RTLD_NEXT, "malloc"); + if (plibc_malloc == NULL) { + fprintf(stderr, "mallocwrap: unable to find malloc\n"); + return NULL; + } + } + + retval = plibc_malloc(size); + + ust_marker(malloc, "size %d ptr %p", (int)size, retval); + + return retval; +} + +void free(void *ptr) +{ + static void *(*plibc_free)(void *ptr) = NULL; + + if (plibc_free == NULL) { + plibc_free = dlsym(RTLD_NEXT, "free"); + if (plibc_free == NULL) { + fprintf(stderr, "mallocwrap: unable to find free\n"); + return; + } + } + + ust_marker(free, "ptr %p", ptr); + + plibc_free(ptr); +} + +UST_MARKER_LIB diff --git a/liblttng-ust-malloc/run b/liblttng-ust-malloc/run new file mode 100644 index 00000000..ce4fd100 --- /dev/null +++ b/liblttng-ust-malloc/run @@ -0,0 +1,3 @@ +#!/bin/sh + +LD_VERBOSE=1 LD_LIBRARY_PATH=.:../libust/.libs:../../liburcu LD_PRELOAD=liburcu.so:libust.so:.libs/libmallocwrap.so $1 diff --git a/liblttng-ust/Makefile.am b/liblttng-ust/Makefile.am new file mode 100644 index 00000000..19d7482a --- /dev/null +++ b/liblttng-ust/Makefile.am @@ -0,0 +1,38 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = -fno-strict-aliasing + +lib_LTLIBRARIES = liblttng-ust.la + +liblttng_ust_la_SOURCES = \ + tracepoint.c \ + ltt-tracer.h \ + ltt-tracer-core.h \ + ltt-ring-buffer-client.h \ + ltt-ring-buffer-client-discard.c \ + ltt-ring-buffer-client-overwrite.c \ + ltt-ring-buffer-metadata-client.h \ + ltt-ring-buffer-metadata-client.c \ + ltt-events.c \ + ltt-probes.c \ + lttng-ust-abi.c \ + lttng-ust-comm.c \ + ust-core.c \ + probes/lttng-probe-ust.c \ + probes/lttng-probe-ust.h \ + lttng-context-vtid.c \ + lttng-context-vpid.c \ + lttng-context-pthread-id.c \ + lttng-context-procname.c \ + ltt-context.c + +liblttng_ust_la_LDFLAGS = -no-undefined -version-info 0:0:0 + +liblttng_ust_la_LIBADD = \ + -lpthread \ + -lrt \ + -luuid \ + $(top_builddir)/snprintf/libustsnprintf.la \ + $(top_builddir)/libringbuffer/libringbuffer.la \ + $(top_builddir)/liblttng-ust-comm/liblttng-ust-comm.la + +liblttng_ust_la_CFLAGS = -DUST_COMPONENT="liblttng-ust" -fno-strict-aliasing diff --git a/liblttng-ust/ltt-context.c b/liblttng-ust/ltt-context.c new file mode 100644 index 00000000..90747a55 --- /dev/null +++ b/liblttng-ust/ltt-context.c @@ -0,0 +1,88 @@ +/* + * ltt-context.c + * + * Copyright 2011 (c) - Mathieu Desnoyers + * + * LTTng UST trace/channel/event context management. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include +#include + +int lttng_find_context(struct lttng_ctx *ctx, const char *name) +{ + unsigned int i; + + for (i = 0; i < ctx->nr_fields; i++) { + /* Skip allocated (but non-initialized) contexts */ + if (!ctx->fields[i].event_field.name) + continue; + if (!strcmp(ctx->fields[i].event_field.name, name)) + return 1; + } + return 0; +} + +/* + * Note: as we append context information, the pointer location may change. + */ +struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p) +{ + struct lttng_ctx_field *field; + struct lttng_ctx *ctx; + + if (!*ctx_p) { + *ctx_p = zmalloc(sizeof(struct lttng_ctx)); + if (!*ctx_p) + return NULL; + } + ctx = *ctx_p; + if (ctx->nr_fields + 1 > ctx->allocated_fields) { + struct lttng_ctx_field *new_fields; + + ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields); + new_fields = zmalloc(ctx->allocated_fields * sizeof(struct lttng_ctx_field)); + if (!new_fields) + return NULL; + if (ctx->fields) + memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields); + free(ctx->fields); + ctx->fields = new_fields; + } + field = &ctx->fields[ctx->nr_fields]; + ctx->nr_fields++; + return field; +} + +/* + * Remove last context field. + */ +void lttng_remove_context_field(struct lttng_ctx **ctx_p, + struct lttng_ctx_field *field) +{ + struct lttng_ctx *ctx; + + ctx = *ctx_p; + ctx->nr_fields--; + assert(&ctx->fields[ctx->nr_fields] == field); + memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field)); +} + +void lttng_destroy_context(struct lttng_ctx *ctx) +{ + int i; + + if (!ctx) + return; + for (i = 0; i < ctx->nr_fields; i++) { + if (ctx->fields[i].destroy) + ctx->fields[i].destroy(&ctx->fields[i]); + } + free(ctx->fields); + free(ctx); +} diff --git a/liblttng-ust/ltt-events.c b/liblttng-ust/ltt-events.c new file mode 100644 index 00000000..68531bcd --- /dev/null +++ b/liblttng-ust/ltt-events.c @@ -0,0 +1,1010 @@ +/* + * ltt-events.c + * + * Copyright 2010 (c) - Mathieu Desnoyers + * + * Holds LTTng per-session event registry. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lttng/core.h" +#include "ltt-tracer.h" +#include "ltt-tracer-core.h" +#include "lttng/wait.h" +#include "../libringbuffer/shm.h" + +typedef u32 uint32_t; +#include + +/* + * The sessions mutex is the centralized mutex across UST tracing + * control and probe registration. All operations within this file are + * called by the communication thread, under ust_lock protection. + */ +static DEFINE_MUTEX(sessions_mutex); + +void ust_lock(void) +{ + pthread_mutex_lock(&sessions_mutex); +} + +void ust_unlock(void) +{ + pthread_mutex_unlock(&sessions_mutex); +} + +static CDS_LIST_HEAD(sessions); +static CDS_LIST_HEAD(ltt_transport_list); + +/* + * Pending probes hash table, containing the registered ltt events for + * which tracepoint probes are still missing. Protected by the sessions + * mutex. + */ +#define PENDING_PROBE_HASH_BITS 6 +#define PENDING_PROBE_HASH_SIZE (1 << PENDING_PROBE_HASH_BITS) +static struct cds_hlist_head pending_probe_table[PENDING_PROBE_HASH_SIZE]; + +struct ust_pending_probe { + struct ltt_event *event; + struct cds_hlist_node node; + char name[]; +}; + +static void _ltt_event_destroy(struct ltt_event *event); +static void _ltt_channel_destroy(struct ltt_channel *chan); +static int _ltt_event_unregister(struct ltt_event *event); +static +int _ltt_event_metadata_statedump(struct ltt_session *session, + struct ltt_channel *chan, + struct ltt_event *event); +static +int _ltt_session_metadata_statedump(struct ltt_session *session); + +/* + * called at event creation if probe is missing. + * called with session mutex held. + */ +static +int add_pending_probe(struct ltt_event *event, const char *name) +{ + struct cds_hlist_head *head; + struct ust_pending_probe *e; + size_t name_len = strlen(name) + 1; + u32 hash = jhash(name, name_len - 1, 0); + + head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)]; + e = zmalloc(sizeof(struct ust_pending_probe) + name_len); + if (!e) + return -ENOMEM; + memcpy(&e->name[0], name, name_len); + cds_hlist_add_head(&e->node, head); + e->event = event; + event->pending_probe = e; + return 0; +} + +/* + * remove a pending probe. called when at event teardown and when an + * event is fixed (probe is loaded). + * called with session mutex held. + */ +static +void remove_pending_probe(struct ust_pending_probe *e) +{ + if (!e) + return; + cds_hlist_del(&e->node); + free(e); +} + +/* + * Called at library load: connect the probe on the events pending on + * probe load. + * called with session mutex held. + */ +int pending_probe_fix_events(const struct lttng_event_desc *desc) +{ + struct cds_hlist_head *head; + struct cds_hlist_node *node, *p; + struct ust_pending_probe *e; + const char *name = desc->name; + size_t name_len = strlen(name) + 1; + u32 hash = jhash(name, name_len - 1, 0); + int ret = 0; + + head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)]; + cds_hlist_for_each_entry_safe(e, node, p, head, node) { + struct ltt_event *event; + struct ltt_channel *chan; + + if (strcmp(name, e->name)) + continue; + event = e->event; + chan = event->chan; + assert(!event->desc); + event->desc = desc; + event->pending_probe = NULL; + remove_pending_probe(e); + ret |= __tracepoint_probe_register(name, + event->desc->probe_callback, + event); + if (ret) + continue; + event->id = chan->free_event_id++; + ret |= _ltt_event_metadata_statedump(chan->session, chan, + event); + } + return ret; +} + +void synchronize_trace(void) +{ + synchronize_rcu(); +} + +struct ltt_session *ltt_session_create(void) +{ + struct ltt_session *session; + + session = zmalloc(sizeof(struct ltt_session)); + if (!session) + return NULL; + CDS_INIT_LIST_HEAD(&session->chan); + CDS_INIT_LIST_HEAD(&session->events); + uuid_generate(session->uuid); + cds_list_add(&session->list, &sessions); + return session; +} + +void ltt_session_destroy(struct ltt_session *session) +{ + struct ltt_channel *chan, *tmpchan; + struct ltt_event *event, *tmpevent; + int ret; + + CMM_ACCESS_ONCE(session->active) = 0; + cds_list_for_each_entry(event, &session->events, list) { + ret = _ltt_event_unregister(event); + WARN_ON(ret); + } + synchronize_trace(); /* Wait for in-flight events to complete */ + cds_list_for_each_entry_safe(event, tmpevent, &session->events, list) + _ltt_event_destroy(event); + cds_list_for_each_entry_safe(chan, tmpchan, &session->chan, list) + _ltt_channel_destroy(chan); + cds_list_del(&session->list); + free(session); +} + +int ltt_session_enable(struct ltt_session *session) +{ + int ret = 0; + struct ltt_channel *chan; + + if (session->active) { + ret = -EBUSY; + goto end; + } + + /* + * Snapshot the number of events per channel to know the type of header + * we need to use. + */ + cds_list_for_each_entry(chan, &session->chan, list) { + if (chan->header_type) + continue; /* don't change it if session stop/restart */ + if (chan->free_event_id < 31) + chan->header_type = 1; /* compact */ + else + chan->header_type = 2; /* large */ + } + + CMM_ACCESS_ONCE(session->active) = 1; + CMM_ACCESS_ONCE(session->been_active) = 1; + ret = _ltt_session_metadata_statedump(session); + if (ret) + CMM_ACCESS_ONCE(session->active) = 0; +end: + return ret; +} + +int ltt_session_disable(struct ltt_session *session) +{ + int ret = 0; + + if (!session->active) { + ret = -EBUSY; + goto end; + } + CMM_ACCESS_ONCE(session->active) = 0; +end: + return ret; +} + +int ltt_channel_enable(struct ltt_channel *channel) +{ + int old; + + if (channel == channel->session->metadata) + return -EPERM; + old = uatomic_xchg(&channel->enabled, 1); + if (old) + return -EEXIST; + return 0; +} + +int ltt_channel_disable(struct ltt_channel *channel) +{ + int old; + + if (channel == channel->session->metadata) + return -EPERM; + old = uatomic_xchg(&channel->enabled, 0); + if (!old) + return -EEXIST; + return 0; +} + +int ltt_event_enable(struct ltt_event *event) +{ + int old; + + if (event->chan == event->chan->session->metadata) + return -EPERM; + old = uatomic_xchg(&event->enabled, 1); + if (old) + return -EEXIST; + return 0; +} + +int ltt_event_disable(struct ltt_event *event) +{ + int old; + + if (event->chan == event->chan->session->metadata) + return -EPERM; + old = uatomic_xchg(&event->enabled, 0); + if (!old) + return -EEXIST; + return 0; +} + +static struct ltt_transport *ltt_transport_find(const char *name) +{ + struct ltt_transport *transport; + + cds_list_for_each_entry(transport, <t_transport_list, node) { + if (!strcmp(transport->name, name)) + return transport; + } + return NULL; +} + +struct ltt_channel *ltt_channel_create(struct ltt_session *session, + const char *transport_name, + void *buf_addr, + size_t subbuf_size, size_t num_subbuf, + unsigned int switch_timer_interval, + unsigned int read_timer_interval, + int *shm_fd, int *wait_fd, + uint64_t *memory_map_size) +{ + struct ltt_channel *chan; + struct ltt_transport *transport; + + if (session->been_active) + goto active; /* Refuse to add channel to active session */ + transport = ltt_transport_find(transport_name); + if (!transport) { + DBG("LTTng transport %s not found\n", + transport_name); + goto notransport; + } + chan = zmalloc(sizeof(struct ltt_channel)); + if (!chan) + goto nomem; + chan->session = session; + chan->id = session->free_chan_id++; + /* + * Note: the channel creation op already writes into the packet + * headers. Therefore the "chan" information used as input + * should be already accessible. + */ + transport->ops.channel_create("[lttng]", chan, buf_addr, + subbuf_size, num_subbuf, switch_timer_interval, + read_timer_interval, shm_fd, wait_fd, + memory_map_size); + if (!chan->chan) + goto create_error; + chan->enabled = 1; + chan->ops = &transport->ops; + cds_list_add(&chan->list, &session->chan); + return chan; + +create_error: + free(chan); +nomem: +notransport: +active: + return NULL; +} + +/* + * Only used internally at session destruction. + */ +static +void _ltt_channel_destroy(struct ltt_channel *chan) +{ + chan->ops->channel_destroy(chan); + cds_list_del(&chan->list); + lttng_destroy_context(chan->ctx); + free(chan); +} + +/* + * Supports event creation while tracing session is active. + */ +struct ltt_event *ltt_event_create(struct ltt_channel *chan, + struct lttng_ust_event *event_param, + void *filter) +{ + struct ltt_event *event; + int ret; + + if (chan->used_event_id == -1UL) + goto full; + /* + * This is O(n^2) (for each event, the loop is called at event + * creation). Might require a hash if we have lots of events. + */ + cds_list_for_each_entry(event, &chan->session->events, list) + if (event->desc && !strcmp(event->desc->name, event_param->name)) + goto exist; + event = zmalloc(sizeof(struct ltt_event)); + if (!event) + goto cache_error; + event->chan = chan; + event->filter = filter; + /* + * used_event_id counts the maximum number of event IDs that can + * register if all probes register. + */ + chan->used_event_id++; + event->enabled = 1; + event->instrumentation = event_param->instrumentation; + /* Populate ltt_event structure before tracepoint registration. */ + cmm_smp_wmb(); + switch (event_param->instrumentation) { + case LTTNG_UST_TRACEPOINT: + event->desc = ltt_event_get(event_param->name); + if (event->desc) { + ret = __tracepoint_probe_register(event_param->name, + event->desc->probe_callback, + event); + if (ret) + goto register_error; + event->id = chan->free_event_id++; + } else { + /* + * If the probe is not present, event->desc stays NULL, + * waiting for the probe to register, and the event->id + * stays unallocated. + */ + ret = add_pending_probe(event, event_param->name); + if (ret) + goto add_pending_error; + } + break; + default: + WARN_ON_ONCE(1); + } + if (event->desc) { + ret = _ltt_event_metadata_statedump(chan->session, chan, event); + if (ret) + goto statedump_error; + } + cds_list_add(&event->list, &chan->session->events); + return event; + +statedump_error: + if (event->desc) { + WARN_ON_ONCE(__tracepoint_probe_unregister(event_param->name, + event->desc->probe_callback, + event)); + ltt_event_put(event->desc); + } +add_pending_error: +register_error: + free(event); +cache_error: +exist: +full: + return NULL; +} + +/* + * Only used internally at session destruction. + */ +int _ltt_event_unregister(struct ltt_event *event) +{ + int ret = -EINVAL; + + switch (event->instrumentation) { + case LTTNG_UST_TRACEPOINT: + if (event->desc) { + ret = __tracepoint_probe_unregister(event->desc->name, + event->desc->probe_callback, + event); + if (ret) + return ret; + } else { + remove_pending_probe(event->pending_probe); + ret = 0; + } + break; + default: + WARN_ON_ONCE(1); + } + return ret; +} + +/* + * Only used internally at session destruction. + */ +static +void _ltt_event_destroy(struct ltt_event *event) +{ + switch (event->instrumentation) { + case LTTNG_UST_TRACEPOINT: + if (event->desc) { + ltt_event_put(event->desc); + } + break; + default: + WARN_ON_ONCE(1); + } + cds_list_del(&event->list); + lttng_destroy_context(event->ctx); + free(event); +} + +/* + * We have exclusive access to our metadata buffer (protected by the + * ust_lock), so we can do racy operations such as looking for + * remaining space left in packet and write, since mutual exclusion + * protects us from concurrent writes. + */ +int lttng_metadata_printf(struct ltt_session *session, + const char *fmt, ...) +{ + struct lttng_ust_lib_ring_buffer_ctx ctx; + struct ltt_channel *chan = session->metadata; + char *str = NULL; + int ret = 0, waitret; + size_t len, reserve_len, pos; + va_list ap; + + WARN_ON_ONCE(!CMM_ACCESS_ONCE(session->active)); + + va_start(ap, fmt); + ret = vasprintf(&str, fmt, ap); + va_end(ap); + if (ret < 0) + return -ENOMEM; + + len = strlen(str); + pos = 0; + + for (pos = 0; pos < len; pos += reserve_len) { + reserve_len = min_t(size_t, + chan->ops->packet_avail_size(chan->chan, chan->handle), + len - pos); + lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len, + sizeof(char), -1, chan->handle); + /* + * We don't care about metadata buffer's records lost + * count, because we always retry here. Report error if + * we need to bail out after timeout or being + * interrupted. + */ + waitret = wait_cond_interruptible_timeout( + ({ + ret = chan->ops->event_reserve(&ctx, 0); + ret != -ENOBUFS || !ret; + }), + LTTNG_METADATA_TIMEOUT_MSEC); + if (waitret == -ETIMEDOUT || waitret == -EINTR || ret) { + DBG("LTTng: Failure to write metadata to buffers (%s)\n", + waitret == -EINTR ? "interrupted" : + (ret == -ENOBUFS ? "timeout" : "I/O error")); + if (waitret == -EINTR) + ret = waitret; + goto end; + } + chan->ops->event_write(&ctx, &str[pos], reserve_len); + chan->ops->event_commit(&ctx); + } +end: + free(str); + return ret; +} + +static +int _ltt_field_statedump(struct ltt_session *session, + const struct lttng_event_field *field) +{ + int ret = 0; + + switch (field->type.atype) { + case atype_integer: + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s;\n", + field->type.u.basic.integer.size, + field->type.u.basic.integer.alignment, + field->type.u.basic.integer.signedness, + (field->type.u.basic.integer.encoding == lttng_encode_none) + ? "none" + : (field->type.u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + field->type.u.basic.integer.base, +#if (BYTE_ORDER == BIG_ENDIAN) + field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", +#else + field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", +#endif + field->name); + break; + case atype_float: + ret = lttng_metadata_printf(session, + " floating_point { exp_dig = %u; mant_dig = %u; align = %u;%s } _%s;\n", + field->type.u.basic._float.exp_dig, + field->type.u.basic._float.mant_dig, + field->type.u.basic._float.alignment, +#if (BYTE_ORDER == BIG_ENDIAN) + field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", +#else + field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", +#endif + field->name); + break; + case atype_enum: + ret = lttng_metadata_printf(session, + " %s %s;\n", + field->type.u.basic.enumeration.name, + field->name); + break; + case atype_array: + { + const struct lttng_basic_type *elem_type; + + elem_type = &field->type.u.array.elem_type; + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[%u];\n", + elem_type->u.basic.integer.size, + elem_type->u.basic.integer.alignment, + elem_type->u.basic.integer.signedness, + (elem_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + elem_type->u.basic.integer.base, +#if (BYTE_ORDER == BIG_ENDIAN) + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", +#else + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", +#endif + field->name, field->type.u.array.length); + break; + } + case atype_sequence: + { + const struct lttng_basic_type *elem_type; + const struct lttng_basic_type *length_type; + + elem_type = &field->type.u.sequence.elem_type; + length_type = &field->type.u.sequence.length_type; + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n", + length_type->u.basic.integer.size, + (unsigned int) length_type->u.basic.integer.alignment, + length_type->u.basic.integer.signedness, + (length_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : ((length_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII"), + length_type->u.basic.integer.base, +#if (BYTE_ORDER == BIG_ENDIAN) + length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", +#else + length_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", +#endif + field->name); + if (ret) + return ret; + + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[ __%s_length ];\n", + elem_type->u.basic.integer.size, + (unsigned int) elem_type->u.basic.integer.alignment, + elem_type->u.basic.integer.signedness, + (elem_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : ((elem_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII"), + elem_type->u.basic.integer.base, +#if (BYTE_ORDER == BIG_ENDIAN) + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", +#else + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", +#endif + field->name, + field->name); + break; + } + + case atype_string: + /* Default encoding is UTF8 */ + ret = lttng_metadata_printf(session, + " string%s _%s;\n", + field->type.u.basic.string.encoding == lttng_encode_ASCII ? + " { encoding = ASCII; }" : "", + field->name); + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + return ret; +} + +static +int _ltt_context_metadata_statedump(struct ltt_session *session, + struct lttng_ctx *ctx) +{ + int ret = 0; + int i; + + if (!ctx) + return 0; + for (i = 0; i < ctx->nr_fields; i++) { + const struct lttng_ctx_field *field = &ctx->fields[i]; + + ret = _ltt_field_statedump(session, &field->event_field); + if (ret) + return ret; + } + return ret; +} + +static +int _ltt_fields_metadata_statedump(struct ltt_session *session, + struct ltt_event *event) +{ + const struct lttng_event_desc *desc = event->desc; + int ret = 0; + int i; + + for (i = 0; i < desc->nr_fields; i++) { + const struct lttng_event_field *field = &desc->fields[i]; + + ret = _ltt_field_statedump(session, field); + if (ret) + return ret; + } + return ret; +} + +static +int _ltt_event_metadata_statedump(struct ltt_session *session, + struct ltt_channel *chan, + struct ltt_event *event) +{ + int ret = 0; + + if (event->metadata_dumped || !CMM_ACCESS_ONCE(session->active)) + return 0; + if (chan == session->metadata) + return 0; + /* + * Don't print events for which probe load is pending. + */ + if (!event->desc) + return 0; + + ret = lttng_metadata_printf(session, + "event {\n" + " name = %s;\n" + " id = %u;\n" + " stream_id = %u;\n", + event->desc->name, + event->id, + event->chan->id); + if (ret) + goto end; + + if (event->ctx) { + ret = lttng_metadata_printf(session, + " context := struct {\n"); + if (ret) + goto end; + } + ret = _ltt_context_metadata_statedump(session, event->ctx); + if (ret) + goto end; + if (event->ctx) { + ret = lttng_metadata_printf(session, + " };\n"); + if (ret) + goto end; + } + + ret = lttng_metadata_printf(session, + " fields := struct {\n" + ); + if (ret) + goto end; + + ret = _ltt_fields_metadata_statedump(session, event); + if (ret) + goto end; + + /* + * LTTng space reservation can only reserve multiples of the + * byte size. + */ + ret = lttng_metadata_printf(session, + " };\n" + "};\n\n"); + if (ret) + goto end; + + event->metadata_dumped = 1; +end: + return ret; + +} + +static +int _ltt_channel_metadata_statedump(struct ltt_session *session, + struct ltt_channel *chan) +{ + int ret = 0; + + if (chan->metadata_dumped || !CMM_ACCESS_ONCE(session->active)) + return 0; + if (chan == session->metadata) + return 0; + + WARN_ON_ONCE(!chan->header_type); + ret = lttng_metadata_printf(session, + "stream {\n" + " id = %u;\n" + " event.header := %s;\n" + " packet.context := struct packet_context;\n", + chan->id, + chan->header_type == 1 ? "struct event_header_compact" : + "struct event_header_large"); + if (ret) + goto end; + + if (chan->ctx) { + ret = lttng_metadata_printf(session, + " event.context := struct {\n"); + if (ret) + goto end; + } + ret = _ltt_context_metadata_statedump(session, chan->ctx); + if (ret) + goto end; + if (chan->ctx) { + ret = lttng_metadata_printf(session, + " };\n"); + if (ret) + goto end; + } + + ret = lttng_metadata_printf(session, + "};\n\n"); + + chan->metadata_dumped = 1; +end: + return ret; +} + +static +int _ltt_stream_packet_context_declare(struct ltt_session *session) +{ + return lttng_metadata_printf(session, + "struct packet_context {\n" + " uint64_t timestamp_begin;\n" + " uint64_t timestamp_end;\n" + " uint32_t events_discarded;\n" + " uint32_t content_size;\n" + " uint32_t packet_size;\n" + " uint32_t cpu_id;\n" + "};\n\n" + ); +} + +/* + * Compact header: + * id: range: 0 - 30. + * id 31 is reserved to indicate an extended header. + * + * Large header: + * id: range: 0 - 65534. + * id 65535 is reserved to indicate an extended header. + */ +static +int _ltt_event_header_declare(struct ltt_session *session) +{ + return lttng_metadata_printf(session, + "struct event_header_compact {\n" + " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n" + " variant {\n" + " struct {\n" + " uint27_t timestamp;\n" + " } compact;\n" + " struct {\n" + " uint32_t id;\n" + " uint64_t timestamp;\n" + " } extended;\n" + " } v;\n" + "} align(%u);\n" + "\n" + "struct event_header_large {\n" + " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n" + " variant {\n" + " struct {\n" + " uint32_t timestamp;\n" + " } compact;\n" + " struct {\n" + " uint32_t id;\n" + " uint64_t timestamp;\n" + " } extended;\n" + " } v;\n" + "} align(%u);\n\n", + lttng_alignof(uint32_t) * CHAR_BIT, + lttng_alignof(uint16_t) * CHAR_BIT + ); +} + +/* + * Output metadata into this session's metadata buffers. + */ +static +int _ltt_session_metadata_statedump(struct ltt_session *session) +{ + unsigned char *uuid_c = session->uuid; + char uuid_s[37]; + struct ltt_channel *chan; + struct ltt_event *event; + int ret = 0; + + if (!CMM_ACCESS_ONCE(session->active)) + return 0; + if (session->metadata_dumped) + goto skip_session; + if (!session->metadata) { + DBG("LTTng: attempt to start tracing, but metadata channel is not found. Operation abort.\n"); + return -EPERM; + } + + snprintf(uuid_s, sizeof(uuid_s), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3], + uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7], + uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11], + uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]); + + ret = lttng_metadata_printf(session, + "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n" + "typealias integer { size = 16; align = %u; signed = false; } := uint16_t;\n" + "typealias integer { size = 32; align = %u; signed = false; } := uint32_t;\n" + "typealias integer { size = 64; align = %u; signed = false; } := uint64_t;\n" + "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n" + "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n" + "\n" + "trace {\n" + " major = %u;\n" + " minor = %u;\n" + " uuid = \"%s\";\n" + " byte_order = %s;\n" + " packet.header := struct {\n" + " uint32_t magic;\n" + " uint8_t uuid[16];\n" + " uint32_t stream_id;\n" + " };\n" + "};\n\n", + lttng_alignof(uint8_t) * CHAR_BIT, + lttng_alignof(uint16_t) * CHAR_BIT, + lttng_alignof(uint32_t) * CHAR_BIT, + lttng_alignof(uint64_t) * CHAR_BIT, + CTF_VERSION_MAJOR, + CTF_VERSION_MINOR, + uuid_s, +#if (BYTE_ORDER == BIG_ENDIAN) + "be" +#else + "le" +#endif + ); + if (ret) + goto end; + + ret = _ltt_stream_packet_context_declare(session); + if (ret) + goto end; + + ret = _ltt_event_header_declare(session); + if (ret) + goto end; + +skip_session: + cds_list_for_each_entry(chan, &session->chan, list) { + ret = _ltt_channel_metadata_statedump(session, chan); + if (ret) + goto end; + } + + cds_list_for_each_entry(event, &session->events, list) { + ret = _ltt_event_metadata_statedump(session, event->chan, event); + if (ret) + goto end; + } + session->metadata_dumped = 1; +end: + return ret; +} + +/** + * ltt_transport_register - LTT transport registration + * @transport: transport structure + * + * Registers a transport which can be used as output to extract the data out of + * LTTng. Called with ust_lock held. + */ +void ltt_transport_register(struct ltt_transport *transport) +{ + cds_list_add_tail(&transport->node, <t_transport_list); +} + +/** + * ltt_transport_unregister - LTT transport unregistration + * @transport: transport structure + * Called with ust_lock held. + */ +void ltt_transport_unregister(struct ltt_transport *transport) +{ + cds_list_del(&transport->node); +} + +void lttng_ust_events_exit(void) +{ + struct ltt_session *session, *tmpsession; + + cds_list_for_each_entry_safe(session, tmpsession, &sessions, list) + ltt_session_destroy(session); +} diff --git a/liblttng-ust/ltt-probes.c b/liblttng-ust/ltt-probes.c new file mode 100644 index 00000000..66ee971c --- /dev/null +++ b/liblttng-ust/ltt-probes.c @@ -0,0 +1,169 @@ +/* + * ltt-probes.c + * + * Copyright 2010 (c) - Mathieu Desnoyers + * + * Holds LTTng probes registry. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include +#include + +#include "ltt-tracer-core.h" + +/* + * probe list is protected by ust_lock()/ust_unlock(). + */ +static CDS_LIST_HEAD(probe_list); + +static +const struct lttng_event_desc *find_event(const char *name) +{ + struct lttng_probe_desc *probe_desc; + int i; + + cds_list_for_each_entry(probe_desc, &probe_list, head) { + for (i = 0; i < probe_desc->nr_events; i++) { + if (!strcmp(probe_desc->event_desc[i].name, name)) + return &probe_desc->event_desc[i]; + } + } + return NULL; +} + +int ltt_probe_register(struct lttng_probe_desc *desc) +{ + int ret = 0; + int i; + + ust_lock(); + /* + * TODO: This is O(N^2). Turn into a hash table when probe registration + * overhead becomes an issue. + */ + for (i = 0; i < desc->nr_events; i++) { + if (find_event(desc->event_desc[i].name)) { + ret = -EEXIST; + goto end; + } + } + cds_list_add(&desc->head, &probe_list); + + /* + * fix the events awaiting probe load. + */ + for (i = 0; i < desc->nr_events; i++) { + ret = pending_probe_fix_events(&desc->event_desc[i]); + assert(!ret); + } +end: + ust_unlock(); + return ret; +} + +void ltt_probe_unregister(struct lttng_probe_desc *desc) +{ + ust_lock(); + cds_list_del(&desc->head); + ust_unlock(); +} + +/* + * called with UST lock held. + */ +const struct lttng_event_desc *ltt_event_get(const char *name) +{ + const struct lttng_event_desc *event; + + event = find_event(name); + if (!event) + return NULL; + return event; +} + +void ltt_event_put(const struct lttng_event_desc *event) +{ +} + +#if 0 +static +void *tp_list_start(struct seq_file *m, loff_t *pos) +{ + struct lttng_probe_desc *probe_desc; + int iter = 0, i; + + pthread_mutex_lock(&probe_mutex); + cds_list_for_each_entry(probe_desc, &probe_list, head) { + for (i = 0; i < probe_desc->nr_events; i++) { + if (iter++ >= *pos) + return (void *) &probe_desc->event_desc[i]; + } + } + /* End of list */ + return NULL; +} + +static +void *tp_list_next(struct seq_file *m, void *p, loff_t *ppos) +{ + struct lttng_probe_desc *probe_desc; + int iter = 0, i; + + (*ppos)++; + cds_list_for_each_entry(probe_desc, &probe_list, head) { + for (i = 0; i < probe_desc->nr_events; i++) { + if (iter++ >= *ppos) + return (void *) &probe_desc->event_desc[i]; + } + } + /* End of list */ + return NULL; +} + +static +void tp_list_stop(struct seq_file *m, void *p) +{ + pthread_mutex_unlock(&probe_mutex); +} + +static +int tp_list_show(struct seq_file *m, void *p) +{ + const struct lttng_event_desc *probe_desc = p; + + /* + * Don't export lttng internal events (metadata). + */ + if (!strncmp(probe_desc->name, "lttng_", sizeof("lttng_") - 1)) + return 0; + seq_printf(m, "event { name = %s; };\n", + probe_desc->name); + return 0; +} + +static +const struct seq_operations lttng_tracepoint_list_seq_ops = { + .start = tp_list_start, + .next = tp_list_next, + .stop = tp_list_stop, + .show = tp_list_show, +}; + +static +int lttng_tracepoint_list_open(struct inode *inode, struct file *file) +{ + return seq_open(file, <tng_tracepoint_list_seq_ops); +} + +const struct file_operations lttng_tracepoint_list_fops = { + .open = lttng_tracepoint_list_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +#endif //0 diff --git a/liblttng-ust/ltt-ring-buffer-client-discard.c b/liblttng-ust/ltt-ring-buffer-client-discard.c new file mode 100644 index 00000000..e89026c7 --- /dev/null +++ b/liblttng-ust/ltt-ring-buffer-client-discard.c @@ -0,0 +1,19 @@ +/* + * ltt-ring-buffer-client-discard.c + * + * Copyright (C) 2010 - Mathieu Desnoyers + * + * LTTng lib ring buffer client (discard mode). + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include "ltt-tracer.h" + +#define RING_BUFFER_MODE_TEMPLATE RING_BUFFER_DISCARD +#define RING_BUFFER_MODE_TEMPLATE_STRING "discard" +#define RING_BUFFER_MODE_TEMPLATE_INIT \ + ltt_ring_buffer_client_discard_init +#define RING_BUFFER_MODE_TEMPLATE_EXIT \ + ltt_ring_buffer_client_discard_exit +#include "ltt-ring-buffer-client.h" diff --git a/liblttng-ust/ltt-ring-buffer-client-overwrite.c b/liblttng-ust/ltt-ring-buffer-client-overwrite.c new file mode 100644 index 00000000..8590a7ee --- /dev/null +++ b/liblttng-ust/ltt-ring-buffer-client-overwrite.c @@ -0,0 +1,19 @@ +/* + * ltt-ring-buffer-client-overwrite.c + * + * Copyright (C) 2010 - Mathieu Desnoyers + * + * LTTng lib ring buffer client (overwrite mode). + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include "ltt-tracer.h" + +#define RING_BUFFER_MODE_TEMPLATE RING_BUFFER_OVERWRITE +#define RING_BUFFER_MODE_TEMPLATE_STRING "overwrite" +#define RING_BUFFER_MODE_TEMPLATE_INIT \ + ltt_ring_buffer_client_overwrite_init +#define RING_BUFFER_MODE_TEMPLATE_EXIT \ + ltt_ring_buffer_client_overwrite_exit +#include "ltt-ring-buffer-client.h" diff --git a/liblttng-ust/ltt-ring-buffer-client.h b/liblttng-ust/ltt-ring-buffer-client.h new file mode 100644 index 00000000..a1bc8c32 --- /dev/null +++ b/liblttng-ust/ltt-ring-buffer-client.h @@ -0,0 +1,554 @@ +/* + * ltt-ring-buffer-client.h + * + * Copyright (C) 2010 - Mathieu Desnoyers + * + * LTTng lib ring buffer client template. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include "lttng/bitfield.h" +#include "lttng/clock.h" +#include "ltt-tracer.h" +#include "../libringbuffer/frontend_types.h" + +/* + * Keep the natural field alignment for _each field_ within this structure if + * you ever add/remove a field from this header. Packed attribute is not used + * because gcc generates poor code on at least powerpc and mips. Don't ever + * let gcc add padding between the structure elements. + */ + +struct packet_header { + /* Trace packet header */ + uint32_t magic; /* + * Trace magic number. + * contains endianness information. + */ + uint8_t uuid[16]; + uint32_t stream_id; + + struct { + /* Stream packet context */ + uint64_t timestamp_begin; /* Cycle count at subbuffer start */ + uint64_t timestamp_end; /* Cycle count at subbuffer end */ + uint32_t events_discarded; /* + * Events lost in this subbuffer since + * the beginning of the trace. + * (may overflow) + */ + uint32_t content_size; /* Size of data in subbuffer */ + uint32_t packet_size; /* Subbuffer size (include padding) */ + uint32_t cpu_id; /* CPU id associated with stream */ + uint8_t header_end; /* End of header */ + } ctx; +}; + + +static inline notrace u64 lib_ring_buffer_clock_read(struct channel *chan) +{ + return trace_clock_read64(); +} + +static inline +size_t ctx_get_size(size_t offset, struct lttng_ctx *ctx) +{ + int i; + size_t orig_offset = offset; + + if (caa_likely(!ctx)) + return 0; + for (i = 0; i < ctx->nr_fields; i++) + offset += ctx->fields[i].get_size(offset); + return offset - orig_offset; +} + +static inline +void ctx_record(struct lttng_ust_lib_ring_buffer_ctx *bufctx, + struct ltt_channel *chan, + struct lttng_ctx *ctx) +{ + int i; + + if (caa_likely(!ctx)) + return; + for (i = 0; i < ctx->nr_fields; i++) + ctx->fields[i].record(&ctx->fields[i], bufctx, chan); +} + +/* + * record_header_size - Calculate the header size and padding necessary. + * @config: ring buffer instance configuration + * @chan: channel + * @offset: offset in the write buffer + * @pre_header_padding: padding to add before the header (output) + * @ctx: reservation context + * + * Returns the event header size (including padding). + * + * The payload must itself determine its own alignment from the biggest type it + * contains. + */ +static __inline__ +unsigned char record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, + struct channel *chan, size_t offset, + size_t *pre_header_padding, + struct lttng_ust_lib_ring_buffer_ctx *ctx) +{ + struct ltt_channel *ltt_chan = channel_get_private(chan); + struct ltt_event *event = ctx->priv; + size_t orig_offset = offset; + size_t padding; + + switch (ltt_chan->header_type) { + case 1: /* compact */ + padding = lib_ring_buffer_align(offset, lttng_alignof(uint32_t)); + offset += padding; + if (!(ctx->rflags & (RING_BUFFER_RFLAG_FULL_TSC | LTT_RFLAG_EXTENDED))) { + offset += sizeof(uint32_t); /* id and timestamp */ + } else { + /* Minimum space taken by 5-bit id */ + offset += sizeof(uint8_t); + /* Align extended struct on largest member */ + offset += lib_ring_buffer_align(offset, lttng_alignof(uint64_t)); + offset += sizeof(uint32_t); /* id */ + offset += lib_ring_buffer_align(offset, lttng_alignof(uint64_t)); + offset += sizeof(uint64_t); /* timestamp */ + } + break; + case 2: /* large */ + padding = lib_ring_buffer_align(offset, lttng_alignof(uint16_t)); + offset += padding; + offset += sizeof(uint16_t); + if (!(ctx->rflags & (RING_BUFFER_RFLAG_FULL_TSC | LTT_RFLAG_EXTENDED))) { + offset += lib_ring_buffer_align(offset, lttng_alignof(uint32_t)); + offset += sizeof(uint32_t); /* timestamp */ + } else { + /* Align extended struct on largest member */ + offset += lib_ring_buffer_align(offset, lttng_alignof(uint64_t)); + offset += sizeof(uint32_t); /* id */ + offset += lib_ring_buffer_align(offset, lttng_alignof(uint64_t)); + offset += sizeof(uint64_t); /* timestamp */ + } + break; + default: + padding = 0; + WARN_ON_ONCE(1); + } + offset += ctx_get_size(offset, event->ctx); + offset += ctx_get_size(offset, ltt_chan->ctx); + + *pre_header_padding = padding; + return offset - orig_offset; +} + +#include "../libringbuffer/api.h" + +static +void ltt_write_event_header_slow(const struct lttng_ust_lib_ring_buffer_config *config, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + uint32_t event_id); + +/* + * ltt_write_event_header + * + * Writes the event header to the offset (already aligned on 32-bits). + * + * @config: ring buffer instance configuration + * @ctx: reservation context + * @event_id: event ID + */ +static __inline__ +void ltt_write_event_header(const struct lttng_ust_lib_ring_buffer_config *config, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + uint32_t event_id) +{ + struct ltt_channel *ltt_chan = channel_get_private(ctx->chan); + struct ltt_event *event = ctx->priv; + + if (caa_unlikely(ctx->rflags)) + goto slow_path; + + switch (ltt_chan->header_type) { + case 1: /* compact */ + { + uint32_t id_time = 0; + + bt_bitfield_write(&id_time, uint32_t, 0, 5, event_id); + bt_bitfield_write(&id_time, uint32_t, 5, 27, ctx->tsc); + lib_ring_buffer_write(config, ctx, &id_time, sizeof(id_time)); + break; + } + case 2: /* large */ + { + uint32_t timestamp = (uint32_t) ctx->tsc; + uint16_t id = event_id; + + lib_ring_buffer_write(config, ctx, &id, sizeof(id)); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint32_t)); + lib_ring_buffer_write(config, ctx, ×tamp, sizeof(timestamp)); + break; + } + default: + WARN_ON_ONCE(1); + } + + ctx_record(ctx, ltt_chan, ltt_chan->ctx); + ctx_record(ctx, ltt_chan, event->ctx); + lib_ring_buffer_align_ctx(ctx, ctx->largest_align); + + return; + +slow_path: + ltt_write_event_header_slow(config, ctx, event_id); +} + +static +void ltt_write_event_header_slow(const struct lttng_ust_lib_ring_buffer_config *config, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + uint32_t event_id) +{ + struct ltt_channel *ltt_chan = channel_get_private(ctx->chan); + struct ltt_event *event = ctx->priv; + + switch (ltt_chan->header_type) { + case 1: /* compact */ + if (!(ctx->rflags & (RING_BUFFER_RFLAG_FULL_TSC | LTT_RFLAG_EXTENDED))) { + uint32_t id_time = 0; + + bt_bitfield_write(&id_time, uint32_t, 0, 5, event_id); + bt_bitfield_write(&id_time, uint32_t, 5, 27, ctx->tsc); + lib_ring_buffer_write(config, ctx, &id_time, sizeof(id_time)); + } else { + uint8_t id = 0; + uint64_t timestamp = ctx->tsc; + + bt_bitfield_write(&id, uint8_t, 0, 5, 31); + lib_ring_buffer_write(config, ctx, &id, sizeof(id)); + /* Align extended struct on largest member */ + lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint64_t)); + lib_ring_buffer_write(config, ctx, &event_id, sizeof(event_id)); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint64_t)); + lib_ring_buffer_write(config, ctx, ×tamp, sizeof(timestamp)); + } + break; + case 2: /* large */ + { + if (!(ctx->rflags & (RING_BUFFER_RFLAG_FULL_TSC | LTT_RFLAG_EXTENDED))) { + uint32_t timestamp = (uint32_t) ctx->tsc; + uint16_t id = event_id; + + lib_ring_buffer_write(config, ctx, &id, sizeof(id)); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint32_t)); + lib_ring_buffer_write(config, ctx, ×tamp, sizeof(timestamp)); + } else { + uint16_t id = 65535; + uint64_t timestamp = ctx->tsc; + + lib_ring_buffer_write(config, ctx, &id, sizeof(id)); + /* Align extended struct on largest member */ + lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint64_t)); + lib_ring_buffer_write(config, ctx, &event_id, sizeof(event_id)); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint64_t)); + lib_ring_buffer_write(config, ctx, ×tamp, sizeof(timestamp)); + } + break; + } + default: + WARN_ON_ONCE(1); + } + ctx_record(ctx, ltt_chan, ltt_chan->ctx); + ctx_record(ctx, ltt_chan, event->ctx); + lib_ring_buffer_align_ctx(ctx, ctx->largest_align); +} + +static const struct lttng_ust_lib_ring_buffer_config client_config; + +static u64 client_ring_buffer_clock_read(struct channel *chan) +{ + return lib_ring_buffer_clock_read(chan); +} + +static +size_t client_record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, + struct channel *chan, size_t offset, + size_t *pre_header_padding, + struct lttng_ust_lib_ring_buffer_ctx *ctx) +{ + return record_header_size(config, chan, offset, + pre_header_padding, ctx); +} + +/** + * client_packet_header_size - called on buffer-switch to a new sub-buffer + * + * Return header size without padding after the structure. Don't use packed + * structure because gcc generates inefficient code on some architectures + * (powerpc, mips..) + */ +static size_t client_packet_header_size(void) +{ + return offsetof(struct packet_header, ctx.header_end); +} + +static void client_buffer_begin(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, + unsigned int subbuf_idx, + struct lttng_ust_shm_handle *handle) +{ + struct channel *chan = shmp(handle, buf->backend.chan); + struct packet_header *header = + (struct packet_header *) + lib_ring_buffer_offset_address(&buf->backend, + subbuf_idx * chan->backend.subbuf_size, + handle); + struct ltt_channel *ltt_chan = channel_get_private(chan); + struct ltt_session *session = ltt_chan->session; + + header->magic = CTF_MAGIC_NUMBER; + memcpy(header->uuid, session->uuid, sizeof(session->uuid)); + header->stream_id = ltt_chan->id; + header->ctx.timestamp_begin = tsc; + header->ctx.timestamp_end = 0; + header->ctx.events_discarded = 0; + header->ctx.content_size = 0xFFFFFFFF; /* for debugging */ + header->ctx.packet_size = 0xFFFFFFFF; + header->ctx.cpu_id = buf->backend.cpu; +} + +/* + * offset is assumed to never be 0 here : never deliver a completely empty + * subbuffer. data_size is between 1 and subbuf_size. + */ +static void client_buffer_end(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, + unsigned int subbuf_idx, unsigned long data_size, + struct lttng_ust_shm_handle *handle) +{ + struct channel *chan = shmp(handle, buf->backend.chan); + struct packet_header *header = + (struct packet_header *) + lib_ring_buffer_offset_address(&buf->backend, + subbuf_idx * chan->backend.subbuf_size, + handle); + unsigned long records_lost = 0; + + header->ctx.timestamp_end = tsc; + header->ctx.content_size = data_size * CHAR_BIT; /* in bits */ + header->ctx.packet_size = PAGE_ALIGN(data_size) * CHAR_BIT; /* in bits */ + /* + * We do not care about the records lost count, because the metadata + * channel waits and retry. + */ + (void) lib_ring_buffer_get_records_lost_full(&client_config, buf); + records_lost += lib_ring_buffer_get_records_lost_wrap(&client_config, buf); + records_lost += lib_ring_buffer_get_records_lost_big(&client_config, buf); + header->ctx.events_discarded = records_lost; +} + +static int client_buffer_create(struct lttng_ust_lib_ring_buffer *buf, void *priv, + int cpu, const char *name, struct lttng_ust_shm_handle *handle) +{ + return 0; +} + +static void client_buffer_finalize(struct lttng_ust_lib_ring_buffer *buf, void *priv, int cpu, struct lttng_ust_shm_handle *handle) +{ +} + +static const struct lttng_ust_lib_ring_buffer_config client_config = { + .cb.ring_buffer_clock_read = client_ring_buffer_clock_read, + .cb.record_header_size = client_record_header_size, + .cb.subbuffer_header_size = client_packet_header_size, + .cb.buffer_begin = client_buffer_begin, + .cb.buffer_end = client_buffer_end, + .cb.buffer_create = client_buffer_create, + .cb.buffer_finalize = client_buffer_finalize, + + .tsc_bits = 32, + .alloc = RING_BUFFER_ALLOC_PER_CPU, + .sync = RING_BUFFER_SYNC_GLOBAL, + .mode = RING_BUFFER_MODE_TEMPLATE, + .backend = RING_BUFFER_PAGE, + .output = RING_BUFFER_MMAP, + .oops = RING_BUFFER_OOPS_CONSISTENCY, + .ipi = RING_BUFFER_NO_IPI_BARRIER, + .wakeup = RING_BUFFER_WAKEUP_BY_WRITER, +}; + +static +struct ltt_channel *_channel_create(const char *name, + struct ltt_channel *ltt_chan, void *buf_addr, + size_t subbuf_size, size_t num_subbuf, + unsigned int switch_timer_interval, + unsigned int read_timer_interval, + int *shm_fd, int *wait_fd, + uint64_t *memory_map_size) +{ + ltt_chan->handle = channel_create(&client_config, name, ltt_chan, buf_addr, + subbuf_size, num_subbuf, switch_timer_interval, + read_timer_interval, shm_fd, wait_fd, + memory_map_size); + if (!ltt_chan->handle) + return NULL; + ltt_chan->chan = shmp(ltt_chan->handle, ltt_chan->handle->chan); + return ltt_chan; +} + +static +void ltt_channel_destroy(struct ltt_channel *ltt_chan) +{ + channel_destroy(ltt_chan->chan, ltt_chan->handle, 0); +} + +static +struct lttng_ust_lib_ring_buffer *ltt_buffer_read_open(struct channel *chan, + struct lttng_ust_shm_handle *handle, + int *shm_fd, int *wait_fd, + uint64_t *memory_map_size) +{ + struct lttng_ust_lib_ring_buffer *buf; + int cpu; + + for_each_channel_cpu(cpu, chan) { + buf = channel_get_ring_buffer(&client_config, chan, + cpu, handle, shm_fd, wait_fd, + memory_map_size); + if (!lib_ring_buffer_open_read(buf, handle, 0)) + return buf; + } + return NULL; +} + +static +void ltt_buffer_read_close(struct lttng_ust_lib_ring_buffer *buf, + struct lttng_ust_shm_handle *handle) +{ + lib_ring_buffer_release_read(buf, handle, 0); +} + +static +int ltt_event_reserve(struct lttng_ust_lib_ring_buffer_ctx *ctx, + uint32_t event_id) +{ + struct ltt_channel *ltt_chan = channel_get_private(ctx->chan); + int ret, cpu; + + cpu = lib_ring_buffer_get_cpu(&client_config); + if (cpu < 0) + return -EPERM; + ctx->cpu = cpu; + + switch (ltt_chan->header_type) { + case 1: /* compact */ + if (event_id > 30) + ctx->rflags |= LTT_RFLAG_EXTENDED; + break; + case 2: /* large */ + if (event_id > 65534) + ctx->rflags |= LTT_RFLAG_EXTENDED; + break; + default: + WARN_ON_ONCE(1); + } + + ret = lib_ring_buffer_reserve(&client_config, ctx); + if (ret) + goto put; + ltt_write_event_header(&client_config, ctx, event_id); + return 0; +put: + lib_ring_buffer_put_cpu(&client_config); + return ret; +} + +static +void ltt_event_commit(struct lttng_ust_lib_ring_buffer_ctx *ctx) +{ + lib_ring_buffer_commit(&client_config, ctx); + lib_ring_buffer_put_cpu(&client_config); +} + +static +void ltt_event_write(struct lttng_ust_lib_ring_buffer_ctx *ctx, const void *src, + size_t len) +{ + lib_ring_buffer_write(&client_config, ctx, src, len); +} + +#if 0 +static +wait_queue_head_t *ltt_get_reader_wait_queue(struct channel *chan) +{ + return &chan->read_wait; +} + +static +wait_queue_head_t *ltt_get_hp_wait_queue(struct channel *chan) +{ + return &chan->hp_wait; +} +#endif //0 + +static +int ltt_is_finalized(struct channel *chan) +{ + return lib_ring_buffer_channel_is_finalized(chan); +} + +static +int ltt_is_disabled(struct channel *chan) +{ + return lib_ring_buffer_channel_is_disabled(chan); +} + +static +int ltt_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle) +{ + struct lttng_ust_lib_ring_buffer *buf; + int cpu; + + for_each_channel_cpu(cpu, chan) { + int shm_fd, wait_fd; + uint64_t memory_map_size; + + buf = channel_get_ring_buffer(&client_config, chan, + cpu, handle, &shm_fd, &wait_fd, + &memory_map_size); + lib_ring_buffer_switch(&client_config, buf, + SWITCH_ACTIVE, handle); + } + return 0; +} + +static struct ltt_transport ltt_relay_transport = { + .name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING "-mmap", + .ops = { + .channel_create = _channel_create, + .channel_destroy = ltt_channel_destroy, + .buffer_read_open = ltt_buffer_read_open, + .buffer_read_close = ltt_buffer_read_close, + .event_reserve = ltt_event_reserve, + .event_commit = ltt_event_commit, + .event_write = ltt_event_write, + .packet_avail_size = NULL, /* Would be racy anyway */ + //.get_reader_wait_queue = ltt_get_reader_wait_queue, + //.get_hp_wait_queue = ltt_get_hp_wait_queue, + .is_finalized = ltt_is_finalized, + .is_disabled = ltt_is_disabled, + .flush_buffer = ltt_flush_buffer, + }, +}; + +void RING_BUFFER_MODE_TEMPLATE_INIT(void) +{ + DBG("LTT : ltt ring buffer client init\n"); + ltt_transport_register(<t_relay_transport); +} + +void RING_BUFFER_MODE_TEMPLATE_EXIT(void) +{ + DBG("LTT : ltt ring buffer client exit\n"); + ltt_transport_unregister(<t_relay_transport); +} diff --git a/liblttng-ust/ltt-ring-buffer-metadata-client.c b/liblttng-ust/ltt-ring-buffer-metadata-client.c new file mode 100644 index 00000000..e1747c43 --- /dev/null +++ b/liblttng-ust/ltt-ring-buffer-metadata-client.c @@ -0,0 +1,19 @@ +/* + * ltt-ring-buffer-metadata-client.c + * + * Copyright (C) 2010 - Mathieu Desnoyers + * + * LTTng lib ring buffer metadta client. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include "ltt-tracer.h" + +#define RING_BUFFER_MODE_TEMPLATE RING_BUFFER_DISCARD +#define RING_BUFFER_MODE_TEMPLATE_STRING "metadata" +#define RING_BUFFER_MODE_TEMPLATE_INIT \ + ltt_ring_buffer_metadata_client_init +#define RING_BUFFER_MODE_TEMPLATE_EXIT \ + ltt_ring_buffer_metadata_client_exit +#include "ltt-ring-buffer-metadata-client.h" diff --git a/liblttng-ust/ltt-ring-buffer-metadata-client.h b/liblttng-ust/ltt-ring-buffer-metadata-client.h new file mode 100644 index 00000000..d1a83d53 --- /dev/null +++ b/liblttng-ust/ltt-ring-buffer-metadata-client.h @@ -0,0 +1,316 @@ +/* + * ltt-ring-buffer-client.h + * + * Copyright (C) 2010 - Mathieu Desnoyers + * + * LTTng lib ring buffer client template. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include "lttng/bitfield.h" +#include "ltt-tracer.h" +#include "../libringbuffer/frontend_types.h" + +struct metadata_packet_header { + uint32_t magic; /* 0x75D11D57 */ + uint8_t uuid[16]; /* Unique Universal Identifier */ + uint32_t checksum; /* 0 if unused */ + uint32_t content_size; /* in bits */ + uint32_t packet_size; /* in bits */ + uint8_t compression_scheme; /* 0 if unused */ + uint8_t encryption_scheme; /* 0 if unused */ + uint8_t checksum_scheme; /* 0 if unused */ + uint8_t major; /* CTF spec major version number */ + uint8_t minor; /* CTF spec minor version number */ + uint8_t header_end[0]; +}; + +struct metadata_record_header { + uint8_t header_end[0]; /* End of header */ +}; + +static const struct lttng_ust_lib_ring_buffer_config client_config; + +static inline +u64 lib_ring_buffer_clock_read(struct channel *chan) +{ + return 0; +} + +static inline +unsigned char record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, + struct channel *chan, size_t offset, + size_t *pre_header_padding, + struct lttng_ust_lib_ring_buffer_ctx *ctx) +{ + return 0; +} + +#include "../libringbuffer/api.h" + +static u64 client_ring_buffer_clock_read(struct channel *chan) +{ + return 0; +} + +static +size_t client_record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, + struct channel *chan, size_t offset, + size_t *pre_header_padding, + struct lttng_ust_lib_ring_buffer_ctx *ctx) +{ + return 0; +} + +/** + * client_packet_header_size - called on buffer-switch to a new sub-buffer + * + * Return header size without padding after the structure. Don't use packed + * structure because gcc generates inefficient code on some architectures + * (powerpc, mips..) + */ +static size_t client_packet_header_size(void) +{ + return offsetof(struct metadata_packet_header, header_end); +} + +static void client_buffer_begin(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, + unsigned int subbuf_idx, + struct lttng_ust_shm_handle *handle) +{ + struct channel *chan = shmp(handle, buf->backend.chan); + struct metadata_packet_header *header = + (struct metadata_packet_header *) + lib_ring_buffer_offset_address(&buf->backend, + subbuf_idx * chan->backend.subbuf_size, + handle); + struct ltt_channel *ltt_chan = channel_get_private(chan); + struct ltt_session *session = ltt_chan->session; + + header->magic = TSDL_MAGIC_NUMBER; + memcpy(header->uuid, session->uuid, sizeof(session->uuid)); + header->checksum = 0; /* 0 if unused */ + header->content_size = 0xFFFFFFFF; /* in bits, for debugging */ + header->packet_size = 0xFFFFFFFF; /* in bits, for debugging */ + header->compression_scheme = 0; /* 0 if unused */ + header->encryption_scheme = 0; /* 0 if unused */ + header->checksum_scheme = 0; /* 0 if unused */ + header->major = CTF_SPEC_MAJOR; + header->minor = CTF_SPEC_MINOR; + +} + +/* + * offset is assumed to never be 0 here : never deliver a completely empty + * subbuffer. data_size is between 1 and subbuf_size. + */ +static void client_buffer_end(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, + unsigned int subbuf_idx, unsigned long data_size, + struct lttng_ust_shm_handle *handle) +{ + struct channel *chan = shmp(handle, buf->backend.chan); + struct metadata_packet_header *header = + (struct metadata_packet_header *) + lib_ring_buffer_offset_address(&buf->backend, + subbuf_idx * chan->backend.subbuf_size, + handle); + unsigned long records_lost = 0; + + header->content_size = data_size * CHAR_BIT; /* in bits */ + header->packet_size = PAGE_ALIGN(data_size) * CHAR_BIT; /* in bits */ + records_lost += lib_ring_buffer_get_records_lost_full(&client_config, buf); + records_lost += lib_ring_buffer_get_records_lost_wrap(&client_config, buf); + records_lost += lib_ring_buffer_get_records_lost_big(&client_config, buf); + WARN_ON_ONCE(records_lost != 0); +} + +static int client_buffer_create(struct lttng_ust_lib_ring_buffer *buf, void *priv, + int cpu, const char *name, + struct lttng_ust_shm_handle *handle) +{ + return 0; +} + +static void client_buffer_finalize(struct lttng_ust_lib_ring_buffer *buf, + void *priv, int cpu, + struct lttng_ust_shm_handle *handle) +{ +} + +static const struct lttng_ust_lib_ring_buffer_config client_config = { + .cb.ring_buffer_clock_read = client_ring_buffer_clock_read, + .cb.record_header_size = client_record_header_size, + .cb.subbuffer_header_size = client_packet_header_size, + .cb.buffer_begin = client_buffer_begin, + .cb.buffer_end = client_buffer_end, + .cb.buffer_create = client_buffer_create, + .cb.buffer_finalize = client_buffer_finalize, + + .tsc_bits = 0, + .alloc = RING_BUFFER_ALLOC_GLOBAL, + .sync = RING_BUFFER_SYNC_GLOBAL, + .mode = RING_BUFFER_MODE_TEMPLATE, + .backend = RING_BUFFER_PAGE, + .output = RING_BUFFER_MMAP, + .oops = RING_BUFFER_OOPS_CONSISTENCY, + .ipi = RING_BUFFER_NO_IPI_BARRIER, + .wakeup = RING_BUFFER_WAKEUP_BY_WRITER, +}; + +static +struct ltt_channel *_channel_create(const char *name, + struct ltt_channel *ltt_chan, void *buf_addr, + size_t subbuf_size, size_t num_subbuf, + unsigned int switch_timer_interval, + unsigned int read_timer_interval, + int *shm_fd, int *wait_fd, + uint64_t *memory_map_size) +{ + ltt_chan->handle = channel_create(&client_config, name, ltt_chan, buf_addr, + subbuf_size, num_subbuf, switch_timer_interval, + read_timer_interval, shm_fd, wait_fd, + memory_map_size); + if (!ltt_chan->handle) + return NULL; + ltt_chan->chan = shmp(ltt_chan->handle, ltt_chan->handle->chan); + return ltt_chan; +} + +static +void ltt_channel_destroy(struct ltt_channel *ltt_chan) +{ + channel_destroy(ltt_chan->chan, ltt_chan->handle, 0); +} + +static +struct lttng_ust_lib_ring_buffer *ltt_buffer_read_open(struct channel *chan, + struct lttng_ust_shm_handle *handle, + int *shm_fd, int *wait_fd, + uint64_t *memory_map_size) +{ + struct lttng_ust_lib_ring_buffer *buf; + + buf = channel_get_ring_buffer(&client_config, chan, + 0, handle, shm_fd, wait_fd, memory_map_size); + if (!lib_ring_buffer_open_read(buf, handle, 0)) + return buf; + return NULL; +} + +static +void ltt_buffer_read_close(struct lttng_ust_lib_ring_buffer *buf, + struct lttng_ust_shm_handle *handle) +{ + lib_ring_buffer_release_read(buf, handle, 0); +} + +static +int ltt_event_reserve(struct lttng_ust_lib_ring_buffer_ctx *ctx, uint32_t event_id) +{ + return lib_ring_buffer_reserve(&client_config, ctx); +} + +static +void ltt_event_commit(struct lttng_ust_lib_ring_buffer_ctx *ctx) +{ + lib_ring_buffer_commit(&client_config, ctx); +} + +static +void ltt_event_write(struct lttng_ust_lib_ring_buffer_ctx *ctx, const void *src, + size_t len) +{ + lib_ring_buffer_write(&client_config, ctx, src, len); +} + +static +size_t ltt_packet_avail_size(struct channel *chan, struct lttng_ust_shm_handle *handle) + +{ + unsigned long o_begin; + struct lttng_ust_lib_ring_buffer *buf; + + buf = shmp(handle, chan->backend.buf[0].shmp); /* Only for global buffer ! */ + o_begin = v_read(&client_config, &buf->offset); + if (subbuf_offset(o_begin, chan) != 0) { + return chan->backend.subbuf_size - subbuf_offset(o_begin, chan); + } else { + return chan->backend.subbuf_size - subbuf_offset(o_begin, chan) + - sizeof(struct metadata_packet_header); + } +} + +#if 0 +static +wait_queue_head_t *ltt_get_reader_wait_queue(struct channel *chan) +{ + return &chan->read_wait; +} + +static +wait_queue_head_t *ltt_get_hp_wait_queue(struct channel *chan) +{ + return &chan->hp_wait; +} +#endif //0 + +static +int ltt_is_finalized(struct channel *chan) +{ + return lib_ring_buffer_channel_is_finalized(chan); +} + +static +int ltt_is_disabled(struct channel *chan) +{ + return lib_ring_buffer_channel_is_disabled(chan); +} + +static +int ltt_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle) +{ + struct lttng_ust_lib_ring_buffer *buf; + int shm_fd, wait_fd; + uint64_t memory_map_size; + + buf = channel_get_ring_buffer(&client_config, chan, + 0, handle, &shm_fd, &wait_fd, + &memory_map_size); + lib_ring_buffer_switch(&client_config, buf, + SWITCH_ACTIVE, handle); + return 0; +} + +static struct ltt_transport ltt_relay_transport = { + .name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING "-mmap", + .ops = { + .channel_create = _channel_create, + .channel_destroy = ltt_channel_destroy, + .buffer_read_open = ltt_buffer_read_open, + .buffer_read_close = ltt_buffer_read_close, + .event_reserve = ltt_event_reserve, + .event_commit = ltt_event_commit, + .event_write = ltt_event_write, + .packet_avail_size = ltt_packet_avail_size, + //.get_reader_wait_queue = ltt_get_reader_wait_queue, + //.get_hp_wait_queue = ltt_get_hp_wait_queue, + .is_finalized = ltt_is_finalized, + .is_disabled = ltt_is_disabled, + .flush_buffer = ltt_flush_buffer, + }, +}; + +void RING_BUFFER_MODE_TEMPLATE_INIT(void) +{ + DBG("LTT : ltt ring buffer client init\n"); + ltt_transport_register(<t_relay_transport); +} + +void RING_BUFFER_MODE_TEMPLATE_EXIT(void) +{ + DBG("LTT : ltt ring buffer client exit\n"); + ltt_transport_unregister(<t_relay_transport); +} diff --git a/liblttng-ust/ltt-tracer-core.h b/liblttng-ust/ltt-tracer-core.h new file mode 100644 index 00000000..20ed0c0e --- /dev/null +++ b/liblttng-ust/ltt-tracer-core.h @@ -0,0 +1,40 @@ +#ifndef _LTT_TRACER_CORE_H +#define _LTT_TRACER_CORE_H + +/* + * Copyright (C) 2005-2011 Mathieu Desnoyers + * + * This contains the core definitions for the Linux Trace Toolkit. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 of + * the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include "lttng/bug.h" + +#include + +struct ltt_session; +struct ltt_channel; +struct ltt_event; + +void ust_lock(void); +void ust_unlock(void); + +#endif /* _LTT_TRACER_CORE_H */ diff --git a/liblttng-ust/ltt-tracer.h b/liblttng-ust/ltt-tracer.h new file mode 100644 index 00000000..6ab80e7c --- /dev/null +++ b/liblttng-ust/ltt-tracer.h @@ -0,0 +1,58 @@ +#ifndef _LTT_TRACER_H +#define _LTT_TRACER_H + +/* + * Copyright (C) 2005-2011 Mathieu Desnoyers + * + * This contains the definitions for the Linux Trace Toolkit tracer. + * + * Ported to userspace by Pierre-Marc Fournier. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 of + * the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include "ltt-tracer-core.h" + +/* Number of bytes to log with a read/write event */ +#define LTT_LOG_RW_SIZE 32L +#define LTT_MAX_SMALL_SIZE 0xFFFFU + +/* Tracer properties */ +#define CTF_MAGIC_NUMBER 0xC1FC1FC1 +#define TSDL_MAGIC_NUMBER 0x75D11D57 + +/* CTF specification version followed */ +#define CTF_SPEC_MAJOR 1 +#define CTF_SPEC_MINOR 8 + +/* Tracer major/minor versions */ +#define CTF_VERSION_MAJOR 0 +#define CTF_VERSION_MINOR 1 + +/* + * Number of milliseconds to retry before failing metadata writes on buffer full + * condition. (10 seconds) + */ +#define LTTNG_METADATA_TIMEOUT_MSEC 10000 + +#define LTT_RFLAG_EXTENDED RING_BUFFER_RFLAG_END +#define LTT_RFLAG_END (LTT_RFLAG_EXTENDED << 1) + +#endif /* _LTT_TRACER_H */ diff --git a/liblttng-ust/lttng-context-procname.c b/liblttng-ust/lttng-context-procname.c new file mode 100644 index 00000000..b9bae82e --- /dev/null +++ b/liblttng-ust/lttng-context-procname.c @@ -0,0 +1,88 @@ +/* + * (C) Copyright 2009-2011 - + * Mathieu Desnoyers + * + * LTTng UST procname context. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include +#include + +#define PROCNAME_LEN 17 /* includes \0 */ + +/* + * We cache the result to ensure we don't trigger a system call for + * each event. + * Upon exec, procname changes, but exec takes care of throwing away + * this cached version. + */ +static char cached_procname[17]; + +static inline +char *wrapper_getprocname(void) +{ + int ret; + + if (caa_unlikely(!cached_procname[0])) { + ret = prctl(PR_GET_NAME, (unsigned long) cached_procname, + 0, 0, 0); + assert(!ret); + } + return cached_procname; +} + +void lttng_context_procname_reset(void) +{ + cached_procname[0] = '\0'; +} + +static +size_t procname_get_size(size_t offset) +{ + size_t size = 0; + + size += PROCNAME_LEN; + return size; +} + +static +void procname_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct ltt_channel *chan) +{ + char *procname; + + procname = wrapper_getprocname(); + chan->ops->event_write(ctx, procname, PROCNAME_LEN); +} + +int lttng_add_procname_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "procname")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "procname"; + field->event_field.type.atype = atype_array; + field->event_field.type.u.array.elem_type.atype = atype_integer; + field->event_field.type.u.array.elem_type.u.basic.integer.size = sizeof(char) * CHAR_BIT; + field->event_field.type.u.array.elem_type.u.basic.integer.alignment = lttng_alignof(char) * CHAR_BIT; + field->event_field.type.u.array.elem_type.u.basic.integer.signedness = lttng_is_signed_type(char); + field->event_field.type.u.array.elem_type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.array.elem_type.u.basic.integer.base = 10; + field->event_field.type.u.array.elem_type.u.basic.integer.encoding = lttng_encode_UTF8; + field->event_field.type.u.array.length = PROCNAME_LEN; + field->get_size = procname_get_size; + field->record = procname_record; + return 0; +} diff --git a/liblttng-ust/lttng-context-pthread-id.c b/liblttng-ust/lttng-context-pthread-id.c new file mode 100644 index 00000000..62eda808 --- /dev/null +++ b/liblttng-ust/lttng-context-pthread-id.c @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2009-2011 - + * Mathieu Desnoyers + * + * LTTng UST pthread_id context. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include + +static +size_t pthread_id_get_size(size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(unsigned long)); + size += sizeof(unsigned long); + return size; +} + +static +void pthread_id_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct ltt_channel *chan) +{ + unsigned long pthread_id; + + pthread_id = (unsigned long) pthread_self(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(pthread_id)); + chan->ops->event_write(ctx, &pthread_id, sizeof(pthread_id)); +} + +int lttng_add_pthread_id_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "pthread_id")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "pthread_id"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(unsigned long) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(unsigned long); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = pthread_id_get_size; + field->record = pthread_id_record; + return 0; +} diff --git a/liblttng-ust/lttng-context-vpid.c b/liblttng-ust/lttng-context-vpid.c new file mode 100644 index 00000000..db76747a --- /dev/null +++ b/liblttng-ust/lttng-context-vpid.c @@ -0,0 +1,95 @@ +/* + * (C) Copyright 2009-2011 - + * Mathieu Desnoyers + * + * LTTng UST vpid context. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include +#include + +#ifdef __linux__ +static inline +pid_t wrapper_getpid(void) +{ + return getpid(); +} + +void lttng_context_vpid_reset(void) +{ +} +#else +/* + * We cache the result to ensure we don't trigger a system call for + * each event. + */ +static pid_t cached_vpid; + +static inline +pid_t wrapper_getpid(void) +{ + if (caa_unlikely(!cached_vpid)) + cached_vpid = getpid(); + return cached_vpid; +} + +/* + * Upon fork or clone, the PID assigned to our thread is not the same as + * we kept in cache. + */ +void lttng_context_vpid_reset(void) +{ + cached_vpid = 0; +} +#endif + +static +size_t vpid_get_size(size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(pid_t)); + size += sizeof(pid_t); + return size; +} + +static +void vpid_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct ltt_channel *chan) +{ + pid_t pid; + + pid = wrapper_getpid(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(pid)); + chan->ops->event_write(ctx, &pid, sizeof(pid)); +} + +int lttng_add_vpid_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "vpid")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "vpid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(pid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(pid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(pid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = vpid_get_size; + field->record = vpid_record; + return 0; +} diff --git a/liblttng-ust/lttng-context-vtid.c b/liblttng-ust/lttng-context-vtid.c new file mode 100644 index 00000000..6f7e078d --- /dev/null +++ b/liblttng-ust/lttng-context-vtid.c @@ -0,0 +1,94 @@ +/* + * (C) Copyright 2009-2011 - + * Mathieu Desnoyers + * + * LTTng UST vtid context. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#endif + +#if defined(_syscall0) +_syscall0(pid_t, gettid) +#elif defined(__NR_gettid) +static inline pid_t gettid(void) +{ + return syscall(__NR_gettid); +} +#else +#warning "use pid as tid" +static inline pid_t gettid(void) +{ + return getpid(); +} +#endif + +/* + * We cache the result to ensure we don't trigger a system call for + * each event. + */ +static __thread pid_t cached_vtid; + +/* + * Upon fork or clone, the TID assigned to our thread is not the same as + * we kept in cache. Luckily, we are the only thread surviving in the + * child process, so we can simply clear our cached version. + */ +void lttng_context_vtid_reset(void) +{ + cached_vtid = 0; +} + +static +size_t vtid_get_size(size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(pid_t)); + size += sizeof(pid_t); + return size; +} + +static +void vtid_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct ltt_channel *chan) +{ + if (caa_unlikely(!cached_vtid)) + cached_vtid = gettid(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(cached_vtid)); + chan->ops->event_write(ctx, &cached_vtid, sizeof(cached_vtid)); +} + +int lttng_add_vtid_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "vtid")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "vtid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(pid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(pid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(pid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = vtid_get_size; + field->record = vtid_record; + return 0; +} diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c new file mode 100644 index 00000000..6d17c200 --- /dev/null +++ b/liblttng-ust/lttng-ust-abi.c @@ -0,0 +1,822 @@ +/* + * 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 +#include "lttng/core.h" +#include "ltt-tracer.h" + +/* + * Object descriptor table. Should be protected from concurrent access + * by the caller. + */ + +struct lttng_ust_obj { + union { + struct { + void *private_data; + const struct lttng_ust_objd_ops *ops; + int f_count; + } s; + int freelist_next; /* offset freelist. end is -1. */ + } u; +}; + +struct lttng_ust_objd_table { + struct lttng_ust_obj *array; + unsigned int len, allocated_len; + int freelist_head; /* offset freelist head. end is -1 */ +}; + +static struct lttng_ust_objd_table objd_table = { + .freelist_head = -1, +}; + +static +int objd_alloc(void *private_data, const struct lttng_ust_objd_ops *ops) +{ + struct lttng_ust_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 lttng_ust_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 lttng_ust_obj) * new_allocated_len); + if (!new_table) + return -ENOMEM; + memcpy(new_table, old_table, + sizeof(struct lttng_ust_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 = 2; /* count == 1 : object is allocated */ + /* count == 2 : allocated + hold ref */ + return obj - objd_table.array; +} + +static +struct lttng_ust_obj *_objd_get(int id) +{ + if (id >= objd_table.len) + return NULL; + if (!objd_table.array[id].u.s.f_count) + return NULL; + return &objd_table.array[id]; +} + +static +void *objd_private(int id) +{ + struct lttng_ust_obj *obj = _objd_get(id); + assert(obj); + return obj->u.s.private_data; +} + +static +void objd_set_private(int id, void *private_data) +{ + struct lttng_ust_obj *obj = _objd_get(id); + assert(obj); + obj->u.s.private_data = private_data; +} + +const struct lttng_ust_objd_ops *objd_ops(int id) +{ + struct lttng_ust_obj *obj = _objd_get(id); + + if (!obj) + return NULL; + return obj->u.s.ops; +} + +static +void objd_free(int id) +{ + struct lttng_ust_obj *obj = _objd_get(id); + + assert(obj); + obj->u.freelist_next = objd_table.freelist_head; + objd_table.freelist_head = obj - objd_table.array; + assert(obj->u.s.f_count == 1); + obj->u.s.f_count = 0; /* deallocated */ +} + +static +void objd_ref(int id) +{ + struct lttng_ust_obj *obj = _objd_get(id); + obj->u.s.f_count++; +} + +int lttng_ust_objd_unref(int id) +{ + struct lttng_ust_obj *obj = _objd_get(id); + + if (!obj) + return -EINVAL; + if (obj->u.s.f_count == 1) { + ERR("Reference counting error\n"); + return -EINVAL; + } + if ((--obj->u.s.f_count) == 1) { + const struct lttng_ust_objd_ops *ops = objd_ops(id); + + if (ops->release) + ops->release(id); + objd_free(id); + } + return 0; +} + +static +void objd_table_destroy(void) +{ + int i; + + for (i = 0; i < objd_table.allocated_len; i++) + (void) lttng_ust_objd_unref(i); + free(objd_table.array); + objd_table.array = NULL; + objd_table.len = 0; + objd_table.allocated_len = 0; + objd_table.freelist_head = -1; +} + +/* + * This is LTTng's own personal way to create an ABI for sessiond. + * We send commands over a socket. + */ + +static const struct lttng_ust_objd_ops lttng_ops; +static const struct lttng_ust_objd_ops lttng_session_ops; +static const struct lttng_ust_objd_ops lttng_channel_ops; +static const struct lttng_ust_objd_ops lttng_metadata_ops; +static const struct lttng_ust_objd_ops lttng_event_ops; +static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops; + +enum channel_type { + PER_CPU_CHANNEL, + METADATA_CHANNEL, +}; + +int lttng_abi_create_root_handle(void) +{ + int root_handle; + + root_handle = objd_alloc(NULL, <tng_ops); + return root_handle; +} + +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_PTHREAD_ID: + return lttng_add_pthread_id_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VTID: + return lttng_add_vtid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VPID: + return lttng_add_vpid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_PROCNAME: + return lttng_add_procname_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 lttng_ust_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 */ +} + +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 lttng_ust_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, + &chan_param->shm_fd, + &chan_param->wait_fd, + &chan_param->memory_map_size); + 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: + { + int err; + + err = lttng_ust_objd_unref(chan_objd); + assert(!err); + } +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_release_session(int objd) +{ + struct ltt_session *session = objd_private(objd); + + if (session) { + ltt_session_destroy(session); + return 0; + } else { + return -EINVAL; + } +} + +static const struct lttng_ust_objd_ops lttng_session_ops = { + .release = lttng_release_session, + .cmd = lttng_session_cmd, +}; + +struct stream_priv_data { + struct lttng_ust_lib_ring_buffer *buf; + struct ltt_channel *ltt_chan; +}; + +static +int lttng_abi_open_stream(int channel_objd, struct lttng_ust_stream *info) +{ + struct ltt_channel *channel = objd_private(channel_objd); + struct lttng_ust_lib_ring_buffer *buf; + struct stream_priv_data *priv; + int stream_objd, ret; + + buf = channel->ops->buffer_read_open(channel->chan, channel->handle, + &info->shm_fd, &info->wait_fd, &info->memory_map_size); + if (!buf) + return -ENOENT; + + priv = zmalloc(sizeof(*priv)); + if (!priv) { + ret = -ENOMEM; + goto alloc_error; + } + priv->buf = buf; + priv->ltt_chan = channel; + stream_objd = objd_alloc(priv, &lib_ring_buffer_objd_ops); + if (stream_objd < 0) { + ret = stream_objd; + goto objd_error; + } + /* Hold a reference on the channel object descriptor */ + objd_ref(channel_objd); + return stream_objd; + +objd_error: + free(priv); +alloc_error: + channel->ops->buffer_read_close(buf, channel->handle); + return ret; +} + +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: + { + int err; + + err = lttng_ust_objd_unref(event_objd); + assert(!err); + } +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: + { + struct lttng_ust_stream *stream; + + stream = (struct lttng_ust_stream *) arg; + /* stream used as output */ + return lttng_abi_open_stream(objd, stream); + } + 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); + case LTTNG_UST_FLUSH_BUFFER: + return channel->ops->flush_buffer(channel->chan, channel->handle); + 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) +{ + struct ltt_channel *channel = objd_private(objd); + + switch (cmd) { + case LTTNG_UST_STREAM: + { + struct lttng_ust_stream *stream; + + stream = (struct lttng_ust_stream *) arg; + /* stream used as output */ + return lttng_abi_open_stream(objd, stream); + } + case LTTNG_UST_FLUSH_BUFFER: + return channel->ops->flush_buffer(channel->chan, channel->handle); + 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) + return lttng_ust_objd_unref(channel->session->objd); + return 0; +} + +static const struct lttng_ust_objd_ops lttng_channel_ops = { + .release = lttng_channel_release, + //.poll = lttng_channel_poll, + .cmd = lttng_channel_cmd, +}; + +static const struct lttng_ust_objd_ops lttng_metadata_ops = { + .release = lttng_channel_release, + .cmd = lttng_metadata_cmd, +}; + +/** + * lttng_rb_cmd - lttng ring buffer control through object descriptors + * + * @objd: the object descriptor + * @cmd: the command + * @arg: command arg + * + * This object descriptor implements lttng commands: + * (None for now. Access is done directly though shm.) + */ +static +long lttng_rb_cmd(int objd, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + default: + return -EINVAL; + } +} + +static +int lttng_rb_release(int objd) +{ + struct stream_priv_data *priv = objd_private(objd); + struct lttng_ust_lib_ring_buffer *buf; + struct ltt_channel *channel; + + if (priv) { + buf = priv->buf; + channel = priv->ltt_chan; + free(priv); + channel->ops->buffer_read_close(buf, channel->handle); + + return lttng_ust_objd_unref(channel->objd); + } + return 0; +} + +static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops = { + .release = lttng_rb_release, + .cmd = lttng_rb_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) + return lttng_ust_objd_unref(event->chan->objd); + return 0; +} + +/* TODO: filter control ioctl */ +static const struct lttng_ust_objd_ops lttng_event_ops = { + .release = lttng_event_release, + .cmd = lttng_event_cmd, +}; + +void lttng_ust_abi_exit(void) +{ + objd_table_destroy(); +} diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c new file mode 100644 index 00000000..d35511b2 --- /dev/null +++ b/liblttng-ust/lttng-ust-comm.c @@ -0,0 +1,935 @@ +/* + * lttng-ust-comm.c + * + * Copyright (C) 2011 David Goulet + * Copyright (C) 2011 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "ltt-tracer-core.h" + +/* + * Has lttng ust comm constructor been called ? + */ +static int initialized; + +/* + * The ust_lock/ust_unlock lock is used as a communication thread mutex. + * Held when handling a command, also held by fork() to deal with + * removal of threads, and by exit path. + */ + +/* Should the ust comm thread quit ? */ +static int lttng_ust_comm_should_quit; + +/* + * Wait for either of these before continuing to the main + * program: + * - the register_done message from sessiond daemon + * (will let the sessiond daemon enable sessions before main + * starts.) + * - sessiond daemon is not reachable. + * - timeout (ensuring applications are resilient to session + * daemon problems). + */ +static sem_t constructor_wait; +/* + * Doing this for both the global and local sessiond. + */ +static int sem_count = { 2 }; + +/* + * Info about socket and associated listener thread. + */ +struct sock_info { + const char *name; + pthread_t ust_listener; /* listener thread */ + int root_handle; + int constructor_sem_posted; + int allowed; + int global; + + char sock_path[PATH_MAX]; + int socket; + + char wait_shm_path[PATH_MAX]; + char *wait_shm_mmap; +}; + +/* Socket from app (connect) to session daemon (listen) for communication */ +struct sock_info global_apps = { + .name = "global", + .global = 1, + + .root_handle = -1, + .allowed = 1, + + .sock_path = DEFAULT_GLOBAL_APPS_UNIX_SOCK, + .socket = -1, + + .wait_shm_path = DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH, +}; + +/* TODO: allow global_apps_sock_path override */ + +struct sock_info local_apps = { + .name = "local", + .global = 0, + .root_handle = -1, + .allowed = 0, /* Check setuid bit first */ + + .socket = -1, +}; + +static int wait_poll_fallback; + +extern void ltt_ring_buffer_client_overwrite_init(void); +extern void ltt_ring_buffer_client_discard_init(void); +extern void ltt_ring_buffer_metadata_client_init(void); +extern void ltt_ring_buffer_client_overwrite_exit(void); +extern void ltt_ring_buffer_client_discard_exit(void); +extern void ltt_ring_buffer_metadata_client_exit(void); + +static +int setup_local_apps(void) +{ + const char *home_dir; + uid_t uid; + + uid = getuid(); + /* + * Disallow per-user tracing for setuid binaries. + */ + if (uid != geteuid()) { + local_apps.allowed = 0; + return 0; + } else { + local_apps.allowed = 1; + } + home_dir = (const char *) getenv("HOME"); + if (!home_dir) + return -ENOENT; + snprintf(local_apps.sock_path, PATH_MAX, + DEFAULT_HOME_APPS_UNIX_SOCK, home_dir); + snprintf(local_apps.wait_shm_path, PATH_MAX, + DEFAULT_HOME_APPS_WAIT_SHM_PATH, uid); + return 0; +} + +static +int register_app_to_sessiond(int socket) +{ + ssize_t ret; + int prctl_ret; + struct { + uint32_t major; + uint32_t minor; + pid_t pid; + pid_t ppid; + uid_t uid; + gid_t gid; + char name[16]; /* process name */ + } reg_msg; + + reg_msg.major = LTTNG_UST_COMM_VERSION_MAJOR; + reg_msg.minor = LTTNG_UST_COMM_VERSION_MINOR; + reg_msg.pid = getpid(); + reg_msg.ppid = getppid(); + reg_msg.uid = getuid(); + reg_msg.gid = getgid(); + prctl_ret = prctl(PR_GET_NAME, (unsigned long) reg_msg.name, 0, 0, 0); + if (prctl_ret) { + ERR("Error executing prctl"); + return -errno; + } + + ret = ustcomm_send_unix_sock(socket, ®_msg, sizeof(reg_msg)); + if (ret >= 0 && ret != sizeof(reg_msg)) + return -EIO; + return ret; +} + +static +int send_reply(int sock, struct ustcomm_ust_reply *lur) +{ + ssize_t len; + + len = ustcomm_send_unix_sock(sock, lur, sizeof(*lur)); + switch (len) { + case sizeof(*lur): + DBG("message successfully sent"); + return 0; + case -1: + if (errno == ECONNRESET) { + printf("remote end closed connection\n"); + return 0; + } + return -1; + default: + printf("incorrect message size: %zd\n", len); + return -1; + } +} + +static +int handle_register_done(struct sock_info *sock_info) +{ + int ret; + + if (sock_info->constructor_sem_posted) + return 0; + sock_info->constructor_sem_posted = 1; + if (uatomic_read(&sem_count) <= 0) { + return 0; + } + ret = uatomic_add_return(&sem_count, -1); + if (ret == 0) { + ret = sem_post(&constructor_wait); + assert(!ret); + } + return 0; +} + +static +int handle_message(struct sock_info *sock_info, + int sock, struct ustcomm_ust_msg *lum) +{ + int ret = 0; + const struct lttng_ust_objd_ops *ops; + struct ustcomm_ust_reply lur; + int shm_fd, wait_fd; + + ust_lock(); + + memset(&lur, 0, sizeof(lur)); + + if (lttng_ust_comm_should_quit) { + ret = -EPERM; + goto end; + } + + ops = objd_ops(lum->handle); + if (!ops) { + ret = -ENOENT; + goto end; + } + + switch (lum->cmd) { + case LTTNG_UST_REGISTER_DONE: + if (lum->handle == LTTNG_UST_ROOT_HANDLE) + ret = handle_register_done(sock_info); + else + ret = -EINVAL; + break; + case LTTNG_UST_RELEASE: + if (lum->handle == LTTNG_UST_ROOT_HANDLE) + ret = -EPERM; + else + ret = lttng_ust_objd_unref(lum->handle); + break; + default: + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &lum->u); + else + ret = -ENOSYS; + break; + } + +end: + lur.handle = lum->handle; + lur.cmd = lum->cmd; + lur.ret_val = ret; + if (ret >= 0) { + lur.ret_code = USTCOMM_OK; + } else { + //lur.ret_code = USTCOMM_SESSION_FAIL; + lur.ret_code = ret; + } + switch (lum->cmd) { + case LTTNG_UST_STREAM: + /* + * Special-case reply to send stream info. + * Use lum.u output. + */ + lur.u.stream.memory_map_size = lum->u.stream.memory_map_size; + shm_fd = lum->u.stream.shm_fd; + wait_fd = lum->u.stream.wait_fd; + break; + case LTTNG_UST_METADATA: + case LTTNG_UST_CHANNEL: + lur.u.channel.memory_map_size = lum->u.channel.memory_map_size; + shm_fd = lum->u.channel.shm_fd; + wait_fd = lum->u.channel.wait_fd; + break; + case LTTNG_UST_VERSION: + lur.u.version = lum->u.version; + break; + } + ret = send_reply(sock, &lur); + if (ret < 0) { + perror("error sending reply"); + goto error; + } + + if ((lum->cmd == LTTNG_UST_STREAM + || lum->cmd == LTTNG_UST_CHANNEL + || lum->cmd == LTTNG_UST_METADATA) + && lur.ret_code == USTCOMM_OK) { + /* we also need to send the file descriptors. */ + ret = ustcomm_send_fds_unix_sock(sock, + &shm_fd, &shm_fd, + 1, sizeof(int)); + if (ret < 0) { + perror("send shm_fd"); + goto error; + } + ret = ustcomm_send_fds_unix_sock(sock, + &wait_fd, &wait_fd, + 1, sizeof(int)); + if (ret < 0) { + perror("send wait_fd"); + goto error; + } + } +error: + ust_unlock(); + return ret; +} + +static +void cleanup_sock_info(struct sock_info *sock_info) +{ + int ret; + + if (sock_info->socket != -1) { + ret = close(sock_info->socket); + if (ret) { + ERR("Error closing apps socket"); + } + sock_info->socket = -1; + } + if (sock_info->root_handle != -1) { + ret = lttng_ust_objd_unref(sock_info->root_handle); + if (ret) { + ERR("Error unref root handle"); + } + sock_info->root_handle = -1; + } + sock_info->constructor_sem_posted = 0; + if (sock_info->wait_shm_mmap) { + ret = munmap(sock_info->wait_shm_mmap, sysconf(_SC_PAGE_SIZE)); + if (ret) { + ERR("Error unmapping wait shm"); + } + sock_info->wait_shm_mmap = NULL; + } +} + +/* + * Using fork to set umask in the child process (not multi-thread safe). + * We deal with the shm_open vs ftruncate race (happening when the + * sessiond owns the shm and does not let everybody modify it, to ensure + * safety against shm_unlink) by simply letting the mmap fail and + * retrying after a few seconds. + * For global shm, everybody has rw access to it until the sessiond + * starts. + */ +static +int get_wait_shm(struct sock_info *sock_info, size_t mmap_size) +{ + int wait_shm_fd, ret; + pid_t pid; + + /* + * Try to open read-only. + */ + wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0); + if (wait_shm_fd >= 0) { + goto end; + } else if (wait_shm_fd < 0 && errno != ENOENT) { + /* + * Real-only open did not work, and it's not because the + * entry was not present. It's a failure that prohibits + * using shm. + */ + ERR("Error opening shm %s", sock_info->wait_shm_path); + goto end; + } + /* + * If the open failed because the file did not exist, try + * creating it ourself. + */ + pid = fork(); + if (pid > 0) { + int status; + + /* + * Parent: wait for child to return, in which case the + * shared memory map will have been created. + */ + pid = wait(&status); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + wait_shm_fd = -1; + goto end; + } + /* + * Try to open read-only again after creation. + */ + wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0); + if (wait_shm_fd < 0) { + /* + * Real-only open did not work. It's a failure + * that prohibits using shm. + */ + ERR("Error opening shm %s", sock_info->wait_shm_path); + goto end; + } + goto end; + } else if (pid == 0) { + int create_mode; + + /* Child */ + create_mode = S_IRUSR | S_IWUSR | S_IRGRP; + if (sock_info->global) + create_mode |= S_IROTH | S_IWGRP | S_IWOTH; + /* + * We're alone in a child process, so we can modify the + * process-wide umask. + */ + umask(~create_mode); + /* + * Try creating shm (or get rw access). + * We don't do an exclusive open, because we allow other + * processes to create+ftruncate it concurrently. + */ + wait_shm_fd = shm_open(sock_info->wait_shm_path, + O_RDWR | O_CREAT, create_mode); + if (wait_shm_fd >= 0) { + ret = ftruncate(wait_shm_fd, mmap_size); + if (ret) { + PERROR("ftruncate"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + /* + * For local shm, we need to have rw access to accept + * opening it: this means the local sessiond will be + * able to wake us up. For global shm, we open it even + * if rw access is not granted, because the root.root + * sessiond will be able to override all rights and wake + * us up. + */ + if (!sock_info->global && errno != EACCES) { + ERR("Error opening shm %s", sock_info->wait_shm_path); + exit(EXIT_FAILURE); + } + /* + * The shm exists, but we cannot open it RW. Report + * success. + */ + exit(EXIT_SUCCESS); + } else { + return -1; + } +end: + if (wait_shm_fd >= 0 && !sock_info->global) { + struct stat statbuf; + + /* + * Ensure that our user is the owner of the shm file for + * local shm. If we do not own the file, it means our + * sessiond will not have access to wake us up (there is + * probably a rogue process trying to fake our + * sessiond). Fallback to polling method in this case. + */ + ret = fstat(wait_shm_fd, &statbuf); + if (ret) { + PERROR("fstat"); + goto error_close; + } + if (statbuf.st_uid != getuid()) + goto error_close; + } + return wait_shm_fd; + +error_close: + ret = close(wait_shm_fd); + if (ret) { + PERROR("Error closing fd"); + } + return -1; +} + +static +char *get_map_shm(struct sock_info *sock_info) +{ + size_t mmap_size = sysconf(_SC_PAGE_SIZE); + int wait_shm_fd, ret; + char *wait_shm_mmap; + + wait_shm_fd = get_wait_shm(sock_info, mmap_size); + if (wait_shm_fd < 0) { + goto error; + } + wait_shm_mmap = mmap(NULL, mmap_size, PROT_READ, + MAP_SHARED, wait_shm_fd, 0); + /* close shm fd immediately after taking the mmap reference */ + ret = close(wait_shm_fd); + if (ret) { + PERROR("Error closing fd"); + } + if (wait_shm_mmap == MAP_FAILED) { + DBG("mmap error (can be caused by race with sessiond). Fallback to poll mode."); + goto error; + } + return wait_shm_mmap; + +error: + return NULL; +} + +static +void wait_for_sessiond(struct sock_info *sock_info) +{ + int ret; + + ust_lock(); + if (lttng_ust_comm_should_quit) { + goto quit; + } + if (wait_poll_fallback) { + goto error; + } + if (!sock_info->wait_shm_mmap) { + sock_info->wait_shm_mmap = get_map_shm(sock_info); + if (!sock_info->wait_shm_mmap) + goto error; + } + ust_unlock(); + + DBG("Waiting for %s apps sessiond", sock_info->name); + /* Wait for futex wakeup */ + if (uatomic_read((int32_t *) sock_info->wait_shm_mmap) == 0) { + ret = futex_async((int32_t *) sock_info->wait_shm_mmap, + FUTEX_WAIT, 0, NULL, NULL, 0); + if (ret < 0) { + if (errno == EFAULT) { + wait_poll_fallback = 1; + WARN( +"Linux kernels 2.6.33 to 3.0 (with the exception of stable versions) " +"do not support FUTEX_WAKE on read-only memory mappings correctly. " +"Please upgrade your kernel " +"(fix is commit 9ea71503a8ed9184d2d0b8ccc4d269d05f7940ae in Linux kernel " +"mainline). LTTng-UST will use polling mode fallback."); + } + PERROR("futex"); + } + } + return; + +quit: + ust_unlock(); + return; + +error: + ust_unlock(); + return; +} + +/* + * This thread does not allocate any resource, except within + * handle_message, within mutex protection. This mutex protects against + * fork and exit. + * The other moment it allocates resources is at socket connexion, which + * is also protected by the mutex. + */ +static +void *ust_listener_thread(void *arg) +{ + struct sock_info *sock_info = arg; + int sock, ret, prev_connect_failed = 0, has_waited = 0; + + /* Restart trying to connect to the session daemon */ +restart: + if (prev_connect_failed) { + /* Wait for sessiond availability with pipe */ + wait_for_sessiond(sock_info); + if (has_waited) { + has_waited = 0; + /* + * Sleep for 5 seconds before retrying after a + * sequence of failure / wait / failure. This + * deals with a killed or broken session daemon. + */ + sleep(5); + } + has_waited = 1; + prev_connect_failed = 0; + } + ust_lock(); + + if (lttng_ust_comm_should_quit) { + ust_unlock(); + goto quit; + } + + if (sock_info->socket != -1) { + ret = close(sock_info->socket); + if (ret) { + ERR("Error closing %s apps socket", sock_info->name); + } + sock_info->socket = -1; + } + + /* Register */ + ret = ustcomm_connect_unix_sock(sock_info->sock_path); + if (ret < 0) { + ERR("Error connecting to %s apps socket", sock_info->name); + prev_connect_failed = 1; + /* + * If we cannot find the sessiond daemon, don't delay + * constructor execution. + */ + ret = handle_register_done(sock_info); + assert(!ret); + ust_unlock(); + goto restart; + } + + sock_info->socket = sock = ret; + + /* + * Create only one root handle per listener thread for the whole + * process lifetime. + */ + if (sock_info->root_handle == -1) { + ret = lttng_abi_create_root_handle(); + if (ret < 0) { + ERR("Error creating root handle"); + ust_unlock(); + goto quit; + } + sock_info->root_handle = ret; + } + + ret = register_app_to_sessiond(sock); + if (ret < 0) { + ERR("Error registering to %s apps socket", sock_info->name); + prev_connect_failed = 1; + /* + * If we cannot register to the sessiond daemon, don't + * delay constructor execution. + */ + ret = handle_register_done(sock_info); + assert(!ret); + ust_unlock(); + goto restart; + } + ust_unlock(); + + for (;;) { + ssize_t len; + struct ustcomm_ust_msg lum; + + len = ustcomm_recv_unix_sock(sock, &lum, sizeof(lum)); + switch (len) { + case 0: /* orderly shutdown */ + DBG("%s ltt-sessiond has performed an orderly shutdown\n", sock_info->name); + goto end; + case sizeof(lum): + DBG("message received\n"); + ret = handle_message(sock_info, sock, &lum); + if (ret < 0) { + ERR("Error handling message for %s socket", sock_info->name); + } + continue; + case -1: + if (errno == ECONNRESET) { + ERR("%s remote end closed connection\n", sock_info->name); + goto end; + } + goto end; + default: + ERR("incorrect message size (%s socket): %zd\n", sock_info->name, len); + continue; + } + + } +end: + goto restart; /* try to reconnect */ +quit: + return NULL; +} + +/* + * Return values: -1: don't wait. 0: wait forever. 1: timeout wait. + */ +static +int get_timeout(struct timespec *constructor_timeout) +{ + long constructor_delay_ms = LTTNG_UST_DEFAULT_CONSTRUCTOR_TIMEOUT_MS; + char *str_delay; + int ret; + + str_delay = getenv("LTTNG_UST_REGISTER_TIMEOUT"); + if (str_delay) { + constructor_delay_ms = strtol(str_delay, NULL, 10); + } + + switch (constructor_delay_ms) { + case -1:/* fall-through */ + case 0: + return constructor_delay_ms; + default: + break; + } + + /* + * If we are unable to find the current time, don't wait. + */ + ret = clock_gettime(CLOCK_REALTIME, constructor_timeout); + if (ret) { + return -1; + } + constructor_timeout->tv_sec += constructor_delay_ms / 1000UL; + constructor_timeout->tv_nsec += + (constructor_delay_ms % 1000UL) * 1000000UL; + if (constructor_timeout->tv_nsec >= 1000000000UL) { + constructor_timeout->tv_sec++; + constructor_timeout->tv_nsec -= 1000000000UL; + } + return 1; +} + +/* + * sessiond monitoring thread: monitor presence of global and per-user + * sessiond by polling the application common named pipe. + */ +/* TODO */ + +void __attribute__((constructor)) lttng_ust_init(void) +{ + struct timespec constructor_timeout; + int timeout_mode; + int ret; + + if (uatomic_xchg(&initialized, 1) == 1) + return; + + /* + * We want precise control over the order in which we construct + * our sub-libraries vs starting to receive commands from + * sessiond (otherwise leading to errors when trying to create + * sessiond before the init functions are completed). + */ + init_usterr(); + init_tracepoint(); + ltt_ring_buffer_metadata_client_init(); + ltt_ring_buffer_client_overwrite_init(); + ltt_ring_buffer_client_discard_init(); + + timeout_mode = get_timeout(&constructor_timeout); + + ret = sem_init(&constructor_wait, 0, 0); + assert(!ret); + + ret = setup_local_apps(); + if (ret) { + ERR("Error setting up to local apps"); + } + ret = pthread_create(&local_apps.ust_listener, NULL, + ust_listener_thread, &local_apps); + + if (local_apps.allowed) { + ret = pthread_create(&global_apps.ust_listener, NULL, + ust_listener_thread, &global_apps); + } else { + handle_register_done(&local_apps); + } + + switch (timeout_mode) { + case 1: /* timeout wait */ + do { + ret = sem_timedwait(&constructor_wait, + &constructor_timeout); + } while (ret < 0 && errno == EINTR); + if (ret < 0 && errno == ETIMEDOUT) { + ERR("Timed out waiting for ltt-sessiond"); + } else { + assert(!ret); + } + break; + case -1:/* wait forever */ + do { + ret = sem_wait(&constructor_wait); + } while (ret < 0 && errno == EINTR); + assert(!ret); + break; + case 0: /* no timeout */ + break; + } +} + +static +void lttng_ust_cleanup(int exiting) +{ + cleanup_sock_info(&global_apps); + if (local_apps.allowed) { + cleanup_sock_info(&local_apps); + } + lttng_ust_abi_exit(); + lttng_ust_events_exit(); + ltt_ring_buffer_client_discard_exit(); + ltt_ring_buffer_client_overwrite_exit(); + ltt_ring_buffer_metadata_client_exit(); + exit_tracepoint(); + if (!exiting) { + /* Reinitialize values for fork */ + sem_count = 2; + lttng_ust_comm_should_quit = 0; + initialized = 0; + } +} + +void __attribute__((destructor)) lttng_ust_exit(void) +{ + int ret; + + /* + * Using pthread_cancel here because: + * A) we don't want to hang application teardown. + * B) the thread is not allocating any resource. + */ + + /* + * Require the communication thread to quit. Synchronize with + * mutexes to ensure it is not in a mutex critical section when + * pthread_cancel is later called. + */ + ust_lock(); + lttng_ust_comm_should_quit = 1; + ust_unlock(); + + ret = pthread_cancel(global_apps.ust_listener); + if (ret) { + ERR("Error cancelling global ust listener thread"); + } + if (local_apps.allowed) { + ret = pthread_cancel(local_apps.ust_listener); + if (ret) { + ERR("Error cancelling local ust listener thread"); + } + } + lttng_ust_cleanup(1); +} + +/* + * We exclude the worker threads across fork and clone (except + * CLONE_VM), because these system calls only keep the forking thread + * running in the child. Therefore, we don't want to call fork or clone + * in the middle of an tracepoint or ust tracing state modification. + * Holding this mutex protects these structures across fork and clone. + */ +void ust_before_fork(ust_fork_info_t *fork_info) +{ + /* + * Disable signals. This is to avoid that the child intervenes + * before it is properly setup for tracing. It is safer to + * disable all signals, because then we know we are not breaking + * anything by restoring the original mask. + */ + sigset_t all_sigs; + int ret; + + /* Disable signals */ + sigfillset(&all_sigs); + ret = sigprocmask(SIG_BLOCK, &all_sigs, &fork_info->orig_sigs); + if (ret == -1) { + PERROR("sigprocmask"); + } + ust_lock(); + rcu_bp_before_fork(); +} + +static void ust_after_fork_common(ust_fork_info_t *fork_info) +{ + int ret; + + DBG("process %d", getpid()); + ust_unlock(); + /* Restore signals */ + ret = sigprocmask(SIG_SETMASK, &fork_info->orig_sigs, NULL); + if (ret == -1) { + PERROR("sigprocmask"); + } +} + +void ust_after_fork_parent(ust_fork_info_t *fork_info) +{ + DBG("process %d", getpid()); + rcu_bp_after_fork_parent(); + /* Release mutexes and reenable signals */ + ust_after_fork_common(fork_info); +} + +/* + * After fork, in the child, we need to cleanup all the leftover state, + * except the worker thread which already magically disappeared thanks + * to the weird Linux fork semantics. After tyding up, we call + * lttng_ust_init() again to start over as a new PID. + * + * This is meant for forks() that have tracing in the child between the + * fork and following exec call (if there is any). + */ +void ust_after_fork_child(ust_fork_info_t *fork_info) +{ + DBG("process %d", getpid()); + /* Release urcu mutexes */ + rcu_bp_after_fork_child(); + lttng_ust_cleanup(0); + lttng_context_vtid_reset(); + /* Release mutexes and reenable signals */ + ust_after_fork_common(fork_info); + lttng_ust_init(); +} diff --git a/liblttng-ust/probes/lttng-probe-ust.c b/liblttng-ust/probes/lttng-probe-ust.c new file mode 100644 index 00000000..a5fba868 --- /dev/null +++ b/liblttng-ust/probes/lttng-probe-ust.c @@ -0,0 +1,16 @@ +/* + * probes/lttng-probe-ust.c + * + * Copyright 2010 (c) - Mathieu Desnoyers + * + * LTTng UST core probes. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +/* + * Create LTTng tracepoint probes. + */ +#define TRACEPOINT_CREATE_PROBES + +#include "lttng-probe-ust.h" diff --git a/liblttng-ust/probes/lttng-probe-ust.h b/liblttng-ust/probes/lttng-probe-ust.h new file mode 100644 index 00000000..3394d086 --- /dev/null +++ b/liblttng-ust/probes/lttng-probe-ust.h @@ -0,0 +1,51 @@ +#undef TRACEPOINT_SYSTEM +#define TRACEPOINT_SYSTEM lttng_ust + +#if !defined(_TRACEPOINT_LTTNG_UST_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define _TRACEPOINT_LTTNG_UST_H + +/* + * Copyright (C) 2011 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 of + * the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +TRACEPOINT_EVENT(lttng_metadata, + + TP_PROTO(const char *str), + + TP_ARGS(str), + + /* + * Not exactly a string: more a sequence of bytes (dynamic + * array) without the length. This is a dummy anyway: we only + * use this declaration to generate an event metadata entry. + */ + TP_FIELDS( + ctf_string(str, str) + ) +) + +#undef TRACEPOINT_INCLUDE_PATH +#define TRACEPOINT_INCLUDE_PATH ./probes +#undef TRACEPOINT_INCLUDE_FILE +#define TRACEPOINT_INCLUDE_FILE lttng-probe-ust + +#endif /* _TRACEPOINT_LTTNG_UST_H */ + +/* This part must be outside protection */ +#include diff --git a/liblttng-ust/tracepoint.c b/liblttng-ust/tracepoint.c new file mode 100644 index 00000000..8bf87528 --- /dev/null +++ b/liblttng-ust/tracepoint.c @@ -0,0 +1,669 @@ +/* + * Copyright (C) 2008-2011 Mathieu Desnoyers + * Copyright (C) 2009 Pierre-Marc Fournier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Ported to userspace by Pierre-Marc Fournier. + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ltt-tracer-core.h" + +/* Set to 1 to enable tracepoint debug output */ +static const int tracepoint_debug; +static int initialized; +static void (*new_tracepoint_cb)(struct tracepoint *); + +/* libraries that contain tracepoints (struct tracepoint_lib) */ +static CDS_LIST_HEAD(libs); + +/* + * The UST lock protects the library tracepoints, the hash table, and + * the library list. + * All calls to the tracepoint API must be protected by the UST lock, + * excepts calls to tracepoint_register_lib and + * tracepoint_unregister_lib, which take the UST lock themselves. + */ + +/* + * Tracepoint hash table, containing the active tracepoints. + * Protected by tracepoints_mutex. + */ +#define TRACEPOINT_HASH_BITS 6 +#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) +static struct cds_hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE]; + +static CDS_LIST_HEAD(old_probes); +static int need_update; + +/* + * Note about RCU : + * It is used to to delay the free of multiple probes array until a quiescent + * state is reached. + * Tracepoint entries modifications are protected by the tracepoints_mutex. + */ +struct tracepoint_entry { + struct cds_hlist_node hlist; + struct tracepoint_probe *probes; + int refcount; /* Number of times armed. 0 if disarmed. */ + char name[0]; +}; + +struct tp_probes { + union { + struct cds_list_head list; + } u; + struct tracepoint_probe probes[0]; +}; + +static inline void *allocate_probes(int count) +{ + struct tp_probes *p = zmalloc(count * sizeof(struct tracepoint_probe) + + sizeof(struct tp_probes)); + return p == NULL ? NULL : p->probes; +} + +static inline void release_probes(void *old) +{ + if (old) { + struct tp_probes *tp_probes = _ust_container_of(old, + struct tp_probes, probes[0]); + synchronize_rcu(); + free(tp_probes); + } +} + +static void debug_print_probes(struct tracepoint_entry *entry) +{ + int i; + + if (!tracepoint_debug || !entry->probes) + return; + + for (i = 0; entry->probes[i].func; i++) + DBG("Probe %d : %p", i, entry->probes[i].func); +} + +static void * +tracepoint_entry_add_probe(struct tracepoint_entry *entry, + void *probe, void *data) +{ + int nr_probes = 0; + struct tracepoint_probe *old, *new; + + WARN_ON(!probe); + + debug_print_probes(entry); + old = entry->probes; + if (old) { + /* (N -> N+1), (N != 0, 1) probes */ + for (nr_probes = 0; old[nr_probes].func; nr_probes++) + if (old[nr_probes].func == probe && + old[nr_probes].data == data) + return ERR_PTR(-EEXIST); + } + /* + 2 : one for new probe, one for NULL func */ + new = allocate_probes(nr_probes + 2); + if (new == NULL) + return ERR_PTR(-ENOMEM); + if (old) + memcpy(new, old, nr_probes * sizeof(struct tracepoint_probe)); + new[nr_probes].func = probe; + new[nr_probes].data = data; + new[nr_probes + 1].func = NULL; + entry->refcount = nr_probes + 1; + entry->probes = new; + debug_print_probes(entry); + return old; +} + +static void * +tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe, + void *data) +{ + int nr_probes = 0, nr_del = 0, i; + struct tracepoint_probe *old, *new; + + old = entry->probes; + + if (!old) + return ERR_PTR(-ENOENT); + + debug_print_probes(entry); + /* (N -> M), (N > 1, M >= 0) probes */ + for (nr_probes = 0; old[nr_probes].func; nr_probes++) { + if (!probe || + (old[nr_probes].func == probe && + old[nr_probes].data == data)) + nr_del++; + } + + if (nr_probes - nr_del == 0) { + /* N -> 0, (N > 1) */ + entry->probes = NULL; + entry->refcount = 0; + debug_print_probes(entry); + return old; + } else { + int j = 0; + /* N -> M, (N > 1, M > 0) */ + /* + 1 for NULL */ + new = allocate_probes(nr_probes - nr_del + 1); + if (new == NULL) + return ERR_PTR(-ENOMEM); + for (i = 0; old[i].func; i++) + if (probe && + (old[i].func != probe || old[i].data != data)) + new[j++] = old[i]; + new[nr_probes - nr_del].func = NULL; + entry->refcount = nr_probes - nr_del; + entry->probes = new; + } + debug_print_probes(entry); + return old; +} + +/* + * Get tracepoint if the tracepoint is present in the tracepoint hash table. + * Must be called with tracepoints_mutex held. + * Returns NULL if not present. + */ +static struct tracepoint_entry *get_tracepoint(const char *name) +{ + struct cds_hlist_head *head; + struct cds_hlist_node *node; + struct tracepoint_entry *e; + u32 hash = jhash(name, strlen(name), 0); + + head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; + cds_hlist_for_each_entry(e, node, head, hlist) { + if (!strcmp(name, e->name)) + return e; + } + return NULL; +} + +/* + * Add the tracepoint to the tracepoint hash table. Must be called with + * tracepoints_mutex held. + */ +static struct tracepoint_entry *add_tracepoint(const char *name) +{ + struct cds_hlist_head *head; + struct cds_hlist_node *node; + struct tracepoint_entry *e; + size_t name_len = strlen(name) + 1; + u32 hash = jhash(name, name_len-1, 0); + + head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; + cds_hlist_for_each_entry(e, node, head, hlist) { + if (!strcmp(name, e->name)) { + DBG("tracepoint %s busy", name); + return ERR_PTR(-EEXIST); /* Already there */ + } + } + /* + * Using zmalloc here to allocate a variable length element. Could + * cause some memory fragmentation if overused. + */ + e = zmalloc(sizeof(struct tracepoint_entry) + name_len); + if (!e) + return ERR_PTR(-ENOMEM); + memcpy(&e->name[0], name, name_len); + e->probes = NULL; + e->refcount = 0; + cds_hlist_add_head(&e->hlist, head); + return e; +} + +/* + * Remove the tracepoint from the tracepoint hash table. Must be called with + * ust_lock held. + */ +static inline void remove_tracepoint(struct tracepoint_entry *e) +{ + cds_hlist_del(&e->hlist); + free(e); +} + +/* + * Sets the probe callback corresponding to one tracepoint. + */ +static void set_tracepoint(struct tracepoint_entry **entry, + struct tracepoint *elem, int active) +{ + WARN_ON(strcmp((*entry)->name, elem->name) != 0); + + /* + * rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new + * probe callbacks array is consistent before setting a pointer to it. + * This array is referenced by __DO_TRACE from + * include/linux/tracepoints.h. A matching cmm_smp_read_barrier_depends() + * is used. + */ + rcu_assign_pointer(elem->probes, (*entry)->probes); + elem->state = active; +} + +/* + * Disable a tracepoint and its probe callback. + * Note: only waiting an RCU period after setting elem->call to the empty + * function insures that the original callback is not used anymore. This insured + * by preempt_disable around the call site. + */ +static void disable_tracepoint(struct tracepoint *elem) +{ + elem->state = 0; + rcu_assign_pointer(elem->probes, NULL); +} + +/** + * tracepoint_update_probe_range - Update a probe range + * @begin: beginning of the range + * @end: end of the range + * + * Updates the probe callback corresponding to a range of tracepoints. + */ +static +void tracepoint_update_probe_range(struct tracepoint * const *begin, + struct tracepoint * const *end) +{ + struct tracepoint * const *iter; + struct tracepoint_entry *mark_entry; + + for (iter = begin; iter < end; iter++) { + if (!*iter) + continue; /* skip dummy */ + if (!(*iter)->name) { + disable_tracepoint(*iter); + continue; + } + mark_entry = get_tracepoint((*iter)->name); + if (mark_entry) { + set_tracepoint(&mark_entry, *iter, + !!mark_entry->refcount); + } else { + disable_tracepoint(*iter); + } + } +} + +static void lib_update_tracepoints(void) +{ + struct tracepoint_lib *lib; + + cds_list_for_each_entry(lib, &libs, list) { + tracepoint_update_probe_range(lib->tracepoints_start, + lib->tracepoints_start + lib->tracepoints_count); + } +} + +/* + * Update probes, removing the faulty probes. + */ +static void tracepoint_update_probes(void) +{ + /* tracepoints registered from libraries and executable. */ + lib_update_tracepoints(); +} + +static struct tracepoint_probe * +tracepoint_add_probe(const char *name, void *probe, void *data) +{ + struct tracepoint_entry *entry; + struct tracepoint_probe *old; + + entry = get_tracepoint(name); + if (!entry) { + entry = add_tracepoint(name); + if (IS_ERR(entry)) + return (struct tracepoint_probe *)entry; + } + old = tracepoint_entry_add_probe(entry, probe, data); + if (IS_ERR(old) && !entry->refcount) + remove_tracepoint(entry); + return old; +} + +/** + * __tracepoint_probe_register - Connect a probe to a tracepoint + * @name: tracepoint name + * @probe: probe handler + * + * Returns 0 if ok, error value on error. + * The probe address must at least be aligned on the architecture pointer size. + * Called with the UST lock held. + */ +int __tracepoint_probe_register(const char *name, void *probe, void *data) +{ + void *old; + + old = tracepoint_add_probe(name, probe, data); + if (IS_ERR(old)) + return PTR_ERR(old); + + tracepoint_update_probes(); /* may update entry */ + release_probes(old); + return 0; +} + +static void *tracepoint_remove_probe(const char *name, void *probe, void *data) +{ + struct tracepoint_entry *entry; + void *old; + + entry = get_tracepoint(name); + if (!entry) + return ERR_PTR(-ENOENT); + old = tracepoint_entry_remove_probe(entry, probe, data); + if (IS_ERR(old)) + return old; + if (!entry->refcount) + remove_tracepoint(entry); + return old; +} + +/** + * tracepoint_probe_unregister - Disconnect a probe from a tracepoint + * @name: tracepoint name + * @probe: probe function pointer + * @probe: probe data pointer + * + * Called with the UST lock held. + */ +int __tracepoint_probe_unregister(const char *name, void *probe, void *data) +{ + void *old; + + old = tracepoint_remove_probe(name, probe, data); + if (IS_ERR(old)) + return PTR_ERR(old); + + tracepoint_update_probes(); /* may update entry */ + release_probes(old); + return 0; +} + +static void tracepoint_add_old_probes(void *old) +{ + need_update = 1; + if (old) { + struct tp_probes *tp_probes = _ust_container_of(old, + struct tp_probes, probes[0]); + cds_list_add(&tp_probes->u.list, &old_probes); + } +} + +/** + * tracepoint_probe_register_noupdate - register a probe but not connect + * @name: tracepoint name + * @probe: probe handler + * + * caller must call tracepoint_probe_update_all() + * Called with the UST lock held. + */ +int tracepoint_probe_register_noupdate(const char *name, void *probe, + void *data) +{ + void *old; + + old = tracepoint_add_probe(name, probe, data); + if (IS_ERR(old)) { + return PTR_ERR(old); + } + tracepoint_add_old_probes(old); + return 0; +} + +/** + * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect + * @name: tracepoint name + * @probe: probe function pointer + * + * caller must call tracepoint_probe_update_all() + * Called with the UST lock held. + */ +int tracepoint_probe_unregister_noupdate(const char *name, void *probe, + void *data) +{ + void *old; + + old = tracepoint_remove_probe(name, probe, data); + if (IS_ERR(old)) { + return PTR_ERR(old); + } + tracepoint_add_old_probes(old); + return 0; +} + +/** + * tracepoint_probe_update_all - update tracepoints + * Called with the UST lock held. + */ +void tracepoint_probe_update_all(void) +{ + CDS_LIST_HEAD(release_probes); + struct tp_probes *pos, *next; + + if (!need_update) { + return; + } + if (!cds_list_empty(&old_probes)) + cds_list_replace_init(&old_probes, &release_probes); + need_update = 0; + + tracepoint_update_probes(); + cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) { + cds_list_del(&pos->u.list); + synchronize_rcu(); + free(pos); + } +} + +/* + * Returns 0 if current not found. + * Returns 1 if current found. + * + * Called with tracepoint mutex held + */ +int lib_get_iter_tracepoints(struct tracepoint_iter *iter) +{ + struct tracepoint_lib *iter_lib; + int found = 0; + + cds_list_for_each_entry(iter_lib, &libs, list) { + if (iter_lib < iter->lib) + continue; + else if (iter_lib > iter->lib) + iter->tracepoint = NULL; + found = tracepoint_get_iter_range(&iter->tracepoint, + iter_lib->tracepoints_start, + iter_lib->tracepoints_start + iter_lib->tracepoints_count); + if (found) { + iter->lib = iter_lib; + break; + } + } + return found; +} + +/** + * tracepoint_get_iter_range - Get a next tracepoint iterator given a range. + * @tracepoint: current tracepoints (in), next tracepoint (out) + * @begin: beginning of the range + * @end: end of the range + * + * Returns whether a next tracepoint has been found (1) or not (0). + * Will return the first tracepoint in the range if the input tracepoint is + * NULL. + * Called with tracepoint mutex held. + */ +int tracepoint_get_iter_range(struct tracepoint * const **tracepoint, + struct tracepoint * const *begin, struct tracepoint * const *end) +{ + if (!*tracepoint && begin != end) + *tracepoint = begin; + while (*tracepoint >= begin && *tracepoint < end) { + if (!**tracepoint) + (*tracepoint)++; /* skip dummy */ + else + return 1; + } + return 0; +} + +/* + * Called with tracepoint mutex held. + */ +static void tracepoint_get_iter(struct tracepoint_iter *iter) +{ + int found = 0; + + /* tracepoints in libs. */ + found = lib_get_iter_tracepoints(iter); + if (!found) + tracepoint_iter_reset(iter); +} + +/* + * Called with UST lock held. + */ +void tracepoint_iter_start(struct tracepoint_iter *iter) +{ + tracepoint_get_iter(iter); +} + +/* + * Called with UST lock held. + */ +void tracepoint_iter_next(struct tracepoint_iter *iter) +{ + iter->tracepoint++; + /* + * iter->tracepoint may be invalid because we blindly incremented it. + * Make sure it is valid by marshalling on the tracepoints, getting the + * tracepoints from following modules if necessary. + */ + tracepoint_get_iter(iter); +} + +/* + * Called with UST lock held. + */ +void tracepoint_iter_stop(struct tracepoint_iter *iter) +{ +} + +void tracepoint_iter_reset(struct tracepoint_iter *iter) +{ + iter->tracepoint = NULL; +} + +void tracepoint_set_new_tracepoint_cb(void (*cb)(struct tracepoint *)) +{ + new_tracepoint_cb = cb; +} + +static void new_tracepoints(struct tracepoint * const *start, struct tracepoint * const *end) +{ + if (new_tracepoint_cb) { + struct tracepoint * const *t; + + for (t = start; t < end; t++) { + if (*t) + new_tracepoint_cb(*t); + } + } +} + +int tracepoint_register_lib(struct tracepoint * const *tracepoints_start, + int tracepoints_count) +{ + struct tracepoint_lib *pl, *iter; + + init_tracepoint(); + + pl = (struct tracepoint_lib *) zmalloc(sizeof(struct tracepoint_lib)); + + pl->tracepoints_start = tracepoints_start; + pl->tracepoints_count = tracepoints_count; + + ust_lock(); + /* + * We sort the libs by struct lib pointer address. + */ + cds_list_for_each_entry_reverse(iter, &libs, list) { + BUG_ON(iter == pl); /* Should never be in the list twice */ + if (iter < pl) { + /* We belong to the location right after iter. */ + cds_list_add(&pl->list, &iter->list); + goto lib_added; + } + } + /* We should be added at the head of the list */ + cds_list_add(&pl->list, &libs); +lib_added: + new_tracepoints(tracepoints_start, tracepoints_start + tracepoints_count); + + /* TODO: update just the loaded lib */ + lib_update_tracepoints(); + ust_unlock(); + + DBG("just registered a tracepoints section from %p and having %d tracepoints", + tracepoints_start, tracepoints_count); + + return 0; +} + +int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start) +{ + struct tracepoint_lib *lib; + + ust_lock(); + cds_list_for_each_entry(lib, &libs, list) { + if (lib->tracepoints_start == tracepoints_start) { + struct tracepoint_lib *lib2free = lib; + cds_list_del(&lib->list); + free(lib2free); + break; + } + } + ust_unlock(); + + return 0; +} + +void init_tracepoint(void) +{ + if (uatomic_xchg(&initialized, 1) == 1) + return; + init_usterr(); +} + +void exit_tracepoint(void) +{ + initialized = 0; +} diff --git a/liblttng-ust/ust-core.c b/liblttng-ust/ust-core.c new file mode 100644 index 00000000..404e0b26 --- /dev/null +++ b/liblttng-ust/ust-core.c @@ -0,0 +1,37 @@ +/* + * ust-core.c + * + * Copyright (C) 2011 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +volatile enum ust_loglevel ust_loglevel; + +void init_usterr(void) +{ + char *ust_debug; + + if (ust_loglevel == UST_LOGLEVEL_UNKNOWN) { + ust_debug = getenv("LTTNG_UST_DEBUG"); + if (ust_debug) + ust_loglevel = UST_LOGLEVEL_DEBUG; + else + ust_loglevel = UST_LOGLEVEL_NORMAL; + } +} diff --git a/libust/Makefile.am b/libust/Makefile.am deleted file mode 100644 index 9295d6b7..00000000 --- a/libust/Makefile.am +++ /dev/null @@ -1,38 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -AM_CFLAGS = -fno-strict-aliasing - -lib_LTLIBRARIES = libust.la - -libust_la_SOURCES = \ - tracepoint.c \ - ltt-tracer.h \ - ltt-tracer-core.h \ - ltt-ring-buffer-client.h \ - ltt-ring-buffer-client-discard.c \ - ltt-ring-buffer-client-overwrite.c \ - ltt-ring-buffer-metadata-client.h \ - ltt-ring-buffer-metadata-client.c \ - ltt-events.c \ - ltt-probes.c \ - lttng-ust-abi.c \ - lttng-ust-comm.c \ - ust-core.c \ - probes/lttng-probe-ust.c \ - probes/lttng-probe-ust.h \ - lttng-context-vtid.c \ - lttng-context-vpid.c \ - lttng-context-pthread-id.c \ - lttng-context-procname.c \ - ltt-context.c - -libust_la_LDFLAGS = -no-undefined -version-info 0:0:0 - -libust_la_LIBADD = \ - -lpthread \ - -lrt \ - -luuid \ - $(top_builddir)/snprintf/libustsnprintf.la \ - $(top_builddir)/libringbuffer/libringbuffer.la \ - $(top_builddir)/liblttng-ust-comm/liblttng-ust-comm.la - -libust_la_CFLAGS = -DUST_COMPONENT="libust" -fno-strict-aliasing diff --git a/libust/ltt-context.c b/libust/ltt-context.c deleted file mode 100644 index 90747a55..00000000 --- a/libust/ltt-context.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * ltt-context.c - * - * Copyright 2011 (c) - Mathieu Desnoyers - * - * LTTng UST trace/channel/event context management. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include -#include -#include -#include -#include - -int lttng_find_context(struct lttng_ctx *ctx, const char *name) -{ - unsigned int i; - - for (i = 0; i < ctx->nr_fields; i++) { - /* Skip allocated (but non-initialized) contexts */ - if (!ctx->fields[i].event_field.name) - continue; - if (!strcmp(ctx->fields[i].event_field.name, name)) - return 1; - } - return 0; -} - -/* - * Note: as we append context information, the pointer location may change. - */ -struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p) -{ - struct lttng_ctx_field *field; - struct lttng_ctx *ctx; - - if (!*ctx_p) { - *ctx_p = zmalloc(sizeof(struct lttng_ctx)); - if (!*ctx_p) - return NULL; - } - ctx = *ctx_p; - if (ctx->nr_fields + 1 > ctx->allocated_fields) { - struct lttng_ctx_field *new_fields; - - ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields); - new_fields = zmalloc(ctx->allocated_fields * sizeof(struct lttng_ctx_field)); - if (!new_fields) - return NULL; - if (ctx->fields) - memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields); - free(ctx->fields); - ctx->fields = new_fields; - } - field = &ctx->fields[ctx->nr_fields]; - ctx->nr_fields++; - return field; -} - -/* - * Remove last context field. - */ -void lttng_remove_context_field(struct lttng_ctx **ctx_p, - struct lttng_ctx_field *field) -{ - struct lttng_ctx *ctx; - - ctx = *ctx_p; - ctx->nr_fields--; - assert(&ctx->fields[ctx->nr_fields] == field); - memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field)); -} - -void lttng_destroy_context(struct lttng_ctx *ctx) -{ - int i; - - if (!ctx) - return; - for (i = 0; i < ctx->nr_fields; i++) { - if (ctx->fields[i].destroy) - ctx->fields[i].destroy(&ctx->fields[i]); - } - free(ctx->fields); - free(ctx); -} diff --git a/libust/ltt-events.c b/libust/ltt-events.c deleted file mode 100644 index 68531bcd..00000000 --- a/libust/ltt-events.c +++ /dev/null @@ -1,1010 +0,0 @@ -/* - * ltt-events.c - * - * Copyright 2010 (c) - Mathieu Desnoyers - * - * Holds LTTng per-session event registry. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lttng/core.h" -#include "ltt-tracer.h" -#include "ltt-tracer-core.h" -#include "lttng/wait.h" -#include "../libringbuffer/shm.h" - -typedef u32 uint32_t; -#include - -/* - * The sessions mutex is the centralized mutex across UST tracing - * control and probe registration. All operations within this file are - * called by the communication thread, under ust_lock protection. - */ -static DEFINE_MUTEX(sessions_mutex); - -void ust_lock(void) -{ - pthread_mutex_lock(&sessions_mutex); -} - -void ust_unlock(void) -{ - pthread_mutex_unlock(&sessions_mutex); -} - -static CDS_LIST_HEAD(sessions); -static CDS_LIST_HEAD(ltt_transport_list); - -/* - * Pending probes hash table, containing the registered ltt events for - * which tracepoint probes are still missing. Protected by the sessions - * mutex. - */ -#define PENDING_PROBE_HASH_BITS 6 -#define PENDING_PROBE_HASH_SIZE (1 << PENDING_PROBE_HASH_BITS) -static struct cds_hlist_head pending_probe_table[PENDING_PROBE_HASH_SIZE]; - -struct ust_pending_probe { - struct ltt_event *event; - struct cds_hlist_node node; - char name[]; -}; - -static void _ltt_event_destroy(struct ltt_event *event); -static void _ltt_channel_destroy(struct ltt_channel *chan); -static int _ltt_event_unregister(struct ltt_event *event); -static -int _ltt_event_metadata_statedump(struct ltt_session *session, - struct ltt_channel *chan, - struct ltt_event *event); -static -int _ltt_session_metadata_statedump(struct ltt_session *session); - -/* - * called at event creation if probe is missing. - * called with session mutex held. - */ -static -int add_pending_probe(struct ltt_event *event, const char *name) -{ - struct cds_hlist_head *head; - struct ust_pending_probe *e; - size_t name_len = strlen(name) + 1; - u32 hash = jhash(name, name_len - 1, 0); - - head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)]; - e = zmalloc(sizeof(struct ust_pending_probe) + name_len); - if (!e) - return -ENOMEM; - memcpy(&e->name[0], name, name_len); - cds_hlist_add_head(&e->node, head); - e->event = event; - event->pending_probe = e; - return 0; -} - -/* - * remove a pending probe. called when at event teardown and when an - * event is fixed (probe is loaded). - * called with session mutex held. - */ -static -void remove_pending_probe(struct ust_pending_probe *e) -{ - if (!e) - return; - cds_hlist_del(&e->node); - free(e); -} - -/* - * Called at library load: connect the probe on the events pending on - * probe load. - * called with session mutex held. - */ -int pending_probe_fix_events(const struct lttng_event_desc *desc) -{ - struct cds_hlist_head *head; - struct cds_hlist_node *node, *p; - struct ust_pending_probe *e; - const char *name = desc->name; - size_t name_len = strlen(name) + 1; - u32 hash = jhash(name, name_len - 1, 0); - int ret = 0; - - head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)]; - cds_hlist_for_each_entry_safe(e, node, p, head, node) { - struct ltt_event *event; - struct ltt_channel *chan; - - if (strcmp(name, e->name)) - continue; - event = e->event; - chan = event->chan; - assert(!event->desc); - event->desc = desc; - event->pending_probe = NULL; - remove_pending_probe(e); - ret |= __tracepoint_probe_register(name, - event->desc->probe_callback, - event); - if (ret) - continue; - event->id = chan->free_event_id++; - ret |= _ltt_event_metadata_statedump(chan->session, chan, - event); - } - return ret; -} - -void synchronize_trace(void) -{ - synchronize_rcu(); -} - -struct ltt_session *ltt_session_create(void) -{ - struct ltt_session *session; - - session = zmalloc(sizeof(struct ltt_session)); - if (!session) - return NULL; - CDS_INIT_LIST_HEAD(&session->chan); - CDS_INIT_LIST_HEAD(&session->events); - uuid_generate(session->uuid); - cds_list_add(&session->list, &sessions); - return session; -} - -void ltt_session_destroy(struct ltt_session *session) -{ - struct ltt_channel *chan, *tmpchan; - struct ltt_event *event, *tmpevent; - int ret; - - CMM_ACCESS_ONCE(session->active) = 0; - cds_list_for_each_entry(event, &session->events, list) { - ret = _ltt_event_unregister(event); - WARN_ON(ret); - } - synchronize_trace(); /* Wait for in-flight events to complete */ - cds_list_for_each_entry_safe(event, tmpevent, &session->events, list) - _ltt_event_destroy(event); - cds_list_for_each_entry_safe(chan, tmpchan, &session->chan, list) - _ltt_channel_destroy(chan); - cds_list_del(&session->list); - free(session); -} - -int ltt_session_enable(struct ltt_session *session) -{ - int ret = 0; - struct ltt_channel *chan; - - if (session->active) { - ret = -EBUSY; - goto end; - } - - /* - * Snapshot the number of events per channel to know the type of header - * we need to use. - */ - cds_list_for_each_entry(chan, &session->chan, list) { - if (chan->header_type) - continue; /* don't change it if session stop/restart */ - if (chan->free_event_id < 31) - chan->header_type = 1; /* compact */ - else - chan->header_type = 2; /* large */ - } - - CMM_ACCESS_ONCE(session->active) = 1; - CMM_ACCESS_ONCE(session->been_active) = 1; - ret = _ltt_session_metadata_statedump(session); - if (ret) - CMM_ACCESS_ONCE(session->active) = 0; -end: - return ret; -} - -int ltt_session_disable(struct ltt_session *session) -{ - int ret = 0; - - if (!session->active) { - ret = -EBUSY; - goto end; - } - CMM_ACCESS_ONCE(session->active) = 0; -end: - return ret; -} - -int ltt_channel_enable(struct ltt_channel *channel) -{ - int old; - - if (channel == channel->session->metadata) - return -EPERM; - old = uatomic_xchg(&channel->enabled, 1); - if (old) - return -EEXIST; - return 0; -} - -int ltt_channel_disable(struct ltt_channel *channel) -{ - int old; - - if (channel == channel->session->metadata) - return -EPERM; - old = uatomic_xchg(&channel->enabled, 0); - if (!old) - return -EEXIST; - return 0; -} - -int ltt_event_enable(struct ltt_event *event) -{ - int old; - - if (event->chan == event->chan->session->metadata) - return -EPERM; - old = uatomic_xchg(&event->enabled, 1); - if (old) - return -EEXIST; - return 0; -} - -int ltt_event_disable(struct ltt_event *event) -{ - int old; - - if (event->chan == event->chan->session->metadata) - return -EPERM; - old = uatomic_xchg(&event->enabled, 0); - if (!old) - return -EEXIST; - return 0; -} - -static struct ltt_transport *ltt_transport_find(const char *name) -{ - struct ltt_transport *transport; - - cds_list_for_each_entry(transport, <t_transport_list, node) { - if (!strcmp(transport->name, name)) - return transport; - } - return NULL; -} - -struct ltt_channel *ltt_channel_create(struct ltt_session *session, - const char *transport_name, - void *buf_addr, - size_t subbuf_size, size_t num_subbuf, - unsigned int switch_timer_interval, - unsigned int read_timer_interval, - int *shm_fd, int *wait_fd, - uint64_t *memory_map_size) -{ - struct ltt_channel *chan; - struct ltt_transport *transport; - - if (session->been_active) - goto active; /* Refuse to add channel to active session */ - transport = ltt_transport_find(transport_name); - if (!transport) { - DBG("LTTng transport %s not found\n", - transport_name); - goto notransport; - } - chan = zmalloc(sizeof(struct ltt_channel)); - if (!chan) - goto nomem; - chan->session = session; - chan->id = session->free_chan_id++; - /* - * Note: the channel creation op already writes into the packet - * headers. Therefore the "chan" information used as input - * should be already accessible. - */ - transport->ops.channel_create("[lttng]", chan, buf_addr, - subbuf_size, num_subbuf, switch_timer_interval, - read_timer_interval, shm_fd, wait_fd, - memory_map_size); - if (!chan->chan) - goto create_error; - chan->enabled = 1; - chan->ops = &transport->ops; - cds_list_add(&chan->list, &session->chan); - return chan; - -create_error: - free(chan); -nomem: -notransport: -active: - return NULL; -} - -/* - * Only used internally at session destruction. - */ -static -void _ltt_channel_destroy(struct ltt_channel *chan) -{ - chan->ops->channel_destroy(chan); - cds_list_del(&chan->list); - lttng_destroy_context(chan->ctx); - free(chan); -} - -/* - * Supports event creation while tracing session is active. - */ -struct ltt_event *ltt_event_create(struct ltt_channel *chan, - struct lttng_ust_event *event_param, - void *filter) -{ - struct ltt_event *event; - int ret; - - if (chan->used_event_id == -1UL) - goto full; - /* - * This is O(n^2) (for each event, the loop is called at event - * creation). Might require a hash if we have lots of events. - */ - cds_list_for_each_entry(event, &chan->session->events, list) - if (event->desc && !strcmp(event->desc->name, event_param->name)) - goto exist; - event = zmalloc(sizeof(struct ltt_event)); - if (!event) - goto cache_error; - event->chan = chan; - event->filter = filter; - /* - * used_event_id counts the maximum number of event IDs that can - * register if all probes register. - */ - chan->used_event_id++; - event->enabled = 1; - event->instrumentation = event_param->instrumentation; - /* Populate ltt_event structure before tracepoint registration. */ - cmm_smp_wmb(); - switch (event_param->instrumentation) { - case LTTNG_UST_TRACEPOINT: - event->desc = ltt_event_get(event_param->name); - if (event->desc) { - ret = __tracepoint_probe_register(event_param->name, - event->desc->probe_callback, - event); - if (ret) - goto register_error; - event->id = chan->free_event_id++; - } else { - /* - * If the probe is not present, event->desc stays NULL, - * waiting for the probe to register, and the event->id - * stays unallocated. - */ - ret = add_pending_probe(event, event_param->name); - if (ret) - goto add_pending_error; - } - break; - default: - WARN_ON_ONCE(1); - } - if (event->desc) { - ret = _ltt_event_metadata_statedump(chan->session, chan, event); - if (ret) - goto statedump_error; - } - cds_list_add(&event->list, &chan->session->events); - return event; - -statedump_error: - if (event->desc) { - WARN_ON_ONCE(__tracepoint_probe_unregister(event_param->name, - event->desc->probe_callback, - event)); - ltt_event_put(event->desc); - } -add_pending_error: -register_error: - free(event); -cache_error: -exist: -full: - return NULL; -} - -/* - * Only used internally at session destruction. - */ -int _ltt_event_unregister(struct ltt_event *event) -{ - int ret = -EINVAL; - - switch (event->instrumentation) { - case LTTNG_UST_TRACEPOINT: - if (event->desc) { - ret = __tracepoint_probe_unregister(event->desc->name, - event->desc->probe_callback, - event); - if (ret) - return ret; - } else { - remove_pending_probe(event->pending_probe); - ret = 0; - } - break; - default: - WARN_ON_ONCE(1); - } - return ret; -} - -/* - * Only used internally at session destruction. - */ -static -void _ltt_event_destroy(struct ltt_event *event) -{ - switch (event->instrumentation) { - case LTTNG_UST_TRACEPOINT: - if (event->desc) { - ltt_event_put(event->desc); - } - break; - default: - WARN_ON_ONCE(1); - } - cds_list_del(&event->list); - lttng_destroy_context(event->ctx); - free(event); -} - -/* - * We have exclusive access to our metadata buffer (protected by the - * ust_lock), so we can do racy operations such as looking for - * remaining space left in packet and write, since mutual exclusion - * protects us from concurrent writes. - */ -int lttng_metadata_printf(struct ltt_session *session, - const char *fmt, ...) -{ - struct lttng_ust_lib_ring_buffer_ctx ctx; - struct ltt_channel *chan = session->metadata; - char *str = NULL; - int ret = 0, waitret; - size_t len, reserve_len, pos; - va_list ap; - - WARN_ON_ONCE(!CMM_ACCESS_ONCE(session->active)); - - va_start(ap, fmt); - ret = vasprintf(&str, fmt, ap); - va_end(ap); - if (ret < 0) - return -ENOMEM; - - len = strlen(str); - pos = 0; - - for (pos = 0; pos < len; pos += reserve_len) { - reserve_len = min_t(size_t, - chan->ops->packet_avail_size(chan->chan, chan->handle), - len - pos); - lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len, - sizeof(char), -1, chan->handle); - /* - * We don't care about metadata buffer's records lost - * count, because we always retry here. Report error if - * we need to bail out after timeout or being - * interrupted. - */ - waitret = wait_cond_interruptible_timeout( - ({ - ret = chan->ops->event_reserve(&ctx, 0); - ret != -ENOBUFS || !ret; - }), - LTTNG_METADATA_TIMEOUT_MSEC); - if (waitret == -ETIMEDOUT || waitret == -EINTR || ret) { - DBG("LTTng: Failure to write metadata to buffers (%s)\n", - waitret == -EINTR ? "interrupted" : - (ret == -ENOBUFS ? "timeout" : "I/O error")); - if (waitret == -EINTR) - ret = waitret; - goto end; - } - chan->ops->event_write(&ctx, &str[pos], reserve_len); - chan->ops->event_commit(&ctx); - } -end: - free(str); - return ret; -} - -static -int _ltt_field_statedump(struct ltt_session *session, - const struct lttng_event_field *field) -{ - int ret = 0; - - switch (field->type.atype) { - case atype_integer: - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s;\n", - field->type.u.basic.integer.size, - field->type.u.basic.integer.alignment, - field->type.u.basic.integer.signedness, - (field->type.u.basic.integer.encoding == lttng_encode_none) - ? "none" - : (field->type.u.basic.integer.encoding == lttng_encode_UTF8) - ? "UTF8" - : "ASCII", - field->type.u.basic.integer.base, -#if (BYTE_ORDER == BIG_ENDIAN) - field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", -#else - field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", -#endif - field->name); - break; - case atype_float: - ret = lttng_metadata_printf(session, - " floating_point { exp_dig = %u; mant_dig = %u; align = %u;%s } _%s;\n", - field->type.u.basic._float.exp_dig, - field->type.u.basic._float.mant_dig, - field->type.u.basic._float.alignment, -#if (BYTE_ORDER == BIG_ENDIAN) - field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", -#else - field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", -#endif - field->name); - break; - case atype_enum: - ret = lttng_metadata_printf(session, - " %s %s;\n", - field->type.u.basic.enumeration.name, - field->name); - break; - case atype_array: - { - const struct lttng_basic_type *elem_type; - - elem_type = &field->type.u.array.elem_type; - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[%u];\n", - elem_type->u.basic.integer.size, - elem_type->u.basic.integer.alignment, - elem_type->u.basic.integer.signedness, - (elem_type->u.basic.integer.encoding == lttng_encode_none) - ? "none" - : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8) - ? "UTF8" - : "ASCII", - elem_type->u.basic.integer.base, -#if (BYTE_ORDER == BIG_ENDIAN) - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", -#else - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", -#endif - field->name, field->type.u.array.length); - break; - } - case atype_sequence: - { - const struct lttng_basic_type *elem_type; - const struct lttng_basic_type *length_type; - - elem_type = &field->type.u.sequence.elem_type; - length_type = &field->type.u.sequence.length_type; - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n", - length_type->u.basic.integer.size, - (unsigned int) length_type->u.basic.integer.alignment, - length_type->u.basic.integer.signedness, - (length_type->u.basic.integer.encoding == lttng_encode_none) - ? "none" - : ((length_type->u.basic.integer.encoding == lttng_encode_UTF8) - ? "UTF8" - : "ASCII"), - length_type->u.basic.integer.base, -#if (BYTE_ORDER == BIG_ENDIAN) - length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", -#else - length_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", -#endif - field->name); - if (ret) - return ret; - - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[ __%s_length ];\n", - elem_type->u.basic.integer.size, - (unsigned int) elem_type->u.basic.integer.alignment, - elem_type->u.basic.integer.signedness, - (elem_type->u.basic.integer.encoding == lttng_encode_none) - ? "none" - : ((elem_type->u.basic.integer.encoding == lttng_encode_UTF8) - ? "UTF8" - : "ASCII"), - elem_type->u.basic.integer.base, -#if (BYTE_ORDER == BIG_ENDIAN) - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", -#else - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", -#endif - field->name, - field->name); - break; - } - - case atype_string: - /* Default encoding is UTF8 */ - ret = lttng_metadata_printf(session, - " string%s _%s;\n", - field->type.u.basic.string.encoding == lttng_encode_ASCII ? - " { encoding = ASCII; }" : "", - field->name); - break; - default: - WARN_ON_ONCE(1); - return -EINVAL; - } - return ret; -} - -static -int _ltt_context_metadata_statedump(struct ltt_session *session, - struct lttng_ctx *ctx) -{ - int ret = 0; - int i; - - if (!ctx) - return 0; - for (i = 0; i < ctx->nr_fields; i++) { - const struct lttng_ctx_field *field = &ctx->fields[i]; - - ret = _ltt_field_statedump(session, &field->event_field); - if (ret) - return ret; - } - return ret; -} - -static -int _ltt_fields_metadata_statedump(struct ltt_session *session, - struct ltt_event *event) -{ - const struct lttng_event_desc *desc = event->desc; - int ret = 0; - int i; - - for (i = 0; i < desc->nr_fields; i++) { - const struct lttng_event_field *field = &desc->fields[i]; - - ret = _ltt_field_statedump(session, field); - if (ret) - return ret; - } - return ret; -} - -static -int _ltt_event_metadata_statedump(struct ltt_session *session, - struct ltt_channel *chan, - struct ltt_event *event) -{ - int ret = 0; - - if (event->metadata_dumped || !CMM_ACCESS_ONCE(session->active)) - return 0; - if (chan == session->metadata) - return 0; - /* - * Don't print events for which probe load is pending. - */ - if (!event->desc) - return 0; - - ret = lttng_metadata_printf(session, - "event {\n" - " name = %s;\n" - " id = %u;\n" - " stream_id = %u;\n", - event->desc->name, - event->id, - event->chan->id); - if (ret) - goto end; - - if (event->ctx) { - ret = lttng_metadata_printf(session, - " context := struct {\n"); - if (ret) - goto end; - } - ret = _ltt_context_metadata_statedump(session, event->ctx); - if (ret) - goto end; - if (event->ctx) { - ret = lttng_metadata_printf(session, - " };\n"); - if (ret) - goto end; - } - - ret = lttng_metadata_printf(session, - " fields := struct {\n" - ); - if (ret) - goto end; - - ret = _ltt_fields_metadata_statedump(session, event); - if (ret) - goto end; - - /* - * LTTng space reservation can only reserve multiples of the - * byte size. - */ - ret = lttng_metadata_printf(session, - " };\n" - "};\n\n"); - if (ret) - goto end; - - event->metadata_dumped = 1; -end: - return ret; - -} - -static -int _ltt_channel_metadata_statedump(struct ltt_session *session, - struct ltt_channel *chan) -{ - int ret = 0; - - if (chan->metadata_dumped || !CMM_ACCESS_ONCE(session->active)) - return 0; - if (chan == session->metadata) - return 0; - - WARN_ON_ONCE(!chan->header_type); - ret = lttng_metadata_printf(session, - "stream {\n" - " id = %u;\n" - " event.header := %s;\n" - " packet.context := struct packet_context;\n", - chan->id, - chan->header_type == 1 ? "struct event_header_compact" : - "struct event_header_large"); - if (ret) - goto end; - - if (chan->ctx) { - ret = lttng_metadata_printf(session, - " event.context := struct {\n"); - if (ret) - goto end; - } - ret = _ltt_context_metadata_statedump(session, chan->ctx); - if (ret) - goto end; - if (chan->ctx) { - ret = lttng_metadata_printf(session, - " };\n"); - if (ret) - goto end; - } - - ret = lttng_metadata_printf(session, - "};\n\n"); - - chan->metadata_dumped = 1; -end: - return ret; -} - -static -int _ltt_stream_packet_context_declare(struct ltt_session *session) -{ - return lttng_metadata_printf(session, - "struct packet_context {\n" - " uint64_t timestamp_begin;\n" - " uint64_t timestamp_end;\n" - " uint32_t events_discarded;\n" - " uint32_t content_size;\n" - " uint32_t packet_size;\n" - " uint32_t cpu_id;\n" - "};\n\n" - ); -} - -/* - * Compact header: - * id: range: 0 - 30. - * id 31 is reserved to indicate an extended header. - * - * Large header: - * id: range: 0 - 65534. - * id 65535 is reserved to indicate an extended header. - */ -static -int _ltt_event_header_declare(struct ltt_session *session) -{ - return lttng_metadata_printf(session, - "struct event_header_compact {\n" - " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n" - " variant {\n" - " struct {\n" - " uint27_t timestamp;\n" - " } compact;\n" - " struct {\n" - " uint32_t id;\n" - " uint64_t timestamp;\n" - " } extended;\n" - " } v;\n" - "} align(%u);\n" - "\n" - "struct event_header_large {\n" - " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n" - " variant {\n" - " struct {\n" - " uint32_t timestamp;\n" - " } compact;\n" - " struct {\n" - " uint32_t id;\n" - " uint64_t timestamp;\n" - " } extended;\n" - " } v;\n" - "} align(%u);\n\n", - lttng_alignof(uint32_t) * CHAR_BIT, - lttng_alignof(uint16_t) * CHAR_BIT - ); -} - -/* - * Output metadata into this session's metadata buffers. - */ -static -int _ltt_session_metadata_statedump(struct ltt_session *session) -{ - unsigned char *uuid_c = session->uuid; - char uuid_s[37]; - struct ltt_channel *chan; - struct ltt_event *event; - int ret = 0; - - if (!CMM_ACCESS_ONCE(session->active)) - return 0; - if (session->metadata_dumped) - goto skip_session; - if (!session->metadata) { - DBG("LTTng: attempt to start tracing, but metadata channel is not found. Operation abort.\n"); - return -EPERM; - } - - snprintf(uuid_s, sizeof(uuid_s), - "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3], - uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7], - uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11], - uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]); - - ret = lttng_metadata_printf(session, - "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n" - "typealias integer { size = 16; align = %u; signed = false; } := uint16_t;\n" - "typealias integer { size = 32; align = %u; signed = false; } := uint32_t;\n" - "typealias integer { size = 64; align = %u; signed = false; } := uint64_t;\n" - "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n" - "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n" - "\n" - "trace {\n" - " major = %u;\n" - " minor = %u;\n" - " uuid = \"%s\";\n" - " byte_order = %s;\n" - " packet.header := struct {\n" - " uint32_t magic;\n" - " uint8_t uuid[16];\n" - " uint32_t stream_id;\n" - " };\n" - "};\n\n", - lttng_alignof(uint8_t) * CHAR_BIT, - lttng_alignof(uint16_t) * CHAR_BIT, - lttng_alignof(uint32_t) * CHAR_BIT, - lttng_alignof(uint64_t) * CHAR_BIT, - CTF_VERSION_MAJOR, - CTF_VERSION_MINOR, - uuid_s, -#if (BYTE_ORDER == BIG_ENDIAN) - "be" -#else - "le" -#endif - ); - if (ret) - goto end; - - ret = _ltt_stream_packet_context_declare(session); - if (ret) - goto end; - - ret = _ltt_event_header_declare(session); - if (ret) - goto end; - -skip_session: - cds_list_for_each_entry(chan, &session->chan, list) { - ret = _ltt_channel_metadata_statedump(session, chan); - if (ret) - goto end; - } - - cds_list_for_each_entry(event, &session->events, list) { - ret = _ltt_event_metadata_statedump(session, event->chan, event); - if (ret) - goto end; - } - session->metadata_dumped = 1; -end: - return ret; -} - -/** - * ltt_transport_register - LTT transport registration - * @transport: transport structure - * - * Registers a transport which can be used as output to extract the data out of - * LTTng. Called with ust_lock held. - */ -void ltt_transport_register(struct ltt_transport *transport) -{ - cds_list_add_tail(&transport->node, <t_transport_list); -} - -/** - * ltt_transport_unregister - LTT transport unregistration - * @transport: transport structure - * Called with ust_lock held. - */ -void ltt_transport_unregister(struct ltt_transport *transport) -{ - cds_list_del(&transport->node); -} - -void lttng_ust_events_exit(void) -{ - struct ltt_session *session, *tmpsession; - - cds_list_for_each_entry_safe(session, tmpsession, &sessions, list) - ltt_session_destroy(session); -} diff --git a/libust/ltt-probes.c b/libust/ltt-probes.c deleted file mode 100644 index 66ee971c..00000000 --- a/libust/ltt-probes.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * ltt-probes.c - * - * Copyright 2010 (c) - Mathieu Desnoyers - * - * Holds LTTng probes registry. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include -#include -#include -#include -#include - -#include "ltt-tracer-core.h" - -/* - * probe list is protected by ust_lock()/ust_unlock(). - */ -static CDS_LIST_HEAD(probe_list); - -static -const struct lttng_event_desc *find_event(const char *name) -{ - struct lttng_probe_desc *probe_desc; - int i; - - cds_list_for_each_entry(probe_desc, &probe_list, head) { - for (i = 0; i < probe_desc->nr_events; i++) { - if (!strcmp(probe_desc->event_desc[i].name, name)) - return &probe_desc->event_desc[i]; - } - } - return NULL; -} - -int ltt_probe_register(struct lttng_probe_desc *desc) -{ - int ret = 0; - int i; - - ust_lock(); - /* - * TODO: This is O(N^2). Turn into a hash table when probe registration - * overhead becomes an issue. - */ - for (i = 0; i < desc->nr_events; i++) { - if (find_event(desc->event_desc[i].name)) { - ret = -EEXIST; - goto end; - } - } - cds_list_add(&desc->head, &probe_list); - - /* - * fix the events awaiting probe load. - */ - for (i = 0; i < desc->nr_events; i++) { - ret = pending_probe_fix_events(&desc->event_desc[i]); - assert(!ret); - } -end: - ust_unlock(); - return ret; -} - -void ltt_probe_unregister(struct lttng_probe_desc *desc) -{ - ust_lock(); - cds_list_del(&desc->head); - ust_unlock(); -} - -/* - * called with UST lock held. - */ -const struct lttng_event_desc *ltt_event_get(const char *name) -{ - const struct lttng_event_desc *event; - - event = find_event(name); - if (!event) - return NULL; - return event; -} - -void ltt_event_put(const struct lttng_event_desc *event) -{ -} - -#if 0 -static -void *tp_list_start(struct seq_file *m, loff_t *pos) -{ - struct lttng_probe_desc *probe_desc; - int iter = 0, i; - - pthread_mutex_lock(&probe_mutex); - cds_list_for_each_entry(probe_desc, &probe_list, head) { - for (i = 0; i < probe_desc->nr_events; i++) { - if (iter++ >= *pos) - return (void *) &probe_desc->event_desc[i]; - } - } - /* End of list */ - return NULL; -} - -static -void *tp_list_next(struct seq_file *m, void *p, loff_t *ppos) -{ - struct lttng_probe_desc *probe_desc; - int iter = 0, i; - - (*ppos)++; - cds_list_for_each_entry(probe_desc, &probe_list, head) { - for (i = 0; i < probe_desc->nr_events; i++) { - if (iter++ >= *ppos) - return (void *) &probe_desc->event_desc[i]; - } - } - /* End of list */ - return NULL; -} - -static -void tp_list_stop(struct seq_file *m, void *p) -{ - pthread_mutex_unlock(&probe_mutex); -} - -static -int tp_list_show(struct seq_file *m, void *p) -{ - const struct lttng_event_desc *probe_desc = p; - - /* - * Don't export lttng internal events (metadata). - */ - if (!strncmp(probe_desc->name, "lttng_", sizeof("lttng_") - 1)) - return 0; - seq_printf(m, "event { name = %s; };\n", - probe_desc->name); - return 0; -} - -static -const struct seq_operations lttng_tracepoint_list_seq_ops = { - .start = tp_list_start, - .next = tp_list_next, - .stop = tp_list_stop, - .show = tp_list_show, -}; - -static -int lttng_tracepoint_list_open(struct inode *inode, struct file *file) -{ - return seq_open(file, <tng_tracepoint_list_seq_ops); -} - -const struct file_operations lttng_tracepoint_list_fops = { - .open = lttng_tracepoint_list_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif //0 diff --git a/libust/ltt-ring-buffer-client-discard.c b/libust/ltt-ring-buffer-client-discard.c deleted file mode 100644 index e89026c7..00000000 --- a/libust/ltt-ring-buffer-client-discard.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * ltt-ring-buffer-client-discard.c - * - * Copyright (C) 2010 - Mathieu Desnoyers - * - * LTTng lib ring buffer client (discard mode). - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include "ltt-tracer.h" - -#define RING_BUFFER_MODE_TEMPLATE RING_BUFFER_DISCARD -#define RING_BUFFER_MODE_TEMPLATE_STRING "discard" -#define RING_BUFFER_MODE_TEMPLATE_INIT \ - ltt_ring_buffer_client_discard_init -#define RING_BUFFER_MODE_TEMPLATE_EXIT \ - ltt_ring_buffer_client_discard_exit -#include "ltt-ring-buffer-client.h" diff --git a/libust/ltt-ring-buffer-client-overwrite.c b/libust/ltt-ring-buffer-client-overwrite.c deleted file mode 100644 index 8590a7ee..00000000 --- a/libust/ltt-ring-buffer-client-overwrite.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * ltt-ring-buffer-client-overwrite.c - * - * Copyright (C) 2010 - Mathieu Desnoyers - * - * LTTng lib ring buffer client (overwrite mode). - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include "ltt-tracer.h" - -#define RING_BUFFER_MODE_TEMPLATE RING_BUFFER_OVERWRITE -#define RING_BUFFER_MODE_TEMPLATE_STRING "overwrite" -#define RING_BUFFER_MODE_TEMPLATE_INIT \ - ltt_ring_buffer_client_overwrite_init -#define RING_BUFFER_MODE_TEMPLATE_EXIT \ - ltt_ring_buffer_client_overwrite_exit -#include "ltt-ring-buffer-client.h" diff --git a/libust/ltt-ring-buffer-client.h b/libust/ltt-ring-buffer-client.h deleted file mode 100644 index a1bc8c32..00000000 --- a/libust/ltt-ring-buffer-client.h +++ /dev/null @@ -1,554 +0,0 @@ -/* - * ltt-ring-buffer-client.h - * - * Copyright (C) 2010 - Mathieu Desnoyers - * - * LTTng lib ring buffer client template. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include -#include -#include "lttng/bitfield.h" -#include "lttng/clock.h" -#include "ltt-tracer.h" -#include "../libringbuffer/frontend_types.h" - -/* - * Keep the natural field alignment for _each field_ within this structure if - * you ever add/remove a field from this header. Packed attribute is not used - * because gcc generates poor code on at least powerpc and mips. Don't ever - * let gcc add padding between the structure elements. - */ - -struct packet_header { - /* Trace packet header */ - uint32_t magic; /* - * Trace magic number. - * contains endianness information. - */ - uint8_t uuid[16]; - uint32_t stream_id; - - struct { - /* Stream packet context */ - uint64_t timestamp_begin; /* Cycle count at subbuffer start */ - uint64_t timestamp_end; /* Cycle count at subbuffer end */ - uint32_t events_discarded; /* - * Events lost in this subbuffer since - * the beginning of the trace. - * (may overflow) - */ - uint32_t content_size; /* Size of data in subbuffer */ - uint32_t packet_size; /* Subbuffer size (include padding) */ - uint32_t cpu_id; /* CPU id associated with stream */ - uint8_t header_end; /* End of header */ - } ctx; -}; - - -static inline notrace u64 lib_ring_buffer_clock_read(struct channel *chan) -{ - return trace_clock_read64(); -} - -static inline -size_t ctx_get_size(size_t offset, struct lttng_ctx *ctx) -{ - int i; - size_t orig_offset = offset; - - if (caa_likely(!ctx)) - return 0; - for (i = 0; i < ctx->nr_fields; i++) - offset += ctx->fields[i].get_size(offset); - return offset - orig_offset; -} - -static inline -void ctx_record(struct lttng_ust_lib_ring_buffer_ctx *bufctx, - struct ltt_channel *chan, - struct lttng_ctx *ctx) -{ - int i; - - if (caa_likely(!ctx)) - return; - for (i = 0; i < ctx->nr_fields; i++) - ctx->fields[i].record(&ctx->fields[i], bufctx, chan); -} - -/* - * record_header_size - Calculate the header size and padding necessary. - * @config: ring buffer instance configuration - * @chan: channel - * @offset: offset in the write buffer - * @pre_header_padding: padding to add before the header (output) - * @ctx: reservation context - * - * Returns the event header size (including padding). - * - * The payload must itself determine its own alignment from the biggest type it - * contains. - */ -static __inline__ -unsigned char record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, - struct channel *chan, size_t offset, - size_t *pre_header_padding, - struct lttng_ust_lib_ring_buffer_ctx *ctx) -{ - struct ltt_channel *ltt_chan = channel_get_private(chan); - struct ltt_event *event = ctx->priv; - size_t orig_offset = offset; - size_t padding; - - switch (ltt_chan->header_type) { - case 1: /* compact */ - padding = lib_ring_buffer_align(offset, lttng_alignof(uint32_t)); - offset += padding; - if (!(ctx->rflags & (RING_BUFFER_RFLAG_FULL_TSC | LTT_RFLAG_EXTENDED))) { - offset += sizeof(uint32_t); /* id and timestamp */ - } else { - /* Minimum space taken by 5-bit id */ - offset += sizeof(uint8_t); - /* Align extended struct on largest member */ - offset += lib_ring_buffer_align(offset, lttng_alignof(uint64_t)); - offset += sizeof(uint32_t); /* id */ - offset += lib_ring_buffer_align(offset, lttng_alignof(uint64_t)); - offset += sizeof(uint64_t); /* timestamp */ - } - break; - case 2: /* large */ - padding = lib_ring_buffer_align(offset, lttng_alignof(uint16_t)); - offset += padding; - offset += sizeof(uint16_t); - if (!(ctx->rflags & (RING_BUFFER_RFLAG_FULL_TSC | LTT_RFLAG_EXTENDED))) { - offset += lib_ring_buffer_align(offset, lttng_alignof(uint32_t)); - offset += sizeof(uint32_t); /* timestamp */ - } else { - /* Align extended struct on largest member */ - offset += lib_ring_buffer_align(offset, lttng_alignof(uint64_t)); - offset += sizeof(uint32_t); /* id */ - offset += lib_ring_buffer_align(offset, lttng_alignof(uint64_t)); - offset += sizeof(uint64_t); /* timestamp */ - } - break; - default: - padding = 0; - WARN_ON_ONCE(1); - } - offset += ctx_get_size(offset, event->ctx); - offset += ctx_get_size(offset, ltt_chan->ctx); - - *pre_header_padding = padding; - return offset - orig_offset; -} - -#include "../libringbuffer/api.h" - -static -void ltt_write_event_header_slow(const struct lttng_ust_lib_ring_buffer_config *config, - struct lttng_ust_lib_ring_buffer_ctx *ctx, - uint32_t event_id); - -/* - * ltt_write_event_header - * - * Writes the event header to the offset (already aligned on 32-bits). - * - * @config: ring buffer instance configuration - * @ctx: reservation context - * @event_id: event ID - */ -static __inline__ -void ltt_write_event_header(const struct lttng_ust_lib_ring_buffer_config *config, - struct lttng_ust_lib_ring_buffer_ctx *ctx, - uint32_t event_id) -{ - struct ltt_channel *ltt_chan = channel_get_private(ctx->chan); - struct ltt_event *event = ctx->priv; - - if (caa_unlikely(ctx->rflags)) - goto slow_path; - - switch (ltt_chan->header_type) { - case 1: /* compact */ - { - uint32_t id_time = 0; - - bt_bitfield_write(&id_time, uint32_t, 0, 5, event_id); - bt_bitfield_write(&id_time, uint32_t, 5, 27, ctx->tsc); - lib_ring_buffer_write(config, ctx, &id_time, sizeof(id_time)); - break; - } - case 2: /* large */ - { - uint32_t timestamp = (uint32_t) ctx->tsc; - uint16_t id = event_id; - - lib_ring_buffer_write(config, ctx, &id, sizeof(id)); - lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint32_t)); - lib_ring_buffer_write(config, ctx, ×tamp, sizeof(timestamp)); - break; - } - default: - WARN_ON_ONCE(1); - } - - ctx_record(ctx, ltt_chan, ltt_chan->ctx); - ctx_record(ctx, ltt_chan, event->ctx); - lib_ring_buffer_align_ctx(ctx, ctx->largest_align); - - return; - -slow_path: - ltt_write_event_header_slow(config, ctx, event_id); -} - -static -void ltt_write_event_header_slow(const struct lttng_ust_lib_ring_buffer_config *config, - struct lttng_ust_lib_ring_buffer_ctx *ctx, - uint32_t event_id) -{ - struct ltt_channel *ltt_chan = channel_get_private(ctx->chan); - struct ltt_event *event = ctx->priv; - - switch (ltt_chan->header_type) { - case 1: /* compact */ - if (!(ctx->rflags & (RING_BUFFER_RFLAG_FULL_TSC | LTT_RFLAG_EXTENDED))) { - uint32_t id_time = 0; - - bt_bitfield_write(&id_time, uint32_t, 0, 5, event_id); - bt_bitfield_write(&id_time, uint32_t, 5, 27, ctx->tsc); - lib_ring_buffer_write(config, ctx, &id_time, sizeof(id_time)); - } else { - uint8_t id = 0; - uint64_t timestamp = ctx->tsc; - - bt_bitfield_write(&id, uint8_t, 0, 5, 31); - lib_ring_buffer_write(config, ctx, &id, sizeof(id)); - /* Align extended struct on largest member */ - lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint64_t)); - lib_ring_buffer_write(config, ctx, &event_id, sizeof(event_id)); - lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint64_t)); - lib_ring_buffer_write(config, ctx, ×tamp, sizeof(timestamp)); - } - break; - case 2: /* large */ - { - if (!(ctx->rflags & (RING_BUFFER_RFLAG_FULL_TSC | LTT_RFLAG_EXTENDED))) { - uint32_t timestamp = (uint32_t) ctx->tsc; - uint16_t id = event_id; - - lib_ring_buffer_write(config, ctx, &id, sizeof(id)); - lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint32_t)); - lib_ring_buffer_write(config, ctx, ×tamp, sizeof(timestamp)); - } else { - uint16_t id = 65535; - uint64_t timestamp = ctx->tsc; - - lib_ring_buffer_write(config, ctx, &id, sizeof(id)); - /* Align extended struct on largest member */ - lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint64_t)); - lib_ring_buffer_write(config, ctx, &event_id, sizeof(event_id)); - lib_ring_buffer_align_ctx(ctx, lttng_alignof(uint64_t)); - lib_ring_buffer_write(config, ctx, ×tamp, sizeof(timestamp)); - } - break; - } - default: - WARN_ON_ONCE(1); - } - ctx_record(ctx, ltt_chan, ltt_chan->ctx); - ctx_record(ctx, ltt_chan, event->ctx); - lib_ring_buffer_align_ctx(ctx, ctx->largest_align); -} - -static const struct lttng_ust_lib_ring_buffer_config client_config; - -static u64 client_ring_buffer_clock_read(struct channel *chan) -{ - return lib_ring_buffer_clock_read(chan); -} - -static -size_t client_record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, - struct channel *chan, size_t offset, - size_t *pre_header_padding, - struct lttng_ust_lib_ring_buffer_ctx *ctx) -{ - return record_header_size(config, chan, offset, - pre_header_padding, ctx); -} - -/** - * client_packet_header_size - called on buffer-switch to a new sub-buffer - * - * Return header size without padding after the structure. Don't use packed - * structure because gcc generates inefficient code on some architectures - * (powerpc, mips..) - */ -static size_t client_packet_header_size(void) -{ - return offsetof(struct packet_header, ctx.header_end); -} - -static void client_buffer_begin(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, - unsigned int subbuf_idx, - struct lttng_ust_shm_handle *handle) -{ - struct channel *chan = shmp(handle, buf->backend.chan); - struct packet_header *header = - (struct packet_header *) - lib_ring_buffer_offset_address(&buf->backend, - subbuf_idx * chan->backend.subbuf_size, - handle); - struct ltt_channel *ltt_chan = channel_get_private(chan); - struct ltt_session *session = ltt_chan->session; - - header->magic = CTF_MAGIC_NUMBER; - memcpy(header->uuid, session->uuid, sizeof(session->uuid)); - header->stream_id = ltt_chan->id; - header->ctx.timestamp_begin = tsc; - header->ctx.timestamp_end = 0; - header->ctx.events_discarded = 0; - header->ctx.content_size = 0xFFFFFFFF; /* for debugging */ - header->ctx.packet_size = 0xFFFFFFFF; - header->ctx.cpu_id = buf->backend.cpu; -} - -/* - * offset is assumed to never be 0 here : never deliver a completely empty - * subbuffer. data_size is between 1 and subbuf_size. - */ -static void client_buffer_end(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, - unsigned int subbuf_idx, unsigned long data_size, - struct lttng_ust_shm_handle *handle) -{ - struct channel *chan = shmp(handle, buf->backend.chan); - struct packet_header *header = - (struct packet_header *) - lib_ring_buffer_offset_address(&buf->backend, - subbuf_idx * chan->backend.subbuf_size, - handle); - unsigned long records_lost = 0; - - header->ctx.timestamp_end = tsc; - header->ctx.content_size = data_size * CHAR_BIT; /* in bits */ - header->ctx.packet_size = PAGE_ALIGN(data_size) * CHAR_BIT; /* in bits */ - /* - * We do not care about the records lost count, because the metadata - * channel waits and retry. - */ - (void) lib_ring_buffer_get_records_lost_full(&client_config, buf); - records_lost += lib_ring_buffer_get_records_lost_wrap(&client_config, buf); - records_lost += lib_ring_buffer_get_records_lost_big(&client_config, buf); - header->ctx.events_discarded = records_lost; -} - -static int client_buffer_create(struct lttng_ust_lib_ring_buffer *buf, void *priv, - int cpu, const char *name, struct lttng_ust_shm_handle *handle) -{ - return 0; -} - -static void client_buffer_finalize(struct lttng_ust_lib_ring_buffer *buf, void *priv, int cpu, struct lttng_ust_shm_handle *handle) -{ -} - -static const struct lttng_ust_lib_ring_buffer_config client_config = { - .cb.ring_buffer_clock_read = client_ring_buffer_clock_read, - .cb.record_header_size = client_record_header_size, - .cb.subbuffer_header_size = client_packet_header_size, - .cb.buffer_begin = client_buffer_begin, - .cb.buffer_end = client_buffer_end, - .cb.buffer_create = client_buffer_create, - .cb.buffer_finalize = client_buffer_finalize, - - .tsc_bits = 32, - .alloc = RING_BUFFER_ALLOC_PER_CPU, - .sync = RING_BUFFER_SYNC_GLOBAL, - .mode = RING_BUFFER_MODE_TEMPLATE, - .backend = RING_BUFFER_PAGE, - .output = RING_BUFFER_MMAP, - .oops = RING_BUFFER_OOPS_CONSISTENCY, - .ipi = RING_BUFFER_NO_IPI_BARRIER, - .wakeup = RING_BUFFER_WAKEUP_BY_WRITER, -}; - -static -struct ltt_channel *_channel_create(const char *name, - struct ltt_channel *ltt_chan, void *buf_addr, - size_t subbuf_size, size_t num_subbuf, - unsigned int switch_timer_interval, - unsigned int read_timer_interval, - int *shm_fd, int *wait_fd, - uint64_t *memory_map_size) -{ - ltt_chan->handle = channel_create(&client_config, name, ltt_chan, buf_addr, - subbuf_size, num_subbuf, switch_timer_interval, - read_timer_interval, shm_fd, wait_fd, - memory_map_size); - if (!ltt_chan->handle) - return NULL; - ltt_chan->chan = shmp(ltt_chan->handle, ltt_chan->handle->chan); - return ltt_chan; -} - -static -void ltt_channel_destroy(struct ltt_channel *ltt_chan) -{ - channel_destroy(ltt_chan->chan, ltt_chan->handle, 0); -} - -static -struct lttng_ust_lib_ring_buffer *ltt_buffer_read_open(struct channel *chan, - struct lttng_ust_shm_handle *handle, - int *shm_fd, int *wait_fd, - uint64_t *memory_map_size) -{ - struct lttng_ust_lib_ring_buffer *buf; - int cpu; - - for_each_channel_cpu(cpu, chan) { - buf = channel_get_ring_buffer(&client_config, chan, - cpu, handle, shm_fd, wait_fd, - memory_map_size); - if (!lib_ring_buffer_open_read(buf, handle, 0)) - return buf; - } - return NULL; -} - -static -void ltt_buffer_read_close(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle) -{ - lib_ring_buffer_release_read(buf, handle, 0); -} - -static -int ltt_event_reserve(struct lttng_ust_lib_ring_buffer_ctx *ctx, - uint32_t event_id) -{ - struct ltt_channel *ltt_chan = channel_get_private(ctx->chan); - int ret, cpu; - - cpu = lib_ring_buffer_get_cpu(&client_config); - if (cpu < 0) - return -EPERM; - ctx->cpu = cpu; - - switch (ltt_chan->header_type) { - case 1: /* compact */ - if (event_id > 30) - ctx->rflags |= LTT_RFLAG_EXTENDED; - break; - case 2: /* large */ - if (event_id > 65534) - ctx->rflags |= LTT_RFLAG_EXTENDED; - break; - default: - WARN_ON_ONCE(1); - } - - ret = lib_ring_buffer_reserve(&client_config, ctx); - if (ret) - goto put; - ltt_write_event_header(&client_config, ctx, event_id); - return 0; -put: - lib_ring_buffer_put_cpu(&client_config); - return ret; -} - -static -void ltt_event_commit(struct lttng_ust_lib_ring_buffer_ctx *ctx) -{ - lib_ring_buffer_commit(&client_config, ctx); - lib_ring_buffer_put_cpu(&client_config); -} - -static -void ltt_event_write(struct lttng_ust_lib_ring_buffer_ctx *ctx, const void *src, - size_t len) -{ - lib_ring_buffer_write(&client_config, ctx, src, len); -} - -#if 0 -static -wait_queue_head_t *ltt_get_reader_wait_queue(struct channel *chan) -{ - return &chan->read_wait; -} - -static -wait_queue_head_t *ltt_get_hp_wait_queue(struct channel *chan) -{ - return &chan->hp_wait; -} -#endif //0 - -static -int ltt_is_finalized(struct channel *chan) -{ - return lib_ring_buffer_channel_is_finalized(chan); -} - -static -int ltt_is_disabled(struct channel *chan) -{ - return lib_ring_buffer_channel_is_disabled(chan); -} - -static -int ltt_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle) -{ - struct lttng_ust_lib_ring_buffer *buf; - int cpu; - - for_each_channel_cpu(cpu, chan) { - int shm_fd, wait_fd; - uint64_t memory_map_size; - - buf = channel_get_ring_buffer(&client_config, chan, - cpu, handle, &shm_fd, &wait_fd, - &memory_map_size); - lib_ring_buffer_switch(&client_config, buf, - SWITCH_ACTIVE, handle); - } - return 0; -} - -static struct ltt_transport ltt_relay_transport = { - .name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING "-mmap", - .ops = { - .channel_create = _channel_create, - .channel_destroy = ltt_channel_destroy, - .buffer_read_open = ltt_buffer_read_open, - .buffer_read_close = ltt_buffer_read_close, - .event_reserve = ltt_event_reserve, - .event_commit = ltt_event_commit, - .event_write = ltt_event_write, - .packet_avail_size = NULL, /* Would be racy anyway */ - //.get_reader_wait_queue = ltt_get_reader_wait_queue, - //.get_hp_wait_queue = ltt_get_hp_wait_queue, - .is_finalized = ltt_is_finalized, - .is_disabled = ltt_is_disabled, - .flush_buffer = ltt_flush_buffer, - }, -}; - -void RING_BUFFER_MODE_TEMPLATE_INIT(void) -{ - DBG("LTT : ltt ring buffer client init\n"); - ltt_transport_register(<t_relay_transport); -} - -void RING_BUFFER_MODE_TEMPLATE_EXIT(void) -{ - DBG("LTT : ltt ring buffer client exit\n"); - ltt_transport_unregister(<t_relay_transport); -} diff --git a/libust/ltt-ring-buffer-metadata-client.c b/libust/ltt-ring-buffer-metadata-client.c deleted file mode 100644 index e1747c43..00000000 --- a/libust/ltt-ring-buffer-metadata-client.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * ltt-ring-buffer-metadata-client.c - * - * Copyright (C) 2010 - Mathieu Desnoyers - * - * LTTng lib ring buffer metadta client. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include "ltt-tracer.h" - -#define RING_BUFFER_MODE_TEMPLATE RING_BUFFER_DISCARD -#define RING_BUFFER_MODE_TEMPLATE_STRING "metadata" -#define RING_BUFFER_MODE_TEMPLATE_INIT \ - ltt_ring_buffer_metadata_client_init -#define RING_BUFFER_MODE_TEMPLATE_EXIT \ - ltt_ring_buffer_metadata_client_exit -#include "ltt-ring-buffer-metadata-client.h" diff --git a/libust/ltt-ring-buffer-metadata-client.h b/libust/ltt-ring-buffer-metadata-client.h deleted file mode 100644 index d1a83d53..00000000 --- a/libust/ltt-ring-buffer-metadata-client.h +++ /dev/null @@ -1,316 +0,0 @@ -/* - * ltt-ring-buffer-client.h - * - * Copyright (C) 2010 - Mathieu Desnoyers - * - * LTTng lib ring buffer client template. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include -#include -#include "lttng/bitfield.h" -#include "ltt-tracer.h" -#include "../libringbuffer/frontend_types.h" - -struct metadata_packet_header { - uint32_t magic; /* 0x75D11D57 */ - uint8_t uuid[16]; /* Unique Universal Identifier */ - uint32_t checksum; /* 0 if unused */ - uint32_t content_size; /* in bits */ - uint32_t packet_size; /* in bits */ - uint8_t compression_scheme; /* 0 if unused */ - uint8_t encryption_scheme; /* 0 if unused */ - uint8_t checksum_scheme; /* 0 if unused */ - uint8_t major; /* CTF spec major version number */ - uint8_t minor; /* CTF spec minor version number */ - uint8_t header_end[0]; -}; - -struct metadata_record_header { - uint8_t header_end[0]; /* End of header */ -}; - -static const struct lttng_ust_lib_ring_buffer_config client_config; - -static inline -u64 lib_ring_buffer_clock_read(struct channel *chan) -{ - return 0; -} - -static inline -unsigned char record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, - struct channel *chan, size_t offset, - size_t *pre_header_padding, - struct lttng_ust_lib_ring_buffer_ctx *ctx) -{ - return 0; -} - -#include "../libringbuffer/api.h" - -static u64 client_ring_buffer_clock_read(struct channel *chan) -{ - return 0; -} - -static -size_t client_record_header_size(const struct lttng_ust_lib_ring_buffer_config *config, - struct channel *chan, size_t offset, - size_t *pre_header_padding, - struct lttng_ust_lib_ring_buffer_ctx *ctx) -{ - return 0; -} - -/** - * client_packet_header_size - called on buffer-switch to a new sub-buffer - * - * Return header size without padding after the structure. Don't use packed - * structure because gcc generates inefficient code on some architectures - * (powerpc, mips..) - */ -static size_t client_packet_header_size(void) -{ - return offsetof(struct metadata_packet_header, header_end); -} - -static void client_buffer_begin(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, - unsigned int subbuf_idx, - struct lttng_ust_shm_handle *handle) -{ - struct channel *chan = shmp(handle, buf->backend.chan); - struct metadata_packet_header *header = - (struct metadata_packet_header *) - lib_ring_buffer_offset_address(&buf->backend, - subbuf_idx * chan->backend.subbuf_size, - handle); - struct ltt_channel *ltt_chan = channel_get_private(chan); - struct ltt_session *session = ltt_chan->session; - - header->magic = TSDL_MAGIC_NUMBER; - memcpy(header->uuid, session->uuid, sizeof(session->uuid)); - header->checksum = 0; /* 0 if unused */ - header->content_size = 0xFFFFFFFF; /* in bits, for debugging */ - header->packet_size = 0xFFFFFFFF; /* in bits, for debugging */ - header->compression_scheme = 0; /* 0 if unused */ - header->encryption_scheme = 0; /* 0 if unused */ - header->checksum_scheme = 0; /* 0 if unused */ - header->major = CTF_SPEC_MAJOR; - header->minor = CTF_SPEC_MINOR; - -} - -/* - * offset is assumed to never be 0 here : never deliver a completely empty - * subbuffer. data_size is between 1 and subbuf_size. - */ -static void client_buffer_end(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, - unsigned int subbuf_idx, unsigned long data_size, - struct lttng_ust_shm_handle *handle) -{ - struct channel *chan = shmp(handle, buf->backend.chan); - struct metadata_packet_header *header = - (struct metadata_packet_header *) - lib_ring_buffer_offset_address(&buf->backend, - subbuf_idx * chan->backend.subbuf_size, - handle); - unsigned long records_lost = 0; - - header->content_size = data_size * CHAR_BIT; /* in bits */ - header->packet_size = PAGE_ALIGN(data_size) * CHAR_BIT; /* in bits */ - records_lost += lib_ring_buffer_get_records_lost_full(&client_config, buf); - records_lost += lib_ring_buffer_get_records_lost_wrap(&client_config, buf); - records_lost += lib_ring_buffer_get_records_lost_big(&client_config, buf); - WARN_ON_ONCE(records_lost != 0); -} - -static int client_buffer_create(struct lttng_ust_lib_ring_buffer *buf, void *priv, - int cpu, const char *name, - struct lttng_ust_shm_handle *handle) -{ - return 0; -} - -static void client_buffer_finalize(struct lttng_ust_lib_ring_buffer *buf, - void *priv, int cpu, - struct lttng_ust_shm_handle *handle) -{ -} - -static const struct lttng_ust_lib_ring_buffer_config client_config = { - .cb.ring_buffer_clock_read = client_ring_buffer_clock_read, - .cb.record_header_size = client_record_header_size, - .cb.subbuffer_header_size = client_packet_header_size, - .cb.buffer_begin = client_buffer_begin, - .cb.buffer_end = client_buffer_end, - .cb.buffer_create = client_buffer_create, - .cb.buffer_finalize = client_buffer_finalize, - - .tsc_bits = 0, - .alloc = RING_BUFFER_ALLOC_GLOBAL, - .sync = RING_BUFFER_SYNC_GLOBAL, - .mode = RING_BUFFER_MODE_TEMPLATE, - .backend = RING_BUFFER_PAGE, - .output = RING_BUFFER_MMAP, - .oops = RING_BUFFER_OOPS_CONSISTENCY, - .ipi = RING_BUFFER_NO_IPI_BARRIER, - .wakeup = RING_BUFFER_WAKEUP_BY_WRITER, -}; - -static -struct ltt_channel *_channel_create(const char *name, - struct ltt_channel *ltt_chan, void *buf_addr, - size_t subbuf_size, size_t num_subbuf, - unsigned int switch_timer_interval, - unsigned int read_timer_interval, - int *shm_fd, int *wait_fd, - uint64_t *memory_map_size) -{ - ltt_chan->handle = channel_create(&client_config, name, ltt_chan, buf_addr, - subbuf_size, num_subbuf, switch_timer_interval, - read_timer_interval, shm_fd, wait_fd, - memory_map_size); - if (!ltt_chan->handle) - return NULL; - ltt_chan->chan = shmp(ltt_chan->handle, ltt_chan->handle->chan); - return ltt_chan; -} - -static -void ltt_channel_destroy(struct ltt_channel *ltt_chan) -{ - channel_destroy(ltt_chan->chan, ltt_chan->handle, 0); -} - -static -struct lttng_ust_lib_ring_buffer *ltt_buffer_read_open(struct channel *chan, - struct lttng_ust_shm_handle *handle, - int *shm_fd, int *wait_fd, - uint64_t *memory_map_size) -{ - struct lttng_ust_lib_ring_buffer *buf; - - buf = channel_get_ring_buffer(&client_config, chan, - 0, handle, shm_fd, wait_fd, memory_map_size); - if (!lib_ring_buffer_open_read(buf, handle, 0)) - return buf; - return NULL; -} - -static -void ltt_buffer_read_close(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle) -{ - lib_ring_buffer_release_read(buf, handle, 0); -} - -static -int ltt_event_reserve(struct lttng_ust_lib_ring_buffer_ctx *ctx, uint32_t event_id) -{ - return lib_ring_buffer_reserve(&client_config, ctx); -} - -static -void ltt_event_commit(struct lttng_ust_lib_ring_buffer_ctx *ctx) -{ - lib_ring_buffer_commit(&client_config, ctx); -} - -static -void ltt_event_write(struct lttng_ust_lib_ring_buffer_ctx *ctx, const void *src, - size_t len) -{ - lib_ring_buffer_write(&client_config, ctx, src, len); -} - -static -size_t ltt_packet_avail_size(struct channel *chan, struct lttng_ust_shm_handle *handle) - -{ - unsigned long o_begin; - struct lttng_ust_lib_ring_buffer *buf; - - buf = shmp(handle, chan->backend.buf[0].shmp); /* Only for global buffer ! */ - o_begin = v_read(&client_config, &buf->offset); - if (subbuf_offset(o_begin, chan) != 0) { - return chan->backend.subbuf_size - subbuf_offset(o_begin, chan); - } else { - return chan->backend.subbuf_size - subbuf_offset(o_begin, chan) - - sizeof(struct metadata_packet_header); - } -} - -#if 0 -static -wait_queue_head_t *ltt_get_reader_wait_queue(struct channel *chan) -{ - return &chan->read_wait; -} - -static -wait_queue_head_t *ltt_get_hp_wait_queue(struct channel *chan) -{ - return &chan->hp_wait; -} -#endif //0 - -static -int ltt_is_finalized(struct channel *chan) -{ - return lib_ring_buffer_channel_is_finalized(chan); -} - -static -int ltt_is_disabled(struct channel *chan) -{ - return lib_ring_buffer_channel_is_disabled(chan); -} - -static -int ltt_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle) -{ - struct lttng_ust_lib_ring_buffer *buf; - int shm_fd, wait_fd; - uint64_t memory_map_size; - - buf = channel_get_ring_buffer(&client_config, chan, - 0, handle, &shm_fd, &wait_fd, - &memory_map_size); - lib_ring_buffer_switch(&client_config, buf, - SWITCH_ACTIVE, handle); - return 0; -} - -static struct ltt_transport ltt_relay_transport = { - .name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING "-mmap", - .ops = { - .channel_create = _channel_create, - .channel_destroy = ltt_channel_destroy, - .buffer_read_open = ltt_buffer_read_open, - .buffer_read_close = ltt_buffer_read_close, - .event_reserve = ltt_event_reserve, - .event_commit = ltt_event_commit, - .event_write = ltt_event_write, - .packet_avail_size = ltt_packet_avail_size, - //.get_reader_wait_queue = ltt_get_reader_wait_queue, - //.get_hp_wait_queue = ltt_get_hp_wait_queue, - .is_finalized = ltt_is_finalized, - .is_disabled = ltt_is_disabled, - .flush_buffer = ltt_flush_buffer, - }, -}; - -void RING_BUFFER_MODE_TEMPLATE_INIT(void) -{ - DBG("LTT : ltt ring buffer client init\n"); - ltt_transport_register(<t_relay_transport); -} - -void RING_BUFFER_MODE_TEMPLATE_EXIT(void) -{ - DBG("LTT : ltt ring buffer client exit\n"); - ltt_transport_unregister(<t_relay_transport); -} diff --git a/libust/ltt-tracer-core.h b/libust/ltt-tracer-core.h deleted file mode 100644 index 20ed0c0e..00000000 --- a/libust/ltt-tracer-core.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _LTT_TRACER_CORE_H -#define _LTT_TRACER_CORE_H - -/* - * Copyright (C) 2005-2011 Mathieu Desnoyers - * - * This contains the core definitions for the Linux Trace Toolkit. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 of - * the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include "lttng/bug.h" - -#include - -struct ltt_session; -struct ltt_channel; -struct ltt_event; - -void ust_lock(void); -void ust_unlock(void); - -#endif /* _LTT_TRACER_CORE_H */ diff --git a/libust/ltt-tracer.h b/libust/ltt-tracer.h deleted file mode 100644 index 6ab80e7c..00000000 --- a/libust/ltt-tracer.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _LTT_TRACER_H -#define _LTT_TRACER_H - -/* - * Copyright (C) 2005-2011 Mathieu Desnoyers - * - * This contains the definitions for the Linux Trace Toolkit tracer. - * - * Ported to userspace by Pierre-Marc Fournier. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 of - * the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include "ltt-tracer-core.h" - -/* Number of bytes to log with a read/write event */ -#define LTT_LOG_RW_SIZE 32L -#define LTT_MAX_SMALL_SIZE 0xFFFFU - -/* Tracer properties */ -#define CTF_MAGIC_NUMBER 0xC1FC1FC1 -#define TSDL_MAGIC_NUMBER 0x75D11D57 - -/* CTF specification version followed */ -#define CTF_SPEC_MAJOR 1 -#define CTF_SPEC_MINOR 8 - -/* Tracer major/minor versions */ -#define CTF_VERSION_MAJOR 0 -#define CTF_VERSION_MINOR 1 - -/* - * Number of milliseconds to retry before failing metadata writes on buffer full - * condition. (10 seconds) - */ -#define LTTNG_METADATA_TIMEOUT_MSEC 10000 - -#define LTT_RFLAG_EXTENDED RING_BUFFER_RFLAG_END -#define LTT_RFLAG_END (LTT_RFLAG_EXTENDED << 1) - -#endif /* _LTT_TRACER_H */ diff --git a/libust/lttng-context-procname.c b/libust/lttng-context-procname.c deleted file mode 100644 index b9bae82e..00000000 --- a/libust/lttng-context-procname.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * (C) Copyright 2009-2011 - - * Mathieu Desnoyers - * - * LTTng UST procname context. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include -#include -#include -#include -#include - -#define PROCNAME_LEN 17 /* includes \0 */ - -/* - * We cache the result to ensure we don't trigger a system call for - * each event. - * Upon exec, procname changes, but exec takes care of throwing away - * this cached version. - */ -static char cached_procname[17]; - -static inline -char *wrapper_getprocname(void) -{ - int ret; - - if (caa_unlikely(!cached_procname[0])) { - ret = prctl(PR_GET_NAME, (unsigned long) cached_procname, - 0, 0, 0); - assert(!ret); - } - return cached_procname; -} - -void lttng_context_procname_reset(void) -{ - cached_procname[0] = '\0'; -} - -static -size_t procname_get_size(size_t offset) -{ - size_t size = 0; - - size += PROCNAME_LEN; - return size; -} - -static -void procname_record(struct lttng_ctx_field *field, - struct lttng_ust_lib_ring_buffer_ctx *ctx, - struct ltt_channel *chan) -{ - char *procname; - - procname = wrapper_getprocname(); - chan->ops->event_write(ctx, procname, PROCNAME_LEN); -} - -int lttng_add_procname_to_ctx(struct lttng_ctx **ctx) -{ - struct lttng_ctx_field *field; - - field = lttng_append_context(ctx); - if (!field) - return -ENOMEM; - if (lttng_find_context(*ctx, "procname")) { - lttng_remove_context_field(ctx, field); - return -EEXIST; - } - field->event_field.name = "procname"; - field->event_field.type.atype = atype_array; - field->event_field.type.u.array.elem_type.atype = atype_integer; - field->event_field.type.u.array.elem_type.u.basic.integer.size = sizeof(char) * CHAR_BIT; - field->event_field.type.u.array.elem_type.u.basic.integer.alignment = lttng_alignof(char) * CHAR_BIT; - field->event_field.type.u.array.elem_type.u.basic.integer.signedness = lttng_is_signed_type(char); - field->event_field.type.u.array.elem_type.u.basic.integer.reverse_byte_order = 0; - field->event_field.type.u.array.elem_type.u.basic.integer.base = 10; - field->event_field.type.u.array.elem_type.u.basic.integer.encoding = lttng_encode_UTF8; - field->event_field.type.u.array.length = PROCNAME_LEN; - field->get_size = procname_get_size; - field->record = procname_record; - return 0; -} diff --git a/libust/lttng-context-pthread-id.c b/libust/lttng-context-pthread-id.c deleted file mode 100644 index 62eda808..00000000 --- a/libust/lttng-context-pthread-id.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * (C) Copyright 2009-2011 - - * Mathieu Desnoyers - * - * LTTng UST pthread_id context. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include -#include -#include -#include - -static -size_t pthread_id_get_size(size_t offset) -{ - size_t size = 0; - - size += lib_ring_buffer_align(offset, lttng_alignof(unsigned long)); - size += sizeof(unsigned long); - return size; -} - -static -void pthread_id_record(struct lttng_ctx_field *field, - struct lttng_ust_lib_ring_buffer_ctx *ctx, - struct ltt_channel *chan) -{ - unsigned long pthread_id; - - pthread_id = (unsigned long) pthread_self(); - lib_ring_buffer_align_ctx(ctx, lttng_alignof(pthread_id)); - chan->ops->event_write(ctx, &pthread_id, sizeof(pthread_id)); -} - -int lttng_add_pthread_id_to_ctx(struct lttng_ctx **ctx) -{ - struct lttng_ctx_field *field; - - field = lttng_append_context(ctx); - if (!field) - return -ENOMEM; - if (lttng_find_context(*ctx, "pthread_id")) { - lttng_remove_context_field(ctx, field); - return -EEXIST; - } - field->event_field.name = "pthread_id"; - field->event_field.type.atype = atype_integer; - field->event_field.type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT; - field->event_field.type.u.basic.integer.alignment = lttng_alignof(unsigned long) * CHAR_BIT; - field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(unsigned long); - field->event_field.type.u.basic.integer.reverse_byte_order = 0; - field->event_field.type.u.basic.integer.base = 10; - field->event_field.type.u.basic.integer.encoding = lttng_encode_none; - field->get_size = pthread_id_get_size; - field->record = pthread_id_record; - return 0; -} diff --git a/libust/lttng-context-vpid.c b/libust/lttng-context-vpid.c deleted file mode 100644 index db76747a..00000000 --- a/libust/lttng-context-vpid.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * (C) Copyright 2009-2011 - - * Mathieu Desnoyers - * - * LTTng UST vpid context. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include -#include -#include -#include -#include - -#ifdef __linux__ -static inline -pid_t wrapper_getpid(void) -{ - return getpid(); -} - -void lttng_context_vpid_reset(void) -{ -} -#else -/* - * We cache the result to ensure we don't trigger a system call for - * each event. - */ -static pid_t cached_vpid; - -static inline -pid_t wrapper_getpid(void) -{ - if (caa_unlikely(!cached_vpid)) - cached_vpid = getpid(); - return cached_vpid; -} - -/* - * Upon fork or clone, the PID assigned to our thread is not the same as - * we kept in cache. - */ -void lttng_context_vpid_reset(void) -{ - cached_vpid = 0; -} -#endif - -static -size_t vpid_get_size(size_t offset) -{ - size_t size = 0; - - size += lib_ring_buffer_align(offset, lttng_alignof(pid_t)); - size += sizeof(pid_t); - return size; -} - -static -void vpid_record(struct lttng_ctx_field *field, - struct lttng_ust_lib_ring_buffer_ctx *ctx, - struct ltt_channel *chan) -{ - pid_t pid; - - pid = wrapper_getpid(); - lib_ring_buffer_align_ctx(ctx, lttng_alignof(pid)); - chan->ops->event_write(ctx, &pid, sizeof(pid)); -} - -int lttng_add_vpid_to_ctx(struct lttng_ctx **ctx) -{ - struct lttng_ctx_field *field; - - field = lttng_append_context(ctx); - if (!field) - return -ENOMEM; - if (lttng_find_context(*ctx, "vpid")) { - lttng_remove_context_field(ctx, field); - return -EEXIST; - } - field->event_field.name = "vpid"; - field->event_field.type.atype = atype_integer; - field->event_field.type.u.basic.integer.size = sizeof(pid_t) * CHAR_BIT; - field->event_field.type.u.basic.integer.alignment = lttng_alignof(pid_t) * CHAR_BIT; - field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(pid_t); - field->event_field.type.u.basic.integer.reverse_byte_order = 0; - field->event_field.type.u.basic.integer.base = 10; - field->event_field.type.u.basic.integer.encoding = lttng_encode_none; - field->get_size = vpid_get_size; - field->record = vpid_record; - return 0; -} diff --git a/libust/lttng-context-vtid.c b/libust/lttng-context-vtid.c deleted file mode 100644 index 6f7e078d..00000000 --- a/libust/lttng-context-vtid.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * (C) Copyright 2009-2011 - - * Mathieu Desnoyers - * - * LTTng UST vtid context. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include -#endif - -#if defined(_syscall0) -_syscall0(pid_t, gettid) -#elif defined(__NR_gettid) -static inline pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#else -#warning "use pid as tid" -static inline pid_t gettid(void) -{ - return getpid(); -} -#endif - -/* - * We cache the result to ensure we don't trigger a system call for - * each event. - */ -static __thread pid_t cached_vtid; - -/* - * Upon fork or clone, the TID assigned to our thread is not the same as - * we kept in cache. Luckily, we are the only thread surviving in the - * child process, so we can simply clear our cached version. - */ -void lttng_context_vtid_reset(void) -{ - cached_vtid = 0; -} - -static -size_t vtid_get_size(size_t offset) -{ - size_t size = 0; - - size += lib_ring_buffer_align(offset, lttng_alignof(pid_t)); - size += sizeof(pid_t); - return size; -} - -static -void vtid_record(struct lttng_ctx_field *field, - struct lttng_ust_lib_ring_buffer_ctx *ctx, - struct ltt_channel *chan) -{ - if (caa_unlikely(!cached_vtid)) - cached_vtid = gettid(); - lib_ring_buffer_align_ctx(ctx, lttng_alignof(cached_vtid)); - chan->ops->event_write(ctx, &cached_vtid, sizeof(cached_vtid)); -} - -int lttng_add_vtid_to_ctx(struct lttng_ctx **ctx) -{ - struct lttng_ctx_field *field; - - field = lttng_append_context(ctx); - if (!field) - return -ENOMEM; - if (lttng_find_context(*ctx, "vtid")) { - lttng_remove_context_field(ctx, field); - return -EEXIST; - } - field->event_field.name = "vtid"; - field->event_field.type.atype = atype_integer; - field->event_field.type.u.basic.integer.size = sizeof(pid_t) * CHAR_BIT; - field->event_field.type.u.basic.integer.alignment = lttng_alignof(pid_t) * CHAR_BIT; - field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(pid_t); - field->event_field.type.u.basic.integer.reverse_byte_order = 0; - field->event_field.type.u.basic.integer.base = 10; - field->event_field.type.u.basic.integer.encoding = lttng_encode_none; - field->get_size = vtid_get_size; - field->record = vtid_record; - return 0; -} diff --git a/libust/lttng-ust-abi.c b/libust/lttng-ust-abi.c deleted file mode 100644 index 6d17c200..00000000 --- a/libust/lttng-ust-abi.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * 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 -#include "lttng/core.h" -#include "ltt-tracer.h" - -/* - * Object descriptor table. Should be protected from concurrent access - * by the caller. - */ - -struct lttng_ust_obj { - union { - struct { - void *private_data; - const struct lttng_ust_objd_ops *ops; - int f_count; - } s; - int freelist_next; /* offset freelist. end is -1. */ - } u; -}; - -struct lttng_ust_objd_table { - struct lttng_ust_obj *array; - unsigned int len, allocated_len; - int freelist_head; /* offset freelist head. end is -1 */ -}; - -static struct lttng_ust_objd_table objd_table = { - .freelist_head = -1, -}; - -static -int objd_alloc(void *private_data, const struct lttng_ust_objd_ops *ops) -{ - struct lttng_ust_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 lttng_ust_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 lttng_ust_obj) * new_allocated_len); - if (!new_table) - return -ENOMEM; - memcpy(new_table, old_table, - sizeof(struct lttng_ust_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 = 2; /* count == 1 : object is allocated */ - /* count == 2 : allocated + hold ref */ - return obj - objd_table.array; -} - -static -struct lttng_ust_obj *_objd_get(int id) -{ - if (id >= objd_table.len) - return NULL; - if (!objd_table.array[id].u.s.f_count) - return NULL; - return &objd_table.array[id]; -} - -static -void *objd_private(int id) -{ - struct lttng_ust_obj *obj = _objd_get(id); - assert(obj); - return obj->u.s.private_data; -} - -static -void objd_set_private(int id, void *private_data) -{ - struct lttng_ust_obj *obj = _objd_get(id); - assert(obj); - obj->u.s.private_data = private_data; -} - -const struct lttng_ust_objd_ops *objd_ops(int id) -{ - struct lttng_ust_obj *obj = _objd_get(id); - - if (!obj) - return NULL; - return obj->u.s.ops; -} - -static -void objd_free(int id) -{ - struct lttng_ust_obj *obj = _objd_get(id); - - assert(obj); - obj->u.freelist_next = objd_table.freelist_head; - objd_table.freelist_head = obj - objd_table.array; - assert(obj->u.s.f_count == 1); - obj->u.s.f_count = 0; /* deallocated */ -} - -static -void objd_ref(int id) -{ - struct lttng_ust_obj *obj = _objd_get(id); - obj->u.s.f_count++; -} - -int lttng_ust_objd_unref(int id) -{ - struct lttng_ust_obj *obj = _objd_get(id); - - if (!obj) - return -EINVAL; - if (obj->u.s.f_count == 1) { - ERR("Reference counting error\n"); - return -EINVAL; - } - if ((--obj->u.s.f_count) == 1) { - const struct lttng_ust_objd_ops *ops = objd_ops(id); - - if (ops->release) - ops->release(id); - objd_free(id); - } - return 0; -} - -static -void objd_table_destroy(void) -{ - int i; - - for (i = 0; i < objd_table.allocated_len; i++) - (void) lttng_ust_objd_unref(i); - free(objd_table.array); - objd_table.array = NULL; - objd_table.len = 0; - objd_table.allocated_len = 0; - objd_table.freelist_head = -1; -} - -/* - * This is LTTng's own personal way to create an ABI for sessiond. - * We send commands over a socket. - */ - -static const struct lttng_ust_objd_ops lttng_ops; -static const struct lttng_ust_objd_ops lttng_session_ops; -static const struct lttng_ust_objd_ops lttng_channel_ops; -static const struct lttng_ust_objd_ops lttng_metadata_ops; -static const struct lttng_ust_objd_ops lttng_event_ops; -static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops; - -enum channel_type { - PER_CPU_CHANNEL, - METADATA_CHANNEL, -}; - -int lttng_abi_create_root_handle(void) -{ - int root_handle; - - root_handle = objd_alloc(NULL, <tng_ops); - return root_handle; -} - -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_PTHREAD_ID: - return lttng_add_pthread_id_to_ctx(ctx); - case LTTNG_UST_CONTEXT_VTID: - return lttng_add_vtid_to_ctx(ctx); - case LTTNG_UST_CONTEXT_VPID: - return lttng_add_vpid_to_ctx(ctx); - case LTTNG_UST_CONTEXT_PROCNAME: - return lttng_add_procname_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 lttng_ust_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 */ -} - -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 lttng_ust_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, - &chan_param->shm_fd, - &chan_param->wait_fd, - &chan_param->memory_map_size); - 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: - { - int err; - - err = lttng_ust_objd_unref(chan_objd); - assert(!err); - } -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_release_session(int objd) -{ - struct ltt_session *session = objd_private(objd); - - if (session) { - ltt_session_destroy(session); - return 0; - } else { - return -EINVAL; - } -} - -static const struct lttng_ust_objd_ops lttng_session_ops = { - .release = lttng_release_session, - .cmd = lttng_session_cmd, -}; - -struct stream_priv_data { - struct lttng_ust_lib_ring_buffer *buf; - struct ltt_channel *ltt_chan; -}; - -static -int lttng_abi_open_stream(int channel_objd, struct lttng_ust_stream *info) -{ - struct ltt_channel *channel = objd_private(channel_objd); - struct lttng_ust_lib_ring_buffer *buf; - struct stream_priv_data *priv; - int stream_objd, ret; - - buf = channel->ops->buffer_read_open(channel->chan, channel->handle, - &info->shm_fd, &info->wait_fd, &info->memory_map_size); - if (!buf) - return -ENOENT; - - priv = zmalloc(sizeof(*priv)); - if (!priv) { - ret = -ENOMEM; - goto alloc_error; - } - priv->buf = buf; - priv->ltt_chan = channel; - stream_objd = objd_alloc(priv, &lib_ring_buffer_objd_ops); - if (stream_objd < 0) { - ret = stream_objd; - goto objd_error; - } - /* Hold a reference on the channel object descriptor */ - objd_ref(channel_objd); - return stream_objd; - -objd_error: - free(priv); -alloc_error: - channel->ops->buffer_read_close(buf, channel->handle); - return ret; -} - -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: - { - int err; - - err = lttng_ust_objd_unref(event_objd); - assert(!err); - } -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: - { - struct lttng_ust_stream *stream; - - stream = (struct lttng_ust_stream *) arg; - /* stream used as output */ - return lttng_abi_open_stream(objd, stream); - } - 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); - case LTTNG_UST_FLUSH_BUFFER: - return channel->ops->flush_buffer(channel->chan, channel->handle); - 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) -{ - struct ltt_channel *channel = objd_private(objd); - - switch (cmd) { - case LTTNG_UST_STREAM: - { - struct lttng_ust_stream *stream; - - stream = (struct lttng_ust_stream *) arg; - /* stream used as output */ - return lttng_abi_open_stream(objd, stream); - } - case LTTNG_UST_FLUSH_BUFFER: - return channel->ops->flush_buffer(channel->chan, channel->handle); - 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) - return lttng_ust_objd_unref(channel->session->objd); - return 0; -} - -static const struct lttng_ust_objd_ops lttng_channel_ops = { - .release = lttng_channel_release, - //.poll = lttng_channel_poll, - .cmd = lttng_channel_cmd, -}; - -static const struct lttng_ust_objd_ops lttng_metadata_ops = { - .release = lttng_channel_release, - .cmd = lttng_metadata_cmd, -}; - -/** - * lttng_rb_cmd - lttng ring buffer control through object descriptors - * - * @objd: the object descriptor - * @cmd: the command - * @arg: command arg - * - * This object descriptor implements lttng commands: - * (None for now. Access is done directly though shm.) - */ -static -long lttng_rb_cmd(int objd, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - default: - return -EINVAL; - } -} - -static -int lttng_rb_release(int objd) -{ - struct stream_priv_data *priv = objd_private(objd); - struct lttng_ust_lib_ring_buffer *buf; - struct ltt_channel *channel; - - if (priv) { - buf = priv->buf; - channel = priv->ltt_chan; - free(priv); - channel->ops->buffer_read_close(buf, channel->handle); - - return lttng_ust_objd_unref(channel->objd); - } - return 0; -} - -static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops = { - .release = lttng_rb_release, - .cmd = lttng_rb_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) - return lttng_ust_objd_unref(event->chan->objd); - return 0; -} - -/* TODO: filter control ioctl */ -static const struct lttng_ust_objd_ops lttng_event_ops = { - .release = lttng_event_release, - .cmd = lttng_event_cmd, -}; - -void lttng_ust_abi_exit(void) -{ - objd_table_destroy(); -} diff --git a/libust/lttng-ust-comm.c b/libust/lttng-ust-comm.c deleted file mode 100644 index 1246c654..00000000 --- a/libust/lttng-ust-comm.c +++ /dev/null @@ -1,935 +0,0 @@ -/* - * lttng-ust-comm.c - * - * Copyright (C) 2011 David Goulet - * Copyright (C) 2011 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; only - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define _LGPL_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "ltt-tracer-core.h" - -/* - * Has lttng ust comm constructor been called ? - */ -static int initialized; - -/* - * The ust_lock/ust_unlock lock is used as a communication thread mutex. - * Held when handling a command, also held by fork() to deal with - * removal of threads, and by exit path. - */ - -/* Should the ust comm thread quit ? */ -static int lttng_ust_comm_should_quit; - -/* - * Wait for either of these before continuing to the main - * program: - * - the register_done message from sessiond daemon - * (will let the sessiond daemon enable sessions before main - * starts.) - * - sessiond daemon is not reachable. - * - timeout (ensuring applications are resilient to session - * daemon problems). - */ -static sem_t constructor_wait; -/* - * Doing this for both the global and local sessiond. - */ -static int sem_count = { 2 }; - -/* - * Info about socket and associated listener thread. - */ -struct sock_info { - const char *name; - pthread_t ust_listener; /* listener thread */ - int root_handle; - int constructor_sem_posted; - int allowed; - int global; - - char sock_path[PATH_MAX]; - int socket; - - char wait_shm_path[PATH_MAX]; - char *wait_shm_mmap; -}; - -/* Socket from app (connect) to session daemon (listen) for communication */ -struct sock_info global_apps = { - .name = "global", - .global = 1, - - .root_handle = -1, - .allowed = 1, - - .sock_path = DEFAULT_GLOBAL_APPS_UNIX_SOCK, - .socket = -1, - - .wait_shm_path = DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH, -}; - -/* TODO: allow global_apps_sock_path override */ - -struct sock_info local_apps = { - .name = "local", - .global = 0, - .root_handle = -1, - .allowed = 0, /* Check setuid bit first */ - - .socket = -1, -}; - -static int wait_poll_fallback; - -extern void ltt_ring_buffer_client_overwrite_init(void); -extern void ltt_ring_buffer_client_discard_init(void); -extern void ltt_ring_buffer_metadata_client_init(void); -extern void ltt_ring_buffer_client_overwrite_exit(void); -extern void ltt_ring_buffer_client_discard_exit(void); -extern void ltt_ring_buffer_metadata_client_exit(void); - -static -int setup_local_apps(void) -{ - const char *home_dir; - uid_t uid; - - uid = getuid(); - /* - * Disallow per-user tracing for setuid binaries. - */ - if (uid != geteuid()) { - local_apps.allowed = 0; - return 0; - } else { - local_apps.allowed = 1; - } - home_dir = (const char *) getenv("HOME"); - if (!home_dir) - return -ENOENT; - snprintf(local_apps.sock_path, PATH_MAX, - DEFAULT_HOME_APPS_UNIX_SOCK, home_dir); - snprintf(local_apps.wait_shm_path, PATH_MAX, - DEFAULT_HOME_APPS_WAIT_SHM_PATH, uid); - return 0; -} - -static -int register_app_to_sessiond(int socket) -{ - ssize_t ret; - int prctl_ret; - struct { - uint32_t major; - uint32_t minor; - pid_t pid; - pid_t ppid; - uid_t uid; - gid_t gid; - char name[16]; /* process name */ - } reg_msg; - - reg_msg.major = LTTNG_UST_COMM_VERSION_MAJOR; - reg_msg.minor = LTTNG_UST_COMM_VERSION_MINOR; - reg_msg.pid = getpid(); - reg_msg.ppid = getppid(); - reg_msg.uid = getuid(); - reg_msg.gid = getgid(); - prctl_ret = prctl(PR_GET_NAME, (unsigned long) reg_msg.name, 0, 0, 0); - if (prctl_ret) { - ERR("Error executing prctl"); - return -errno; - } - - ret = ustcomm_send_unix_sock(socket, ®_msg, sizeof(reg_msg)); - if (ret >= 0 && ret != sizeof(reg_msg)) - return -EIO; - return ret; -} - -static -int send_reply(int sock, struct ustcomm_ust_reply *lur) -{ - ssize_t len; - - len = ustcomm_send_unix_sock(sock, lur, sizeof(*lur)); - switch (len) { - case sizeof(*lur): - DBG("message successfully sent"); - return 0; - case -1: - if (errno == ECONNRESET) { - printf("remote end closed connection\n"); - return 0; - } - return -1; - default: - printf("incorrect message size: %zd\n", len); - return -1; - } -} - -static -int handle_register_done(struct sock_info *sock_info) -{ - int ret; - - if (sock_info->constructor_sem_posted) - return 0; - sock_info->constructor_sem_posted = 1; - if (uatomic_read(&sem_count) <= 0) { - return 0; - } - ret = uatomic_add_return(&sem_count, -1); - if (ret == 0) { - ret = sem_post(&constructor_wait); - assert(!ret); - } - return 0; -} - -static -int handle_message(struct sock_info *sock_info, - int sock, struct ustcomm_ust_msg *lum) -{ - int ret = 0; - const struct lttng_ust_objd_ops *ops; - struct ustcomm_ust_reply lur; - int shm_fd, wait_fd; - - ust_lock(); - - memset(&lur, 0, sizeof(lur)); - - if (lttng_ust_comm_should_quit) { - ret = -EPERM; - goto end; - } - - ops = objd_ops(lum->handle); - if (!ops) { - ret = -ENOENT; - goto end; - } - - switch (lum->cmd) { - case LTTNG_UST_REGISTER_DONE: - if (lum->handle == LTTNG_UST_ROOT_HANDLE) - ret = handle_register_done(sock_info); - else - ret = -EINVAL; - break; - case LTTNG_UST_RELEASE: - if (lum->handle == LTTNG_UST_ROOT_HANDLE) - ret = -EPERM; - else - ret = lttng_ust_objd_unref(lum->handle); - break; - default: - if (ops->cmd) - ret = ops->cmd(lum->handle, lum->cmd, - (unsigned long) &lum->u); - else - ret = -ENOSYS; - break; - } - -end: - lur.handle = lum->handle; - lur.cmd = lum->cmd; - lur.ret_val = ret; - if (ret >= 0) { - lur.ret_code = USTCOMM_OK; - } else { - //lur.ret_code = USTCOMM_SESSION_FAIL; - lur.ret_code = ret; - } - switch (lum->cmd) { - case LTTNG_UST_STREAM: - /* - * Special-case reply to send stream info. - * Use lum.u output. - */ - lur.u.stream.memory_map_size = lum->u.stream.memory_map_size; - shm_fd = lum->u.stream.shm_fd; - wait_fd = lum->u.stream.wait_fd; - break; - case LTTNG_UST_METADATA: - case LTTNG_UST_CHANNEL: - lur.u.channel.memory_map_size = lum->u.channel.memory_map_size; - shm_fd = lum->u.channel.shm_fd; - wait_fd = lum->u.channel.wait_fd; - break; - case LTTNG_UST_VERSION: - lur.u.version = lum->u.version; - break; - } - ret = send_reply(sock, &lur); - if (ret < 0) { - perror("error sending reply"); - goto error; - } - - if ((lum->cmd == LTTNG_UST_STREAM - || lum->cmd == LTTNG_UST_CHANNEL - || lum->cmd == LTTNG_UST_METADATA) - && lur.ret_code == USTCOMM_OK) { - /* we also need to send the file descriptors. */ - ret = ustcomm_send_fds_unix_sock(sock, - &shm_fd, &shm_fd, - 1, sizeof(int)); - if (ret < 0) { - perror("send shm_fd"); - goto error; - } - ret = ustcomm_send_fds_unix_sock(sock, - &wait_fd, &wait_fd, - 1, sizeof(int)); - if (ret < 0) { - perror("send wait_fd"); - goto error; - } - } -error: - ust_unlock(); - return ret; -} - -static -void cleanup_sock_info(struct sock_info *sock_info) -{ - int ret; - - if (sock_info->socket != -1) { - ret = close(sock_info->socket); - if (ret) { - ERR("Error closing apps socket"); - } - sock_info->socket = -1; - } - if (sock_info->root_handle != -1) { - ret = lttng_ust_objd_unref(sock_info->root_handle); - if (ret) { - ERR("Error unref root handle"); - } - sock_info->root_handle = -1; - } - sock_info->constructor_sem_posted = 0; - if (sock_info->wait_shm_mmap) { - ret = munmap(sock_info->wait_shm_mmap, sysconf(_SC_PAGE_SIZE)); - if (ret) { - ERR("Error unmapping wait shm"); - } - sock_info->wait_shm_mmap = NULL; - } -} - -/* - * Using fork to set umask in the child process (not multi-thread safe). - * We deal with the shm_open vs ftruncate race (happening when the - * sessiond owns the shm and does not let everybody modify it, to ensure - * safety against shm_unlink) by simply letting the mmap fail and - * retrying after a few seconds. - * For global shm, everybody has rw access to it until the sessiond - * starts. - */ -static -int get_wait_shm(struct sock_info *sock_info, size_t mmap_size) -{ - int wait_shm_fd, ret; - pid_t pid; - - /* - * Try to open read-only. - */ - wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0); - if (wait_shm_fd >= 0) { - goto end; - } else if (wait_shm_fd < 0 && errno != ENOENT) { - /* - * Real-only open did not work, and it's not because the - * entry was not present. It's a failure that prohibits - * using shm. - */ - ERR("Error opening shm %s", sock_info->wait_shm_path); - goto end; - } - /* - * If the open failed because the file did not exist, try - * creating it ourself. - */ - pid = fork(); - if (pid > 0) { - int status; - - /* - * Parent: wait for child to return, in which case the - * shared memory map will have been created. - */ - pid = wait(&status); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - wait_shm_fd = -1; - goto end; - } - /* - * Try to open read-only again after creation. - */ - wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0); - if (wait_shm_fd < 0) { - /* - * Real-only open did not work. It's a failure - * that prohibits using shm. - */ - ERR("Error opening shm %s", sock_info->wait_shm_path); - goto end; - } - goto end; - } else if (pid == 0) { - int create_mode; - - /* Child */ - create_mode = S_IRUSR | S_IWUSR | S_IRGRP; - if (sock_info->global) - create_mode |= S_IROTH | S_IWGRP | S_IWOTH; - /* - * We're alone in a child process, so we can modify the - * process-wide umask. - */ - umask(~create_mode); - /* - * Try creating shm (or get rw access). - * We don't do an exclusive open, because we allow other - * processes to create+ftruncate it concurrently. - */ - wait_shm_fd = shm_open(sock_info->wait_shm_path, - O_RDWR | O_CREAT, create_mode); - if (wait_shm_fd >= 0) { - ret = ftruncate(wait_shm_fd, mmap_size); - if (ret) { - PERROR("ftruncate"); - exit(EXIT_FAILURE); - } - exit(EXIT_SUCCESS); - } - /* - * For local shm, we need to have rw access to accept - * opening it: this means the local sessiond will be - * able to wake us up. For global shm, we open it even - * if rw access is not granted, because the root.root - * sessiond will be able to override all rights and wake - * us up. - */ - if (!sock_info->global && errno != EACCES) { - ERR("Error opening shm %s", sock_info->wait_shm_path); - exit(EXIT_FAILURE); - } - /* - * The shm exists, but we cannot open it RW. Report - * success. - */ - exit(EXIT_SUCCESS); - } else { - return -1; - } -end: - if (wait_shm_fd >= 0 && !sock_info->global) { - struct stat statbuf; - - /* - * Ensure that our user is the owner of the shm file for - * local shm. If we do not own the file, it means our - * sessiond will not have access to wake us up (there is - * probably a rogue process trying to fake our - * sessiond). Fallback to polling method in this case. - */ - ret = fstat(wait_shm_fd, &statbuf); - if (ret) { - PERROR("fstat"); - goto error_close; - } - if (statbuf.st_uid != getuid()) - goto error_close; - } - return wait_shm_fd; - -error_close: - ret = close(wait_shm_fd); - if (ret) { - PERROR("Error closing fd"); - } - return -1; -} - -static -char *get_map_shm(struct sock_info *sock_info) -{ - size_t mmap_size = sysconf(_SC_PAGE_SIZE); - int wait_shm_fd, ret; - char *wait_shm_mmap; - - wait_shm_fd = get_wait_shm(sock_info, mmap_size); - if (wait_shm_fd < 0) { - goto error; - } - wait_shm_mmap = mmap(NULL, mmap_size, PROT_READ, - MAP_SHARED, wait_shm_fd, 0); - /* close shm fd immediately after taking the mmap reference */ - ret = close(wait_shm_fd); - if (ret) { - PERROR("Error closing fd"); - } - if (wait_shm_mmap == MAP_FAILED) { - DBG("mmap error (can be caused by race with sessiond). Fallback to poll mode."); - goto error; - } - return wait_shm_mmap; - -error: - return NULL; -} - -static -void wait_for_sessiond(struct sock_info *sock_info) -{ - int ret; - - ust_lock(); - if (lttng_ust_comm_should_quit) { - goto quit; - } - if (wait_poll_fallback) { - goto error; - } - if (!sock_info->wait_shm_mmap) { - sock_info->wait_shm_mmap = get_map_shm(sock_info); - if (!sock_info->wait_shm_mmap) - goto error; - } - ust_unlock(); - - DBG("Waiting for %s apps sessiond", sock_info->name); - /* Wait for futex wakeup */ - if (uatomic_read((int32_t *) sock_info->wait_shm_mmap) == 0) { - ret = futex_async((int32_t *) sock_info->wait_shm_mmap, - FUTEX_WAIT, 0, NULL, NULL, 0); - if (ret < 0) { - if (errno == EFAULT) { - wait_poll_fallback = 1; - WARN( -"Linux kernels 2.6.33 to 3.0 (with the exception of stable versions) " -"do not support FUTEX_WAKE on read-only memory mappings correctly. " -"Please upgrade your kernel " -"(fix is commit 9ea71503a8ed9184d2d0b8ccc4d269d05f7940ae in Linux kernel " -"mainline). LTTng-UST will use polling mode fallback."); - } - PERROR("futex"); - } - } - return; - -quit: - ust_unlock(); - return; - -error: - ust_unlock(); - return; -} - -/* - * This thread does not allocate any resource, except within - * handle_message, within mutex protection. This mutex protects against - * fork and exit. - * The other moment it allocates resources is at socket connexion, which - * is also protected by the mutex. - */ -static -void *ust_listener_thread(void *arg) -{ - struct sock_info *sock_info = arg; - int sock, ret, prev_connect_failed = 0, has_waited = 0; - - /* Restart trying to connect to the session daemon */ -restart: - if (prev_connect_failed) { - /* Wait for sessiond availability with pipe */ - wait_for_sessiond(sock_info); - if (has_waited) { - has_waited = 0; - /* - * Sleep for 5 seconds before retrying after a - * sequence of failure / wait / failure. This - * deals with a killed or broken session daemon. - */ - sleep(5); - } - has_waited = 1; - prev_connect_failed = 0; - } - ust_lock(); - - if (lttng_ust_comm_should_quit) { - ust_unlock(); - goto quit; - } - - if (sock_info->socket != -1) { - ret = close(sock_info->socket); - if (ret) { - ERR("Error closing %s apps socket", sock_info->name); - } - sock_info->socket = -1; - } - - /* Register */ - ret = ustcomm_connect_unix_sock(sock_info->sock_path); - if (ret < 0) { - ERR("Error connecting to %s apps socket", sock_info->name); - prev_connect_failed = 1; - /* - * If we cannot find the sessiond daemon, don't delay - * constructor execution. - */ - ret = handle_register_done(sock_info); - assert(!ret); - ust_unlock(); - goto restart; - } - - sock_info->socket = sock = ret; - - /* - * Create only one root handle per listener thread for the whole - * process lifetime. - */ - if (sock_info->root_handle == -1) { - ret = lttng_abi_create_root_handle(); - if (ret < 0) { - ERR("Error creating root handle"); - ust_unlock(); - goto quit; - } - sock_info->root_handle = ret; - } - - ret = register_app_to_sessiond(sock); - if (ret < 0) { - ERR("Error registering to %s apps socket", sock_info->name); - prev_connect_failed = 1; - /* - * If we cannot register to the sessiond daemon, don't - * delay constructor execution. - */ - ret = handle_register_done(sock_info); - assert(!ret); - ust_unlock(); - goto restart; - } - ust_unlock(); - - for (;;) { - ssize_t len; - struct ustcomm_ust_msg lum; - - len = ustcomm_recv_unix_sock(sock, &lum, sizeof(lum)); - switch (len) { - case 0: /* orderly shutdown */ - DBG("%s ltt-sessiond has performed an orderly shutdown\n", sock_info->name); - goto end; - case sizeof(lum): - DBG("message received\n"); - ret = handle_message(sock_info, sock, &lum); - if (ret < 0) { - ERR("Error handling message for %s socket", sock_info->name); - } - continue; - case -1: - if (errno == ECONNRESET) { - ERR("%s remote end closed connection\n", sock_info->name); - goto end; - } - goto end; - default: - ERR("incorrect message size (%s socket): %zd\n", sock_info->name, len); - continue; - } - - } -end: - goto restart; /* try to reconnect */ -quit: - return NULL; -} - -/* - * Return values: -1: don't wait. 0: wait forever. 1: timeout wait. - */ -static -int get_timeout(struct timespec *constructor_timeout) -{ - long constructor_delay_ms = LTTNG_UST_DEFAULT_CONSTRUCTOR_TIMEOUT_MS; - char *str_delay; - int ret; - - str_delay = getenv("UST_REGISTER_TIMEOUT"); - if (str_delay) { - constructor_delay_ms = strtol(str_delay, NULL, 10); - } - - switch (constructor_delay_ms) { - case -1:/* fall-through */ - case 0: - return constructor_delay_ms; - default: - break; - } - - /* - * If we are unable to find the current time, don't wait. - */ - ret = clock_gettime(CLOCK_REALTIME, constructor_timeout); - if (ret) { - return -1; - } - constructor_timeout->tv_sec += constructor_delay_ms / 1000UL; - constructor_timeout->tv_nsec += - (constructor_delay_ms % 1000UL) * 1000000UL; - if (constructor_timeout->tv_nsec >= 1000000000UL) { - constructor_timeout->tv_sec++; - constructor_timeout->tv_nsec -= 1000000000UL; - } - return 1; -} - -/* - * sessiond monitoring thread: monitor presence of global and per-user - * sessiond by polling the application common named pipe. - */ -/* TODO */ - -void __attribute__((constructor)) lttng_ust_init(void) -{ - struct timespec constructor_timeout; - int timeout_mode; - int ret; - - if (uatomic_xchg(&initialized, 1) == 1) - return; - - /* - * We want precise control over the order in which we construct - * our sub-libraries vs starting to receive commands from - * sessiond (otherwise leading to errors when trying to create - * sessiond before the init functions are completed). - */ - init_usterr(); - init_tracepoint(); - ltt_ring_buffer_metadata_client_init(); - ltt_ring_buffer_client_overwrite_init(); - ltt_ring_buffer_client_discard_init(); - - timeout_mode = get_timeout(&constructor_timeout); - - ret = sem_init(&constructor_wait, 0, 0); - assert(!ret); - - ret = setup_local_apps(); - if (ret) { - ERR("Error setting up to local apps"); - } - ret = pthread_create(&local_apps.ust_listener, NULL, - ust_listener_thread, &local_apps); - - if (local_apps.allowed) { - ret = pthread_create(&global_apps.ust_listener, NULL, - ust_listener_thread, &global_apps); - } else { - handle_register_done(&local_apps); - } - - switch (timeout_mode) { - case 1: /* timeout wait */ - do { - ret = sem_timedwait(&constructor_wait, - &constructor_timeout); - } while (ret < 0 && errno == EINTR); - if (ret < 0 && errno == ETIMEDOUT) { - ERR("Timed out waiting for ltt-sessiond"); - } else { - assert(!ret); - } - break; - case -1:/* wait forever */ - do { - ret = sem_wait(&constructor_wait); - } while (ret < 0 && errno == EINTR); - assert(!ret); - break; - case 0: /* no timeout */ - break; - } -} - -static -void lttng_ust_cleanup(int exiting) -{ - cleanup_sock_info(&global_apps); - if (local_apps.allowed) { - cleanup_sock_info(&local_apps); - } - lttng_ust_abi_exit(); - lttng_ust_events_exit(); - ltt_ring_buffer_client_discard_exit(); - ltt_ring_buffer_client_overwrite_exit(); - ltt_ring_buffer_metadata_client_exit(); - exit_tracepoint(); - if (!exiting) { - /* Reinitialize values for fork */ - sem_count = 2; - lttng_ust_comm_should_quit = 0; - initialized = 0; - } -} - -void __attribute__((destructor)) lttng_ust_exit(void) -{ - int ret; - - /* - * Using pthread_cancel here because: - * A) we don't want to hang application teardown. - * B) the thread is not allocating any resource. - */ - - /* - * Require the communication thread to quit. Synchronize with - * mutexes to ensure it is not in a mutex critical section when - * pthread_cancel is later called. - */ - ust_lock(); - lttng_ust_comm_should_quit = 1; - ust_unlock(); - - ret = pthread_cancel(global_apps.ust_listener); - if (ret) { - ERR("Error cancelling global ust listener thread"); - } - if (local_apps.allowed) { - ret = pthread_cancel(local_apps.ust_listener); - if (ret) { - ERR("Error cancelling local ust listener thread"); - } - } - lttng_ust_cleanup(1); -} - -/* - * We exclude the worker threads across fork and clone (except - * CLONE_VM), because these system calls only keep the forking thread - * running in the child. Therefore, we don't want to call fork or clone - * in the middle of an tracepoint or ust tracing state modification. - * Holding this mutex protects these structures across fork and clone. - */ -void ust_before_fork(ust_fork_info_t *fork_info) -{ - /* - * Disable signals. This is to avoid that the child intervenes - * before it is properly setup for tracing. It is safer to - * disable all signals, because then we know we are not breaking - * anything by restoring the original mask. - */ - sigset_t all_sigs; - int ret; - - /* Disable signals */ - sigfillset(&all_sigs); - ret = sigprocmask(SIG_BLOCK, &all_sigs, &fork_info->orig_sigs); - if (ret == -1) { - PERROR("sigprocmask"); - } - ust_lock(); - rcu_bp_before_fork(); -} - -static void ust_after_fork_common(ust_fork_info_t *fork_info) -{ - int ret; - - DBG("process %d", getpid()); - ust_unlock(); - /* Restore signals */ - ret = sigprocmask(SIG_SETMASK, &fork_info->orig_sigs, NULL); - if (ret == -1) { - PERROR("sigprocmask"); - } -} - -void ust_after_fork_parent(ust_fork_info_t *fork_info) -{ - DBG("process %d", getpid()); - rcu_bp_after_fork_parent(); - /* Release mutexes and reenable signals */ - ust_after_fork_common(fork_info); -} - -/* - * After fork, in the child, we need to cleanup all the leftover state, - * except the worker thread which already magically disappeared thanks - * to the weird Linux fork semantics. After tyding up, we call - * lttng_ust_init() again to start over as a new PID. - * - * This is meant for forks() that have tracing in the child between the - * fork and following exec call (if there is any). - */ -void ust_after_fork_child(ust_fork_info_t *fork_info) -{ - DBG("process %d", getpid()); - /* Release urcu mutexes */ - rcu_bp_after_fork_child(); - lttng_ust_cleanup(0); - lttng_context_vtid_reset(); - /* Release mutexes and reenable signals */ - ust_after_fork_common(fork_info); - lttng_ust_init(); -} diff --git a/libust/probes/lttng-probe-ust.c b/libust/probes/lttng-probe-ust.c deleted file mode 100644 index a5fba868..00000000 --- a/libust/probes/lttng-probe-ust.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * probes/lttng-probe-ust.c - * - * Copyright 2010 (c) - Mathieu Desnoyers - * - * LTTng UST core probes. - * - * Dual LGPL v2.1/GPL v2 license. - */ - -/* - * Create LTTng tracepoint probes. - */ -#define TRACEPOINT_CREATE_PROBES - -#include "lttng-probe-ust.h" diff --git a/libust/probes/lttng-probe-ust.h b/libust/probes/lttng-probe-ust.h deleted file mode 100644 index 3394d086..00000000 --- a/libust/probes/lttng-probe-ust.h +++ /dev/null @@ -1,51 +0,0 @@ -#undef TRACEPOINT_SYSTEM -#define TRACEPOINT_SYSTEM lttng_ust - -#if !defined(_TRACEPOINT_LTTNG_UST_H) || defined(TRACEPOINT_HEADER_MULTI_READ) -#define _TRACEPOINT_LTTNG_UST_H - -/* - * Copyright (C) 2011 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 of - * the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -TRACEPOINT_EVENT(lttng_metadata, - - TP_PROTO(const char *str), - - TP_ARGS(str), - - /* - * Not exactly a string: more a sequence of bytes (dynamic - * array) without the length. This is a dummy anyway: we only - * use this declaration to generate an event metadata entry. - */ - TP_FIELDS( - ctf_string(str, str) - ) -) - -#undef TRACEPOINT_INCLUDE_PATH -#define TRACEPOINT_INCLUDE_PATH ./probes -#undef TRACEPOINT_INCLUDE_FILE -#define TRACEPOINT_INCLUDE_FILE lttng-probe-ust - -#endif /* _TRACEPOINT_LTTNG_UST_H */ - -/* This part must be outside protection */ -#include diff --git a/libust/tracepoint.c b/libust/tracepoint.c deleted file mode 100644 index 8bf87528..00000000 --- a/libust/tracepoint.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright (C) 2008-2011 Mathieu Desnoyers - * Copyright (C) 2009 Pierre-Marc Fournier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Ported to userspace by Pierre-Marc Fournier. - */ - -#define _LGPL_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ltt-tracer-core.h" - -/* Set to 1 to enable tracepoint debug output */ -static const int tracepoint_debug; -static int initialized; -static void (*new_tracepoint_cb)(struct tracepoint *); - -/* libraries that contain tracepoints (struct tracepoint_lib) */ -static CDS_LIST_HEAD(libs); - -/* - * The UST lock protects the library tracepoints, the hash table, and - * the library list. - * All calls to the tracepoint API must be protected by the UST lock, - * excepts calls to tracepoint_register_lib and - * tracepoint_unregister_lib, which take the UST lock themselves. - */ - -/* - * Tracepoint hash table, containing the active tracepoints. - * Protected by tracepoints_mutex. - */ -#define TRACEPOINT_HASH_BITS 6 -#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) -static struct cds_hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE]; - -static CDS_LIST_HEAD(old_probes); -static int need_update; - -/* - * Note about RCU : - * It is used to to delay the free of multiple probes array until a quiescent - * state is reached. - * Tracepoint entries modifications are protected by the tracepoints_mutex. - */ -struct tracepoint_entry { - struct cds_hlist_node hlist; - struct tracepoint_probe *probes; - int refcount; /* Number of times armed. 0 if disarmed. */ - char name[0]; -}; - -struct tp_probes { - union { - struct cds_list_head list; - } u; - struct tracepoint_probe probes[0]; -}; - -static inline void *allocate_probes(int count) -{ - struct tp_probes *p = zmalloc(count * sizeof(struct tracepoint_probe) - + sizeof(struct tp_probes)); - return p == NULL ? NULL : p->probes; -} - -static inline void release_probes(void *old) -{ - if (old) { - struct tp_probes *tp_probes = _ust_container_of(old, - struct tp_probes, probes[0]); - synchronize_rcu(); - free(tp_probes); - } -} - -static void debug_print_probes(struct tracepoint_entry *entry) -{ - int i; - - if (!tracepoint_debug || !entry->probes) - return; - - for (i = 0; entry->probes[i].func; i++) - DBG("Probe %d : %p", i, entry->probes[i].func); -} - -static void * -tracepoint_entry_add_probe(struct tracepoint_entry *entry, - void *probe, void *data) -{ - int nr_probes = 0; - struct tracepoint_probe *old, *new; - - WARN_ON(!probe); - - debug_print_probes(entry); - old = entry->probes; - if (old) { - /* (N -> N+1), (N != 0, 1) probes */ - for (nr_probes = 0; old[nr_probes].func; nr_probes++) - if (old[nr_probes].func == probe && - old[nr_probes].data == data) - return ERR_PTR(-EEXIST); - } - /* + 2 : one for new probe, one for NULL func */ - new = allocate_probes(nr_probes + 2); - if (new == NULL) - return ERR_PTR(-ENOMEM); - if (old) - memcpy(new, old, nr_probes * sizeof(struct tracepoint_probe)); - new[nr_probes].func = probe; - new[nr_probes].data = data; - new[nr_probes + 1].func = NULL; - entry->refcount = nr_probes + 1; - entry->probes = new; - debug_print_probes(entry); - return old; -} - -static void * -tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe, - void *data) -{ - int nr_probes = 0, nr_del = 0, i; - struct tracepoint_probe *old, *new; - - old = entry->probes; - - if (!old) - return ERR_PTR(-ENOENT); - - debug_print_probes(entry); - /* (N -> M), (N > 1, M >= 0) probes */ - for (nr_probes = 0; old[nr_probes].func; nr_probes++) { - if (!probe || - (old[nr_probes].func == probe && - old[nr_probes].data == data)) - nr_del++; - } - - if (nr_probes - nr_del == 0) { - /* N -> 0, (N > 1) */ - entry->probes = NULL; - entry->refcount = 0; - debug_print_probes(entry); - return old; - } else { - int j = 0; - /* N -> M, (N > 1, M > 0) */ - /* + 1 for NULL */ - new = allocate_probes(nr_probes - nr_del + 1); - if (new == NULL) - return ERR_PTR(-ENOMEM); - for (i = 0; old[i].func; i++) - if (probe && - (old[i].func != probe || old[i].data != data)) - new[j++] = old[i]; - new[nr_probes - nr_del].func = NULL; - entry->refcount = nr_probes - nr_del; - entry->probes = new; - } - debug_print_probes(entry); - return old; -} - -/* - * Get tracepoint if the tracepoint is present in the tracepoint hash table. - * Must be called with tracepoints_mutex held. - * Returns NULL if not present. - */ -static struct tracepoint_entry *get_tracepoint(const char *name) -{ - struct cds_hlist_head *head; - struct cds_hlist_node *node; - struct tracepoint_entry *e; - u32 hash = jhash(name, strlen(name), 0); - - head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; - cds_hlist_for_each_entry(e, node, head, hlist) { - if (!strcmp(name, e->name)) - return e; - } - return NULL; -} - -/* - * Add the tracepoint to the tracepoint hash table. Must be called with - * tracepoints_mutex held. - */ -static struct tracepoint_entry *add_tracepoint(const char *name) -{ - struct cds_hlist_head *head; - struct cds_hlist_node *node; - struct tracepoint_entry *e; - size_t name_len = strlen(name) + 1; - u32 hash = jhash(name, name_len-1, 0); - - head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; - cds_hlist_for_each_entry(e, node, head, hlist) { - if (!strcmp(name, e->name)) { - DBG("tracepoint %s busy", name); - return ERR_PTR(-EEXIST); /* Already there */ - } - } - /* - * Using zmalloc here to allocate a variable length element. Could - * cause some memory fragmentation if overused. - */ - e = zmalloc(sizeof(struct tracepoint_entry) + name_len); - if (!e) - return ERR_PTR(-ENOMEM); - memcpy(&e->name[0], name, name_len); - e->probes = NULL; - e->refcount = 0; - cds_hlist_add_head(&e->hlist, head); - return e; -} - -/* - * Remove the tracepoint from the tracepoint hash table. Must be called with - * ust_lock held. - */ -static inline void remove_tracepoint(struct tracepoint_entry *e) -{ - cds_hlist_del(&e->hlist); - free(e); -} - -/* - * Sets the probe callback corresponding to one tracepoint. - */ -static void set_tracepoint(struct tracepoint_entry **entry, - struct tracepoint *elem, int active) -{ - WARN_ON(strcmp((*entry)->name, elem->name) != 0); - - /* - * rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new - * probe callbacks array is consistent before setting a pointer to it. - * This array is referenced by __DO_TRACE from - * include/linux/tracepoints.h. A matching cmm_smp_read_barrier_depends() - * is used. - */ - rcu_assign_pointer(elem->probes, (*entry)->probes); - elem->state = active; -} - -/* - * Disable a tracepoint and its probe callback. - * Note: only waiting an RCU period after setting elem->call to the empty - * function insures that the original callback is not used anymore. This insured - * by preempt_disable around the call site. - */ -static void disable_tracepoint(struct tracepoint *elem) -{ - elem->state = 0; - rcu_assign_pointer(elem->probes, NULL); -} - -/** - * tracepoint_update_probe_range - Update a probe range - * @begin: beginning of the range - * @end: end of the range - * - * Updates the probe callback corresponding to a range of tracepoints. - */ -static -void tracepoint_update_probe_range(struct tracepoint * const *begin, - struct tracepoint * const *end) -{ - struct tracepoint * const *iter; - struct tracepoint_entry *mark_entry; - - for (iter = begin; iter < end; iter++) { - if (!*iter) - continue; /* skip dummy */ - if (!(*iter)->name) { - disable_tracepoint(*iter); - continue; - } - mark_entry = get_tracepoint((*iter)->name); - if (mark_entry) { - set_tracepoint(&mark_entry, *iter, - !!mark_entry->refcount); - } else { - disable_tracepoint(*iter); - } - } -} - -static void lib_update_tracepoints(void) -{ - struct tracepoint_lib *lib; - - cds_list_for_each_entry(lib, &libs, list) { - tracepoint_update_probe_range(lib->tracepoints_start, - lib->tracepoints_start + lib->tracepoints_count); - } -} - -/* - * Update probes, removing the faulty probes. - */ -static void tracepoint_update_probes(void) -{ - /* tracepoints registered from libraries and executable. */ - lib_update_tracepoints(); -} - -static struct tracepoint_probe * -tracepoint_add_probe(const char *name, void *probe, void *data) -{ - struct tracepoint_entry *entry; - struct tracepoint_probe *old; - - entry = get_tracepoint(name); - if (!entry) { - entry = add_tracepoint(name); - if (IS_ERR(entry)) - return (struct tracepoint_probe *)entry; - } - old = tracepoint_entry_add_probe(entry, probe, data); - if (IS_ERR(old) && !entry->refcount) - remove_tracepoint(entry); - return old; -} - -/** - * __tracepoint_probe_register - Connect a probe to a tracepoint - * @name: tracepoint name - * @probe: probe handler - * - * Returns 0 if ok, error value on error. - * The probe address must at least be aligned on the architecture pointer size. - * Called with the UST lock held. - */ -int __tracepoint_probe_register(const char *name, void *probe, void *data) -{ - void *old; - - old = tracepoint_add_probe(name, probe, data); - if (IS_ERR(old)) - return PTR_ERR(old); - - tracepoint_update_probes(); /* may update entry */ - release_probes(old); - return 0; -} - -static void *tracepoint_remove_probe(const char *name, void *probe, void *data) -{ - struct tracepoint_entry *entry; - void *old; - - entry = get_tracepoint(name); - if (!entry) - return ERR_PTR(-ENOENT); - old = tracepoint_entry_remove_probe(entry, probe, data); - if (IS_ERR(old)) - return old; - if (!entry->refcount) - remove_tracepoint(entry); - return old; -} - -/** - * tracepoint_probe_unregister - Disconnect a probe from a tracepoint - * @name: tracepoint name - * @probe: probe function pointer - * @probe: probe data pointer - * - * Called with the UST lock held. - */ -int __tracepoint_probe_unregister(const char *name, void *probe, void *data) -{ - void *old; - - old = tracepoint_remove_probe(name, probe, data); - if (IS_ERR(old)) - return PTR_ERR(old); - - tracepoint_update_probes(); /* may update entry */ - release_probes(old); - return 0; -} - -static void tracepoint_add_old_probes(void *old) -{ - need_update = 1; - if (old) { - struct tp_probes *tp_probes = _ust_container_of(old, - struct tp_probes, probes[0]); - cds_list_add(&tp_probes->u.list, &old_probes); - } -} - -/** - * tracepoint_probe_register_noupdate - register a probe but not connect - * @name: tracepoint name - * @probe: probe handler - * - * caller must call tracepoint_probe_update_all() - * Called with the UST lock held. - */ -int tracepoint_probe_register_noupdate(const char *name, void *probe, - void *data) -{ - void *old; - - old = tracepoint_add_probe(name, probe, data); - if (IS_ERR(old)) { - return PTR_ERR(old); - } - tracepoint_add_old_probes(old); - return 0; -} - -/** - * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect - * @name: tracepoint name - * @probe: probe function pointer - * - * caller must call tracepoint_probe_update_all() - * Called with the UST lock held. - */ -int tracepoint_probe_unregister_noupdate(const char *name, void *probe, - void *data) -{ - void *old; - - old = tracepoint_remove_probe(name, probe, data); - if (IS_ERR(old)) { - return PTR_ERR(old); - } - tracepoint_add_old_probes(old); - return 0; -} - -/** - * tracepoint_probe_update_all - update tracepoints - * Called with the UST lock held. - */ -void tracepoint_probe_update_all(void) -{ - CDS_LIST_HEAD(release_probes); - struct tp_probes *pos, *next; - - if (!need_update) { - return; - } - if (!cds_list_empty(&old_probes)) - cds_list_replace_init(&old_probes, &release_probes); - need_update = 0; - - tracepoint_update_probes(); - cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) { - cds_list_del(&pos->u.list); - synchronize_rcu(); - free(pos); - } -} - -/* - * Returns 0 if current not found. - * Returns 1 if current found. - * - * Called with tracepoint mutex held - */ -int lib_get_iter_tracepoints(struct tracepoint_iter *iter) -{ - struct tracepoint_lib *iter_lib; - int found = 0; - - cds_list_for_each_entry(iter_lib, &libs, list) { - if (iter_lib < iter->lib) - continue; - else if (iter_lib > iter->lib) - iter->tracepoint = NULL; - found = tracepoint_get_iter_range(&iter->tracepoint, - iter_lib->tracepoints_start, - iter_lib->tracepoints_start + iter_lib->tracepoints_count); - if (found) { - iter->lib = iter_lib; - break; - } - } - return found; -} - -/** - * tracepoint_get_iter_range - Get a next tracepoint iterator given a range. - * @tracepoint: current tracepoints (in), next tracepoint (out) - * @begin: beginning of the range - * @end: end of the range - * - * Returns whether a next tracepoint has been found (1) or not (0). - * Will return the first tracepoint in the range if the input tracepoint is - * NULL. - * Called with tracepoint mutex held. - */ -int tracepoint_get_iter_range(struct tracepoint * const **tracepoint, - struct tracepoint * const *begin, struct tracepoint * const *end) -{ - if (!*tracepoint && begin != end) - *tracepoint = begin; - while (*tracepoint >= begin && *tracepoint < end) { - if (!**tracepoint) - (*tracepoint)++; /* skip dummy */ - else - return 1; - } - return 0; -} - -/* - * Called with tracepoint mutex held. - */ -static void tracepoint_get_iter(struct tracepoint_iter *iter) -{ - int found = 0; - - /* tracepoints in libs. */ - found = lib_get_iter_tracepoints(iter); - if (!found) - tracepoint_iter_reset(iter); -} - -/* - * Called with UST lock held. - */ -void tracepoint_iter_start(struct tracepoint_iter *iter) -{ - tracepoint_get_iter(iter); -} - -/* - * Called with UST lock held. - */ -void tracepoint_iter_next(struct tracepoint_iter *iter) -{ - iter->tracepoint++; - /* - * iter->tracepoint may be invalid because we blindly incremented it. - * Make sure it is valid by marshalling on the tracepoints, getting the - * tracepoints from following modules if necessary. - */ - tracepoint_get_iter(iter); -} - -/* - * Called with UST lock held. - */ -void tracepoint_iter_stop(struct tracepoint_iter *iter) -{ -} - -void tracepoint_iter_reset(struct tracepoint_iter *iter) -{ - iter->tracepoint = NULL; -} - -void tracepoint_set_new_tracepoint_cb(void (*cb)(struct tracepoint *)) -{ - new_tracepoint_cb = cb; -} - -static void new_tracepoints(struct tracepoint * const *start, struct tracepoint * const *end) -{ - if (new_tracepoint_cb) { - struct tracepoint * const *t; - - for (t = start; t < end; t++) { - if (*t) - new_tracepoint_cb(*t); - } - } -} - -int tracepoint_register_lib(struct tracepoint * const *tracepoints_start, - int tracepoints_count) -{ - struct tracepoint_lib *pl, *iter; - - init_tracepoint(); - - pl = (struct tracepoint_lib *) zmalloc(sizeof(struct tracepoint_lib)); - - pl->tracepoints_start = tracepoints_start; - pl->tracepoints_count = tracepoints_count; - - ust_lock(); - /* - * We sort the libs by struct lib pointer address. - */ - cds_list_for_each_entry_reverse(iter, &libs, list) { - BUG_ON(iter == pl); /* Should never be in the list twice */ - if (iter < pl) { - /* We belong to the location right after iter. */ - cds_list_add(&pl->list, &iter->list); - goto lib_added; - } - } - /* We should be added at the head of the list */ - cds_list_add(&pl->list, &libs); -lib_added: - new_tracepoints(tracepoints_start, tracepoints_start + tracepoints_count); - - /* TODO: update just the loaded lib */ - lib_update_tracepoints(); - ust_unlock(); - - DBG("just registered a tracepoints section from %p and having %d tracepoints", - tracepoints_start, tracepoints_count); - - return 0; -} - -int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start) -{ - struct tracepoint_lib *lib; - - ust_lock(); - cds_list_for_each_entry(lib, &libs, list) { - if (lib->tracepoints_start == tracepoints_start) { - struct tracepoint_lib *lib2free = lib; - cds_list_del(&lib->list); - free(lib2free); - break; - } - } - ust_unlock(); - - return 0; -} - -void init_tracepoint(void) -{ - if (uatomic_xchg(&initialized, 1) == 1) - return; - init_usterr(); -} - -void exit_tracepoint(void) -{ - initialized = 0; -} diff --git a/libust/ust-core.c b/libust/ust-core.c deleted file mode 100644 index b5cc8cf8..00000000 --- a/libust/ust-core.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ust-core.c - * - * Copyright (C) 2011 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; only - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -volatile enum ust_loglevel ust_loglevel; - -void init_usterr(void) -{ - char *ust_debug; - - if (ust_loglevel == UST_LOGLEVEL_UNKNOWN) { - ust_debug = getenv("UST_DEBUG"); - if (ust_debug) - ust_loglevel = UST_LOGLEVEL_DEBUG; - else - ust_loglevel = UST_LOGLEVEL_NORMAL; - } -} diff --git a/libustctl/Makefile.am b/libustctl/Makefile.am deleted file mode 100644 index 8101b573..00000000 --- a/libustctl/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/liblttng-ust-comm -AM_CFLAGS = -fno-strict-aliasing - -lib_LTLIBRARIES = libustctl.la - -libustctl_la_SOURCES = ustctl.c - -libustctl_la_LIBADD = $(top_builddir)/liblttng-ust-comm/liblttng-ust-comm.la \ - $(top_builddir)/libringbuffer/libringbuffer.la \ - $(top_builddir)/snprintf/libustsnprintf.la diff --git a/libustctl/ustctl.c b/libustctl/ustctl.c deleted file mode 100644 index 6f3d1ed9..00000000 --- a/libustctl/ustctl.c +++ /dev/null @@ -1,668 +0,0 @@ -/* - * Copyright (C) 2011 - Julien Desfossez - * Mathieu Desnoyers - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; only version 2 - * of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include - -#include "../libringbuffer/backend.h" -#include "../libringbuffer/frontend.h" - -volatile enum ust_loglevel ust_loglevel; - -static -void init_object(struct lttng_ust_object_data *data) -{ - data->handle = -1; - data->shm_fd = -1; - data->wait_fd = -1; - data->memory_map_size = 0; -} - -void release_object(int sock, struct lttng_ust_object_data *data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - int ret; - - if (data->shm_fd >= 0) - close(data->shm_fd); - if (data->wait_fd >= 0) - close(data->wait_fd); - memset(&lum, 0, sizeof(lum)); - lum.handle = data->handle; - lum.cmd = LTTNG_UST_RELEASE; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - assert(!ret); - free(data); -} - -/* - * Send registration done packet to the application. - */ -int ustctl_register_done(int sock) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - int ret; - - DBG("Sending register done command to %d", sock); - memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_REGISTER_DONE; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) - return ret; - if (lur.ret_code != USTCOMM_OK) { - DBG("Return code: %s", ustcomm_get_readable_code(lur.ret_code)); - goto error; - } - return 0; - -error: - return -1; -} - -/* - * returns session handle. - */ -int ustctl_create_session(int sock) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - int ret, session_handle; - - /* Create session */ - memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_SESSION; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) - return ret; - session_handle = lur.ret_val; - DBG("received session handle %u", session_handle); - return session_handle; -} - -/* open the metadata global channel */ -int ustctl_open_metadata(int sock, int session_handle, - struct lttng_ust_channel_attr *chops, - struct lttng_ust_object_data **_metadata_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *metadata_data; - int ret; - - metadata_data = malloc(sizeof(*metadata_data)); - if (!metadata_data) - return -ENOMEM; - init_object(metadata_data); - /* Create metadata channel */ - memset(&lum, 0, sizeof(lum)); - lum.handle = session_handle; - lum.cmd = LTTNG_UST_METADATA; - lum.u.channel.overwrite = chops->overwrite; - lum.u.channel.subbuf_size = chops->subbuf_size; - lum.u.channel.num_subbuf = chops->num_subbuf; - lum.u.channel.switch_timer_interval = chops->switch_timer_interval; - lum.u.channel.read_timer_interval = chops->read_timer_interval; - lum.u.channel.output = chops->output; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(metadata_data); - return ret; - } - if (lur.ret_code != USTCOMM_OK) { - free(metadata_data); - return lur.ret_code; - } - metadata_data->handle = lur.ret_val; - DBG("received metadata handle %u", metadata_data->handle); - metadata_data->memory_map_size = lur.u.channel.memory_map_size; - /* get shm fd */ - ret = ustcomm_recv_fd(sock); - if (ret < 0) - goto error; - metadata_data->shm_fd = ret; - /* get wait fd */ - ret = ustcomm_recv_fd(sock); - if (ret < 0) - goto error; - metadata_data->wait_fd = ret; - *_metadata_data = metadata_data; - return 0; - -error: - release_object(sock, metadata_data); - return -EINVAL; -} - -int ustctl_create_channel(int sock, int session_handle, - struct lttng_ust_channel_attr *chops, - struct lttng_ust_object_data **_channel_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *channel_data; - int ret; - - channel_data = malloc(sizeof(*channel_data)); - if (!channel_data) - return -ENOMEM; - init_object(channel_data); - /* Create metadata channel */ - memset(&lum, 0, sizeof(lum)); - lum.handle = session_handle; - lum.cmd = LTTNG_UST_CHANNEL; - lum.u.channel.overwrite = chops->overwrite; - lum.u.channel.subbuf_size = chops->subbuf_size; - lum.u.channel.num_subbuf = chops->num_subbuf; - lum.u.channel.switch_timer_interval = chops->switch_timer_interval; - lum.u.channel.read_timer_interval = chops->read_timer_interval; - lum.u.channel.output = chops->output; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(channel_data); - return ret; - } - if (lur.ret_code != USTCOMM_OK) { - free(channel_data); - return lur.ret_code; - } - channel_data->handle = lur.ret_val; - DBG("received channel handle %u", channel_data->handle); - channel_data->memory_map_size = lur.u.channel.memory_map_size; - /* get shm fd */ - ret = ustcomm_recv_fd(sock); - if (ret < 0) - goto error; - channel_data->shm_fd = ret; - /* get wait fd */ - ret = ustcomm_recv_fd(sock); - if (ret < 0) - goto error; - channel_data->wait_fd = ret; - *_channel_data = channel_data; - return 0; - -error: - release_object(sock, channel_data); - return -EINVAL; -} - -/* - * Return -ENOENT if no more stream is available for creation. - * Return 0 on success. - * Return negative error value on error. - */ -int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, - struct lttng_ust_object_data **_stream_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *stream_data; - int ret, fd; - - stream_data = malloc(sizeof(*stream_data)); - if (!stream_data) - return -ENOMEM; - init_object(stream_data); - memset(&lum, 0, sizeof(lum)); - lum.handle = channel_data->handle; - lum.cmd = LTTNG_UST_STREAM; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(stream_data); - return ret; - } - if (lur.ret_code != USTCOMM_OK) { - free(stream_data); - return lur.ret_code; - } - - stream_data->handle = lur.ret_val; - DBG("received stream handle %u", stream_data->handle); - stream_data->memory_map_size = lur.u.stream.memory_map_size; - /* get shm fd */ - fd = ustcomm_recv_fd(sock); - if (fd < 0) - goto error; - stream_data->shm_fd = fd; - /* get wait fd */ - fd = ustcomm_recv_fd(sock); - if (fd < 0) - goto error; - stream_data->wait_fd = fd; - *_stream_data = stream_data; - return ret; - -error: - release_object(sock, stream_data); - return -EINVAL; -} - -int ustctl_create_event(int sock, struct lttng_ust_event *ev, - struct lttng_ust_object_data *channel_data, - struct lttng_ust_object_data **_event_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *event_data; - int ret; - - event_data = malloc(sizeof(*event_data)); - if (!event_data) - return -ENOMEM; - init_object(event_data); - memset(&lum, 0, sizeof(lum)); - lum.handle = channel_data->handle; - lum.cmd = LTTNG_UST_EVENT; - strncpy(lum.u.event.name, ev->name, - LTTNG_UST_SYM_NAME_LEN); - lum.u.event.instrumentation = ev->instrumentation; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(event_data); - return ret; - } - event_data->handle = lur.ret_val; - DBG("received event handle %u", event_data->handle); - *_event_data = event_data; - return 0; -} - -int ustctl_add_context(int sock, struct lttng_ust_context *ctx, - struct lttng_ust_object_data *obj_data, - struct lttng_ust_object_data **_context_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *context_data; - int ret; - - context_data = malloc(sizeof(*context_data)); - if (!context_data) - return -ENOMEM; - init_object(context_data); - memset(&lum, 0, sizeof(lum)); - lum.handle = obj_data->handle; - lum.cmd = LTTNG_UST_CONTEXT; - lum.u.context.ctx = ctx->ctx; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(context_data); - return ret; - } - context_data->handle = lur.ret_val; - DBG("received context handle %u", context_data->handle); - *_context_data = context_data; - return ret; -} - -/* Enable event, channel and session ioctl */ -int ustctl_enable(int sock, struct lttng_ust_object_data *object) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - int ret; - - memset(&lum, 0, sizeof(lum)); - lum.handle = object->handle; - lum.cmd = LTTNG_UST_ENABLE; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) - return ret; - DBG("enabled handle %u", object->handle); - return 0; -} - -/* Disable event, channel and session ioctl */ -int ustctl_disable(int sock, struct lttng_ust_object_data *object) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - int ret; - - memset(&lum, 0, sizeof(lum)); - lum.handle = object->handle; - lum.cmd = LTTNG_UST_DISABLE; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) - return ret; - DBG("disable handle %u", object->handle); - return 0; -} - -int ustctl_start_session(int sock, int handle) -{ - struct lttng_ust_object_data obj; - - obj.handle = handle; - return ustctl_enable(sock, &obj); -} - -int ustctl_stop_session(int sock, int handle) -{ - struct lttng_ust_object_data obj; - - obj.handle = handle; - return ustctl_disable(sock, &obj); -} - - -int ustctl_tracepoint_list(int sock) -{ - return -ENOSYS; /* not implemented */ -} - -int ustctl_tracer_version(int sock, struct lttng_ust_tracer_version *v) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - int ret; - - memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_TRACER_VERSION; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) - return ret; - memcpy(v, &lur.u.version, sizeof(*v)); - DBG("received tracer version"); - return 0; -} - -int ustctl_wait_quiescent(int sock) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - int ret; - - memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_WAIT_QUIESCENT; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) - return ret; - DBG("waited for quiescent state"); - return 0; -} - -int ustctl_flush_buffer(int sock, struct lttng_ust_object_data *channel_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - - memset(&lum, 0, sizeof(lum)); - lum.handle = channel_data->handle; - lum.cmd = LTTNG_UST_FLUSH_BUFFER; - return ustcomm_send_app_cmd(sock, &lum, &lur); -} - -int ustctl_calibrate(int sock, struct lttng_ust_calibrate *calibrate) -{ - return -ENOSYS; -} - -/* Buffer operations */ - -/* Map channel shm into process memory */ -struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *chan_data) -{ - struct lttng_ust_shm_handle *handle; - struct channel *chan; - size_t chan_size; - - handle = channel_handle_create(chan_data->shm_fd, - chan_data->wait_fd, - chan_data->memory_map_size); - if (!handle) { - ERR("create handle error"); - return NULL; - } - /* - * Set to -1 because the lttng_ust_shm_handle destruction will take care - * of closing shm_fd and wait_fd. - */ - chan_data->shm_fd = -1; - chan_data->wait_fd = -1; - - /* - * TODO: add consistency checks to be resilient if the - * application try to feed us with incoherent channel structure - * values. - */ - chan = shmp(handle, handle->chan); - /* chan is object 0. This is hardcoded. */ - chan_size = handle->table->objects[0].allocated_len; - handle->shadow_chan = malloc(chan_size); - if (!handle->shadow_chan) { - channel_destroy(chan, handle, 1); - return NULL; - } - memcpy(handle->shadow_chan, chan, chan_size); - return handle; -} - -/* Add stream to channel shm and map its shm into process memory */ -int ustctl_add_stream(struct lttng_ust_shm_handle *handle, - struct lttng_ust_object_data *stream_data) -{ - int ret; - - if (!stream_data->handle) - return -ENOENT; - /* map stream */ - ret = channel_handle_add_stream(handle, - stream_data->shm_fd, - stream_data->wait_fd, - stream_data->memory_map_size); - if (ret) { - ERR("add stream error\n"); - return ret; - } - /* - * Set to -1 because the lttng_ust_shm_handle destruction will take care - * of closing shm_fd and wait_fd. - */ - stream_data->shm_fd = -1; - stream_data->wait_fd = -1; - return 0; -} - -void ustctl_unmap_channel(struct lttng_ust_shm_handle *handle) -{ - struct channel *chan; - - chan = shmp(handle, handle->chan); - channel_destroy(chan, handle, 1); -} - -struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_handle *handle, - int cpu) -{ - struct channel *chan = handle->shadow_chan; - int shm_fd, wait_fd; - uint64_t memory_map_size; - struct lttng_ust_lib_ring_buffer *buf; - int ret; - - buf = channel_get_ring_buffer(&chan->backend.config, - chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); - if (!buf) - return NULL; - ret = lib_ring_buffer_open_read(buf, handle, 1); - if (ret) - return NULL; - return buf; -} - -void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) -{ - lib_ring_buffer_release_read(buf, handle, 1); -} - -/* For mmap mode, readable without "get" operation */ - -void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) -{ - return shmp(handle, buf->backend.memory_map); -} - -/* returns the length to mmap. */ -int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, - unsigned long *len) -{ - unsigned long mmap_buf_len; - struct channel *chan = handle->shadow_chan; - - if (chan->backend.config.output != RING_BUFFER_MMAP) - return -EINVAL; - mmap_buf_len = chan->backend.buf_size; - if (chan->backend.extra_reader_sb) - mmap_buf_len += chan->backend.subbuf_size; - if (mmap_buf_len > INT_MAX) - return -EFBIG; - *len = mmap_buf_len; - return 0; -} - -/* returns the maximum size for sub-buffers. */ -int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, - unsigned long *len) -{ - struct channel *chan = handle->shadow_chan; - - *len = chan->backend.subbuf_size; - return 0; -} - -/* - * For mmap mode, operate on the current packet (between get/put or - * get_next/put_next). - */ - -/* returns the offset of the subbuffer belonging to the mmap reader. */ -int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *off) -{ - struct channel *chan = handle->shadow_chan; - unsigned long sb_bindex; - - if (chan->backend.config.output != RING_BUFFER_MMAP) - return -EINVAL; - sb_bindex = subbuffer_id_get_index(&chan->backend.config, - buf->backend.buf_rsb.id); - *off = shmp(handle, shmp_index(handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; - return 0; -} - -/* returns the size of the current sub-buffer, without padding (for mmap). */ -int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) -{ - struct channel *chan = handle->shadow_chan; - - *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, - handle); - return 0; -} - -/* returns the size of the current sub-buffer, without padding (for mmap). */ -int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) -{ - struct channel *chan = handle->shadow_chan; - - *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, - handle); - *len = PAGE_ALIGN(*len); - return 0; -} - -/* Get exclusive read access to the next sub-buffer that can be read. */ -int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) -{ - return lib_ring_buffer_get_next_subbuf(buf, handle); -} - - -/* Release exclusive sub-buffer access, move consumer forward. */ -int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) -{ - lib_ring_buffer_put_next_subbuf(buf, handle); - return 0; -} - -/* snapshot */ - -/* Get a snapshot of the current ring buffer producer and consumer positions */ -int ustctl_snapshot(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) -{ - return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot, - &buf->prod_snapshot, handle); -} - -/* Get the consumer position (iteration start) */ -int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) -{ - *pos = buf->cons_snapshot; - return 0; -} - -/* Get the producer position (iteration end) */ -int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) -{ - *pos = buf->prod_snapshot; - return 0; -} - -/* Get exclusive read access to the specified sub-buffer position */ -int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) -{ - return lib_ring_buffer_get_subbuf(buf, *pos, handle); -} - -/* Release exclusive sub-buffer access */ -int ustctl_put_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) -{ - lib_ring_buffer_put_subbuf(buf, handle); - return 0; -} - -int ustctl_buffer_flush(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) -{ - lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE, handle); - return 0; -} diff --git a/libustfork/Makefile.am b/libustfork/Makefile.am deleted file mode 100644 index f2a9996e..00000000 --- a/libustfork/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -AM_CFLAGS = -fno-strict-aliasing - -lib_LTLIBRARIES = libustfork.la -libustfork_la_SOURCES = ustfork.c -libustfork_la_LIBADD = \ - -ldl \ - $(top_builddir)/libust/libust.la -libustfork_CFLAGS = -DUST_COMPONENT=libustfork -fno-strict-aliasing diff --git a/libustfork/ustfork.c b/libustfork/ustfork.c deleted file mode 100644 index 5e6acba1..00000000 --- a/libustfork/ustfork.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2009 Pierre-Marc Fournier - * Copyright (C) 2011 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 of - * the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include "usterr.h" - -#include - -struct user_desc; - -pid_t fork(void) -{ - static pid_t (*plibc_func)(void) = NULL; - ust_fork_info_t fork_info; - pid_t retval; - - if (plibc_func == NULL) { - plibc_func = dlsym(RTLD_NEXT, "fork"); - if (plibc_func == NULL) { - fprintf(stderr, "libustfork: unable to find \"fork\" symbol\n"); - return -1; - } - } - - ust_before_fork(&fork_info); - /* Do the real fork */ - retval = plibc_func(); - if (retval == 0) { - /* child */ - ust_after_fork_child(&fork_info); - } else { - ust_after_fork_parent(&fork_info); - } - return retval; -} - -struct ustfork_clone_info { - int (*fn)(void *); - void *arg; - ust_fork_info_t fork_info; -}; - -static int clone_fn(void *arg) -{ - struct ustfork_clone_info *info = (struct ustfork_clone_info *) arg; - - /* clone is now done and we are in child */ - ust_after_fork_child(&info->fork_info); - return info->fn(info->arg); -} - -int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) -{ - static int (*plibc_func)(int (*fn)(void *), void *child_stack, - int flags, void *arg, pid_t *ptid, - struct user_desc *tls, pid_t *ctid) = NULL; - /* var args */ - pid_t *ptid; - struct user_desc *tls; - pid_t *ctid; - /* end of var args */ - va_list ap; - int retval; - - va_start(ap, arg); - ptid = va_arg(ap, pid_t *); - tls = va_arg(ap, struct user_desc *); - ctid = va_arg(ap, pid_t *); - va_end(ap); - - if (plibc_func == NULL) { - plibc_func = dlsym(RTLD_NEXT, "clone"); - if (plibc_func == NULL) { - fprintf(stderr, "libustfork: unable to find \"clone\" symbol.\n"); - return -1; - } - } - - if (flags & CLONE_VM) { - /* - * Creating a thread, no need to intervene, just pass on - * the arguments. - */ - retval = plibc_func(fn, child_stack, flags, arg, ptid, - tls, ctid); - } else { - /* Creating a real process, we need to intervene. */ - struct ustfork_clone_info info = { fn: fn, arg: arg }; - - ust_before_fork(&info.fork_info); - retval = plibc_func(clone_fn, child_stack, flags, &info, - ptid, tls, ctid); - /* The child doesn't get here. */ - ust_after_fork_parent(&info.fork_info); - } - return retval; -} diff --git a/libustinstr-malloc/Makefile.am b/libustinstr-malloc/Makefile.am deleted file mode 100644 index 26c73e0a..00000000 --- a/libustinstr-malloc/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -AM_CFLAGS = -fno-strict-aliasing - -lib_LTLIBRARIES = libustinstr-malloc.la -libustinstr_malloc_la_SOURCES = mallocwrap.c -libustinstr_malloc_la_LIBADD = -ldl - -noinst_SCRIPTS = run -EXTRA_DIST = run diff --git a/libustinstr-malloc/README b/libustinstr-malloc/README deleted file mode 100644 index c58a7e6a..00000000 --- a/libustinstr-malloc/README +++ /dev/null @@ -1,9 +0,0 @@ -libustinstr-malloc is used for instrumenting calls to malloc(3) in a program, -without need for recompiling it. - -libustinstr-malloc defines a malloc() function that is instrumented with a -marker. It also calls the libc malloc afterwards. When loaded with LD_PRELOAD, -it replaces the libc malloc() function, in effect instrumenting all calls to -malloc(). - -See the "run" script for a usage example. diff --git a/libustinstr-malloc/mallocwrap.c b/libustinstr-malloc/mallocwrap.c deleted file mode 100644 index 6e668569..00000000 --- a/libustinstr-malloc/mallocwrap.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2009 Pierre-Marc Fournier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define _GNU_SOURCE -#include -#include -#include -#include - -void *malloc(size_t size) -{ - static void *(*plibc_malloc)(size_t size) = NULL; - void *retval; - - if (plibc_malloc == NULL) { - plibc_malloc = dlsym(RTLD_NEXT, "malloc"); - if (plibc_malloc == NULL) { - fprintf(stderr, "mallocwrap: unable to find malloc\n"); - return NULL; - } - } - - retval = plibc_malloc(size); - - ust_marker(malloc, "size %d ptr %p", (int)size, retval); - - return retval; -} - -void free(void *ptr) -{ - static void *(*plibc_free)(void *ptr) = NULL; - - if (plibc_free == NULL) { - plibc_free = dlsym(RTLD_NEXT, "free"); - if (plibc_free == NULL) { - fprintf(stderr, "mallocwrap: unable to find free\n"); - return; - } - } - - ust_marker(free, "ptr %p", ptr); - - plibc_free(ptr); -} - -UST_MARKER_LIB diff --git a/libustinstr-malloc/run b/libustinstr-malloc/run deleted file mode 100644 index ce4fd100..00000000 --- a/libustinstr-malloc/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -LD_VERBOSE=1 LD_LIBRARY_PATH=.:../libust/.libs:../../liburcu LD_PRELOAD=liburcu.so:libust.so:.libs/libmallocwrap.so $1 diff --git a/libustjava/.gitignore b/libustjava/.gitignore deleted file mode 100644 index ab97d041..00000000 --- a/libustjava/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -UST.class -UST.h diff --git a/libustjava/Makefile.am b/libustjava/Makefile.am deleted file mode 100644 index cb2c1b89..00000000 --- a/libustjava/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -if BUILD_JNI_INTERFACE - -AM_CPPFLAGS = -I$(top_srcdir)/include - -lib_LTLIBRARIES = libustjava.la -libustjava_la_SOURCES = UST.c UST.h ust_java.h -dist_noinst_DATA = UST.java -libustjava_la_LIBADD = -lc -L$(top_builddir)/libust/.libs -lust - -all: UST.class UST.h - -clean-local: - rm -rf UST.h UST.class - -UST.class: UST.java - javac -d "$(builddir)" "$(srcdir)/UST.java" - -UST.h: UST.class - javah -jni UST - -endif diff --git a/libustjava/README b/libustjava/README deleted file mode 100644 index 37834e69..00000000 --- a/libustjava/README +++ /dev/null @@ -1,12 +0,0 @@ -This directory contains a simple API for instrumenting java applications. - -Configuration examples to build this library: - -dependency: sun-java6-jdk -./configure --with-java-jdk=/usr/lib/jvm/java-6-sun --with-jni-interface - -dependency: openjdk-6-jdk -./configure --with-java-jdk=/usr/lib/jvm/java-6-openjdk --with-jni-interface - -dependency: gcj-4.4-jdk -./configure --with-java-jdk=/usr/lib/jvm/java-gcj --with-jni-interface diff --git a/libustjava/UST.c b/libustjava/UST.c deleted file mode 100644 index 7ad1c717..00000000 --- a/libustjava/UST.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#define TRACEPOINT_CREATE_PROBES -#include "ust_java.h" - -JNIEXPORT void JNICALL Java_UST_ust_1java_1event (JNIEnv *env, jobject jobj, - jstring ev_name, jstring args) -{ - jboolean iscopy; - const char *ev_name_cstr = (*env)->GetStringUTFChars(env, ev_name, - &iscopy); - const char *args_cstr = (*env)->GetStringUTFChars(env, args, &iscopy); - - tracepoint(ust_java_event, ev_name_cstr, args_cstr); -} diff --git a/libustjava/UST.java b/libustjava/UST.java deleted file mode 100644 index be5f7c73..00000000 --- a/libustjava/UST.java +++ /dev/null @@ -1,9 +0,0 @@ -import java.util.*; - -class UST { - public static native void ust_java_event(String name, String arg); - static { - System.loadLibrary("ustjava"); - } -} - diff --git a/libustjava/ust_java.h b/libustjava/ust_java.h deleted file mode 100644 index 366b3737..00000000 --- a/libustjava/ust_java.h +++ /dev/null @@ -1,44 +0,0 @@ -#undef TRACEPOINT_SYSTEM -#define TRACEPOINT_SYSTEM ust_java - -#if !defined(_TRACEPOINT_UST_JAVA_H) || defined(TRACEPOINT_HEADER_MULTI_READ) -#define _TRACEPOINT_UST_JAVA_H - -/* - * Copyright (C) 2011 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 of - * the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -TRACEPOINT_EVENT(ust_java_event, - TP_PROTO(const char *name, const char *args), - TP_ARGS(name, args), - TP_FIELDS( - ctf_string(name, name) - ctf_string(args, args) - ) -) - -#endif /* _TRACEPOINT_UST_JAVA_H */ - -#undef TRACEPOINT_INCLUDE_PATH -#define TRACEPOINT_INCLUDE_PATH . -#undef TRACEPOINT_INCLUDE_FILE -#define TRACEPOINT_INCLUDE_FILE ust_java - -/* This part must be outside protection */ -#include diff --git a/tests/fork/Makefile.am b/tests/fork/Makefile.am index 1898f219..29464f41 100644 --- a/tests/fork/Makefile.am +++ b/tests/fork/Makefile.am @@ -2,9 +2,11 @@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_PROGRAMS = fork fork2 fork_SOURCES = fork.c ust_tests_fork.h -fork_LDADD = $(top_builddir)/libust/libust.la $(top_builddir)/libustfork/libustfork.la +fork_LDADD = $(top_builddir)/liblttng-ust/liblttng-ust.la \ + $(top_builddir)/liblttng-ust-fork/liblttng-ust-fork.la fork2_SOURCES = fork2.c -fork2_LDADD = $(top_builddir)/libust/libust.la $(top_builddir)/libustfork/libustfork.la +fork2_LDADD = $(top_builddir)/liblttng-ust/liblttng-ust.la \ + $(top_builddir)/liblttng-ust-fork/liblttng-ust-fork.la noinst_SCRIPTS = run EXTRA_DIST = run diff --git a/tests/hello/Makefile.am b/tests/hello/Makefile.am index 8447e24a..9afe3874 100644 --- a/tests/hello/Makefile.am +++ b/tests/hello/Makefile.am @@ -1,8 +1,8 @@ -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libust +AM_CPPFLAGS = -I$(top_srcdir)/include noinst_PROGRAMS = hello hello_SOURCES = hello.c tp.c tp.h -hello_LDADD = $(top_builddir)/libust/libust.la +hello_LDADD = $(top_builddir)/liblttng-ust/liblttng-ust.la noinst_SCRIPTS = run EXTRA_DIST = run