X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust-ctl%2Fustctl.c;h=40b3667b2994c11c0dc97c1e124fcfc1b0251216;hb=8936b6c0add7eb6706e0a1ca50e03c446dda4006;hp=ff4a537b540b71e0b58a97fd24a029bfd8447af3;hpb=c9023c9304149ee1a4134571fdc41fd5e2e2a1a9;p=lttng-ust.git diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index ff4a537b..40b3667b 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -1,36 +1,40 @@ /* - * Copyright (C) 2011 - Julien Desfossez - * Copyright (C) 2011-2013 - Mathieu Desnoyers + * SPDX-License-Identifier: GPL-2.0-only * - * 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; version 2 of the License only. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (C) 2011 Julien Desfossez + * Copyright (C) 2011-2013 Mathieu Desnoyers */ -#define _GNU_SOURCE +#include #include +#include +#include +#include +#include + +#include #include #include -#include -#include -#include +#include #include #include -#include +#include +#include "ust-compat.h" #include "../libringbuffer/backend.h" #include "../libringbuffer/frontend.h" +#include "../liblttng-ust/ust-events-internal.h" #include "../liblttng-ust/wait.h" +#include "../liblttng-ust/lttng-rb-clients.h" +#include "../liblttng-ust/clock.h" +#include "../liblttng-ust/getenv.h" +#include "../liblttng-ust/lttng-tracer-core.h" +#include "../liblttng-ust/lttng-counter-client.h" + +#include "../libcounter/shm.h" +#include "../libcounter/smp.h" +#include "../libcounter/counter.h" /* * Number of milliseconds to retry before failing metadata writes on @@ -42,17 +46,18 @@ * Channel representation within consumer. */ struct ustctl_consumer_channel { - struct lttng_channel *chan; /* lttng channel buffers */ + struct lttng_ust_channel_buffer *chan; /* lttng channel buffers */ /* initial attributes */ struct ustctl_consumer_channel_attr attr; + int wait_fd; /* monitor close() */ + int wakeup_fd; /* monitor close() */ }; /* * Stream representation within consumer. */ struct ustctl_consumer_stream { - struct lttng_ust_shm_handle *handle; /* shared-memory handle */ struct lttng_ust_lib_ring_buffer *buf; struct ustctl_consumer_channel *chan; int shm_fd, wait_fd, wakeup_fd; @@ -60,15 +65,36 @@ struct ustctl_consumer_stream { uint64_t memory_map_size; }; +#define USTCTL_COUNTER_ATTR_DIMENSION_MAX 8 +struct ustctl_counter_attr { + enum ustctl_counter_arithmetic arithmetic; + enum ustctl_counter_bitness bitness; + uint32_t nr_dimensions; + int64_t global_sum_step; + struct ustctl_counter_dimension dimensions[USTCTL_COUNTER_ATTR_DIMENSION_MAX]; + bool coalesce_hits; +}; + +/* + * Counter representation within daemon. + */ +struct ustctl_daemon_counter { + struct lib_counter *counter; + const struct lttng_counter_ops *ops; + struct ustctl_counter_attr *attr; /* initial attributes */ +}; + extern void lttng_ring_buffer_client_overwrite_init(void); +extern void lttng_ring_buffer_client_overwrite_rt_init(void); extern void lttng_ring_buffer_client_discard_init(void); +extern void lttng_ring_buffer_client_discard_rt_init(void); extern void lttng_ring_buffer_metadata_client_init(void); extern void lttng_ring_buffer_client_overwrite_exit(void); +extern void lttng_ring_buffer_client_overwrite_rt_exit(void); extern void lttng_ring_buffer_client_discard_exit(void); +extern void lttng_ring_buffer_client_discard_rt_exit(void); extern void lttng_ring_buffer_metadata_client_exit(void); -volatile enum ust_loglevel ust_loglevel; - int ustctl_release_handle(int sock, int handle) { struct ustcomm_ust_msg lum; @@ -78,7 +104,7 @@ int ustctl_release_handle(int sock, int handle) return 0; memset(&lum, 0, sizeof(lum)); lum.handle = handle; - lum.cmd = LTTNG_UST_RELEASE; + lum.cmd = LTTNG_UST_ABI_RELEASE; return ustcomm_send_app_cmd(sock, &lum, &lur); } @@ -86,7 +112,7 @@ int ustctl_release_handle(int sock, int handle) * If sock is negative, it means we don't have to notify the other side * (e.g. application has already vanished). */ -int ustctl_release_object(int sock, struct lttng_ust_object_data *data) +int ustctl_release_object(int sock, struct lttng_ust_abi_object_data *data) { int ret; @@ -94,16 +120,26 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) return -EINVAL; switch (data->type) { - case LTTNG_UST_OBJECT_TYPE_CHANNEL: + case LTTNG_UST_ABI_OBJECT_TYPE_CHANNEL: + if (data->u.channel.wakeup_fd >= 0) { + ret = close(data->u.channel.wakeup_fd); + if (ret < 0) { + ret = -errno; + return ret; + } + data->u.channel.wakeup_fd = -1; + } free(data->u.channel.data); + data->u.channel.data = NULL; break; - case LTTNG_UST_OBJECT_TYPE_STREAM: + case LTTNG_UST_ABI_OBJECT_TYPE_STREAM: if (data->u.stream.shm_fd >= 0) { ret = close(data->u.stream.shm_fd); if (ret < 0) { ret = -errno; return ret; } + data->u.stream.shm_fd = -1; } if (data->u.stream.wakeup_fd >= 0) { ret = close(data->u.stream.wakeup_fd); @@ -111,10 +147,37 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) ret = -errno; return ret; } + data->u.stream.wakeup_fd = -1; + } + break; + case LTTNG_UST_ABI_OBJECT_TYPE_EVENT: + case LTTNG_UST_ABI_OBJECT_TYPE_CONTEXT: + case LTTNG_UST_ABI_OBJECT_TYPE_EVENT_NOTIFIER_GROUP: + case LTTNG_UST_ABI_OBJECT_TYPE_EVENT_NOTIFIER: + break; + case LTTNG_UST_ABI_OBJECT_TYPE_COUNTER: + free(data->u.counter.data); + data->u.counter.data = NULL; + break; + case LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_GLOBAL: + if (data->u.counter_global.shm_fd >= 0) { + ret = close(data->u.counter_global.shm_fd); + if (ret < 0) { + ret = -errno; + return ret; + } + data->u.counter_global.shm_fd = -1; } break; - case LTTNG_UST_OBJECT_TYPE_EVENT: - case LTTNG_UST_OBJECT_TYPE_CONTEXT: + case LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_CPU: + if (data->u.counter_cpu.shm_fd >= 0) { + ret = close(data->u.counter_cpu.shm_fd); + if (ret < 0) { + ret = -errno; + return ret; + } + data->u.counter_cpu.shm_fd = -1; + } break; default: assert(0); @@ -133,8 +196,8 @@ int ustctl_register_done(int sock) 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; + lum.handle = LTTNG_UST_ABI_ROOT_HANDLE; + lum.cmd = LTTNG_UST_ABI_REGISTER_DONE; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -152,8 +215,8 @@ int ustctl_create_session(int sock) /* Create session */ memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_SESSION; + lum.handle = LTTNG_UST_ABI_ROOT_HANDLE; + lum.cmd = LTTNG_UST_ABI_SESSION; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -162,13 +225,13 @@ int ustctl_create_session(int sock) return session_handle; } -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) +int ustctl_create_event(int sock, struct lttng_ust_abi_event *ev, + struct lttng_ust_abi_object_data *channel_data, + struct lttng_ust_abi_object_data **_event_data) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *event_data; + struct lttng_ust_abi_object_data *event_data; int ret; if (!channel_data || !_event_data) @@ -177,12 +240,12 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev, event_data = zmalloc(sizeof(*event_data)); if (!event_data) return -ENOMEM; - event_data->type = LTTNG_UST_OBJECT_TYPE_EVENT; + event_data->type = LTTNG_UST_ABI_OBJECT_TYPE_EVENT; memset(&lum, 0, sizeof(lum)); lum.handle = channel_data->handle; - lum.cmd = LTTNG_UST_EVENT; + lum.cmd = LTTNG_UST_ABI_EVENT; strncpy(lum.u.event.name, ev->name, - LTTNG_UST_SYM_NAME_LEN); + LTTNG_UST_ABI_SYM_NAME_LEN); lum.u.event.instrumentation = ev->instrumentation; lum.u.event.loglevel_type = ev->loglevel_type; lum.u.event.loglevel = ev->loglevel; @@ -197,39 +260,91 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev, 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) +int ustctl_add_context(int sock, struct lttng_ust_context_attr *ctx, + struct lttng_ust_abi_object_data *obj_data, + struct lttng_ust_abi_object_data **_context_data) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *context_data; + struct lttng_ust_abi_object_data *context_data = NULL; + char *buf = NULL; + size_t len; int ret; - if (!obj_data || !_context_data) - return -EINVAL; + if (!obj_data || !_context_data) { + ret = -EINVAL; + goto end; + } context_data = zmalloc(sizeof(*context_data)); - if (!context_data) - return -ENOMEM; - context_data->type = LTTNG_UST_OBJECT_TYPE_CONTEXT; + if (!context_data) { + ret = -ENOMEM; + goto end; + } + context_data->type = LTTNG_UST_ABI_OBJECT_TYPE_CONTEXT; memset(&lum, 0, sizeof(lum)); lum.handle = obj_data->handle; - lum.cmd = LTTNG_UST_CONTEXT; + lum.cmd = LTTNG_UST_ABI_CONTEXT; + lum.u.context.ctx = ctx->ctx; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(context_data); - return ret; + switch (ctx->ctx) { + case LTTNG_UST_ABI_CONTEXT_PERF_THREAD_COUNTER: + lum.u.context.u.perf_counter = ctx->u.perf_counter; + break; + case LTTNG_UST_ABI_CONTEXT_APP_CONTEXT: + { + size_t provider_name_len = strlen( + ctx->u.app_ctx.provider_name) + 1; + size_t ctx_name_len = strlen(ctx->u.app_ctx.ctx_name) + 1; + + lum.u.context.u.app_ctx.provider_name_len = provider_name_len; + lum.u.context.u.app_ctx.ctx_name_len = ctx_name_len; + + len = provider_name_len + ctx_name_len; + buf = zmalloc(len); + if (!buf) { + ret = -ENOMEM; + goto end; + } + memcpy(buf, ctx->u.app_ctx.provider_name, + provider_name_len); + memcpy(buf + provider_name_len, ctx->u.app_ctx.ctx_name, + ctx_name_len); + break; + } + default: + break; + } + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + goto end; + if (buf) { + /* send var len ctx_name */ + ret = ustcomm_send_unix_sock(sock, buf, len); + if (ret < 0) { + goto end; + } + if (ret != len) { + ret = -EINVAL; + goto end; + } + } + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (ret < 0) { + goto end; } context_data->handle = -1; DBG("Context created successfully"); *_context_data = context_data; + context_data = NULL; +end: + free(context_data); + free(buf); return ret; } -int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode, - struct lttng_ust_object_data *obj_data) +int ustctl_set_filter(int sock, struct lttng_ust_abi_filter_bytecode *bytecode, + struct lttng_ust_abi_object_data *obj_data) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -240,7 +355,7 @@ int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode, memset(&lum, 0, sizeof(lum)); lum.handle = obj_data->handle; - lum.cmd = LTTNG_UST_FILTER; + lum.cmd = LTTNG_UST_ABI_FILTER; lum.u.filter.data_size = bytecode->len; lum.u.filter.reloc_offset = bytecode->reloc_offset; lum.u.filter.seqnum = bytecode->seqnum; @@ -252,8 +367,6 @@ int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode, ret = ustcomm_send_unix_sock(sock, bytecode->data, bytecode->len); if (ret < 0) { - if (ret == -ECONNRESET) - fprintf(stderr, "remote end closed connection\n"); return ret; } if (ret != bytecode->len) @@ -261,8 +374,73 @@ int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode, return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); } +int ustctl_set_capture(int sock, struct lttng_ust_abi_capture_bytecode *bytecode, + struct lttng_ust_abi_object_data *obj_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + if (!obj_data) + return -EINVAL; + + memset(&lum, 0, sizeof(lum)); + lum.handle = obj_data->handle; + lum.cmd = LTTNG_UST_ABI_CAPTURE; + lum.u.capture.data_size = bytecode->len; + lum.u.capture.reloc_offset = bytecode->reloc_offset; + lum.u.capture.seqnum = bytecode->seqnum; + + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + return ret; + /* send var len bytecode */ + ret = ustcomm_send_unix_sock(sock, bytecode->data, + bytecode->len); + if (ret < 0) { + return ret; + } + if (ret != bytecode->len) + return -EINVAL; + return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); +} + +int ustctl_set_exclusion(int sock, struct lttng_ust_abi_event_exclusion *exclusion, + struct lttng_ust_abi_object_data *obj_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + if (!obj_data) { + return -EINVAL; + } + + memset(&lum, 0, sizeof(lum)); + lum.handle = obj_data->handle; + lum.cmd = LTTNG_UST_ABI_EXCLUSION; + lum.u.exclusion.count = exclusion->count; + + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) { + return ret; + } + + /* send var len exclusion names */ + ret = ustcomm_send_unix_sock(sock, + exclusion->names, + exclusion->count * LTTNG_UST_ABI_SYM_NAME_LEN); + if (ret < 0) { + return ret; + } + if (ret != exclusion->count * LTTNG_UST_ABI_SYM_NAME_LEN) { + return -EINVAL; + } + return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); +} + /* Enable event, channel and session ioctl */ -int ustctl_enable(int sock, struct lttng_ust_object_data *object) +int ustctl_enable(int sock, struct lttng_ust_abi_object_data *object) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -273,7 +451,7 @@ int ustctl_enable(int sock, struct lttng_ust_object_data *object) memset(&lum, 0, sizeof(lum)); lum.handle = object->handle; - lum.cmd = LTTNG_UST_ENABLE; + lum.cmd = LTTNG_UST_ABI_ENABLE; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -282,7 +460,7 @@ int ustctl_enable(int sock, struct lttng_ust_object_data *object) } /* Disable event, channel and session ioctl */ -int ustctl_disable(int sock, struct lttng_ust_object_data *object) +int ustctl_disable(int sock, struct lttng_ust_abi_object_data *object) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -293,7 +471,7 @@ int ustctl_disable(int sock, struct lttng_ust_object_data *object) memset(&lum, 0, sizeof(lum)); lum.handle = object->handle; - lum.cmd = LTTNG_UST_DISABLE; + lum.cmd = LTTNG_UST_ABI_DISABLE; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -303,7 +481,7 @@ int ustctl_disable(int sock, struct lttng_ust_object_data *object) int ustctl_start_session(int sock, int handle) { - struct lttng_ust_object_data obj; + struct lttng_ust_abi_object_data obj; obj.handle = handle; return ustctl_enable(sock, &obj); @@ -311,12 +489,113 @@ int ustctl_start_session(int sock, int handle) int ustctl_stop_session(int sock, int handle) { - struct lttng_ust_object_data obj; + struct lttng_ust_abi_object_data obj; obj.handle = handle; return ustctl_disable(sock, &obj); } +int ustctl_create_event_notifier_group(int sock, int pipe_fd, + struct lttng_ust_abi_object_data **_event_notifier_group_data) +{ + struct lttng_ust_abi_object_data *event_notifier_group_data; + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + ssize_t len; + int ret; + + if (!_event_notifier_group_data) + return -EINVAL; + + event_notifier_group_data = zmalloc(sizeof(*event_notifier_group_data)); + if (!event_notifier_group_data) + return -ENOMEM; + + event_notifier_group_data->type = LTTNG_UST_ABI_OBJECT_TYPE_EVENT_NOTIFIER_GROUP; + + memset(&lum, 0, sizeof(lum)); + lum.handle = LTTNG_UST_ABI_ROOT_HANDLE; + lum.cmd = LTTNG_UST_ABI_EVENT_NOTIFIER_GROUP_CREATE; + + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + goto error; + + /* Send event_notifier notification pipe. */ + len = ustcomm_send_fds_unix_sock(sock, &pipe_fd, 1); + if (len <= 0) { + ret = len; + goto error; + } + + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (ret) + goto error; + + event_notifier_group_data->handle = lur.ret_val; + DBG("received event_notifier group handle %d", event_notifier_group_data->handle); + + *_event_notifier_group_data = event_notifier_group_data; + + ret = 0; + goto end; +error: + free(event_notifier_group_data); + +end: + return ret; +} + +int ustctl_create_event_notifier(int sock, struct lttng_ust_abi_event_notifier *event_notifier, + struct lttng_ust_abi_object_data *event_notifier_group, + struct lttng_ust_abi_object_data **_event_notifier_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + struct lttng_ust_abi_object_data *event_notifier_data; + ssize_t len; + int ret; + + if (!event_notifier_group || !_event_notifier_data) + return -EINVAL; + + event_notifier_data = zmalloc(sizeof(*event_notifier_data)); + if (!event_notifier_data) + return -ENOMEM; + + event_notifier_data->type = LTTNG_UST_ABI_OBJECT_TYPE_EVENT_NOTIFIER; + + memset(&lum, 0, sizeof(lum)); + lum.handle = event_notifier_group->handle; + lum.cmd = LTTNG_UST_ABI_EVENT_NOTIFIER_CREATE; + lum.u.event_notifier.len = sizeof(*event_notifier); + + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) { + free(event_notifier_data); + return ret; + } + /* Send struct lttng_ust_abi_event_notifier */ + len = ustcomm_send_unix_sock(sock, event_notifier, sizeof(*event_notifier)); + if (len != sizeof(*event_notifier)) { + free(event_notifier_data); + if (len < 0) + return len; + else + return -EIO; + } + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (ret) { + free(event_notifier_data); + return ret; + } + event_notifier_data->handle = lur.ret_val; + DBG("received event_notifier handle %u", event_notifier_data->handle); + *_event_notifier_data = event_notifier_data; + + return ret; +} + int ustctl_tracepoint_list(int sock) { struct ustcomm_ust_msg lum; @@ -324,8 +603,8 @@ int ustctl_tracepoint_list(int sock) int ret, tp_list_handle; memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_TRACEPOINT_LIST; + lum.handle = LTTNG_UST_ABI_ROOT_HANDLE; + lum.cmd = LTTNG_UST_ABI_TRACEPOINT_LIST; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -335,7 +614,7 @@ int ustctl_tracepoint_list(int sock) } int ustctl_tracepoint_list_get(int sock, int tp_list_handle, - struct lttng_ust_tracepoint_iter *iter) + struct lttng_ust_abi_tracepoint_iter *iter) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -346,7 +625,7 @@ int ustctl_tracepoint_list_get(int sock, int tp_list_handle, memset(&lum, 0, sizeof(lum)); lum.handle = tp_list_handle; - lum.cmd = LTTNG_UST_TRACEPOINT_LIST_GET; + lum.cmd = LTTNG_UST_ABI_TRACEPOINT_LIST_GET; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -364,8 +643,8 @@ int ustctl_tracepoint_field_list(int sock) int ret, tp_field_list_handle; memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_TRACEPOINT_FIELD_LIST; + lum.handle = LTTNG_UST_ABI_ROOT_HANDLE; + lum.cmd = LTTNG_UST_ABI_TRACEPOINT_FIELD_LIST; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -375,7 +654,7 @@ int ustctl_tracepoint_field_list(int sock) } int ustctl_tracepoint_field_list_get(int sock, int tp_field_list_handle, - struct lttng_ust_field_iter *iter) + struct lttng_ust_abi_field_iter *iter) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -387,7 +666,7 @@ int ustctl_tracepoint_field_list_get(int sock, int tp_field_list_handle, memset(&lum, 0, sizeof(lum)); lum.handle = tp_field_list_handle; - lum.cmd = LTTNG_UST_TRACEPOINT_FIELD_LIST_GET; + lum.cmd = LTTNG_UST_ABI_TRACEPOINT_FIELD_LIST_GET; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -403,7 +682,7 @@ int ustctl_tracepoint_field_list_get(int sock, int tp_field_list_handle, return 0; } -int ustctl_tracer_version(int sock, struct lttng_ust_tracer_version *v) +int ustctl_tracer_version(int sock, struct lttng_ust_abi_tracer_version *v) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -413,8 +692,8 @@ int ustctl_tracer_version(int sock, struct lttng_ust_tracer_version *v) return -EINVAL; memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_TRACER_VERSION; + lum.handle = LTTNG_UST_ABI_ROOT_HANDLE; + lum.cmd = LTTNG_UST_ABI_TRACER_VERSION; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -430,8 +709,8 @@ int ustctl_wait_quiescent(int sock) int ret; memset(&lum, 0, sizeof(lum)); - lum.handle = LTTNG_UST_ROOT_HANDLE; - lum.cmd = LTTNG_UST_WAIT_QUIESCENT; + lum.handle = LTTNG_UST_ABI_ROOT_HANDLE; + lum.cmd = LTTNG_UST_ABI_WAIT_QUIESCENT; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -439,7 +718,7 @@ int ustctl_wait_quiescent(int sock) return 0; } -int ustctl_calibrate(int sock, struct lttng_ust_calibrate *calibrate) +int ustctl_calibrate(int sock, struct lttng_ust_abi_calibrate *calibrate) { if (!calibrate) return -EINVAL; @@ -447,7 +726,7 @@ int ustctl_calibrate(int sock, struct lttng_ust_calibrate *calibrate) return -ENOSYS; } -int ustctl_sock_flush_buffer(int sock, struct lttng_ust_object_data *object) +int ustctl_sock_flush_buffer(int sock, struct lttng_ust_abi_object_data *object) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -458,7 +737,7 @@ int ustctl_sock_flush_buffer(int sock, struct lttng_ust_object_data *object) memset(&lum, 0, sizeof(lum)); lum.handle = object->handle; - lum.cmd = LTTNG_UST_FLUSH_BUFFER; + lum.cmd = LTTNG_UST_ABI_FLUSH_BUFFER; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; @@ -468,9 +747,10 @@ int ustctl_sock_flush_buffer(int sock, struct lttng_ust_object_data *object) static int ustctl_send_channel(int sock, - enum lttng_ust_chan_type type, + enum lttng_ust_abi_chan_type type, void *data, uint64_t size, + int wakeup_fd, int send_fd_only) { ssize_t len; @@ -504,6 +784,14 @@ int ustctl_send_channel(int sock, return -EIO; } + /* Send wakeup fd */ + len = ustcomm_send_fds_unix_sock(sock, &wakeup_fd, 1); + if (len <= 0) { + if (len < 0) + return len; + else + return -EIO; + } return 0; } @@ -567,10 +855,11 @@ int ustctl_send_stream(int sock, } int ustctl_recv_channel_from_consumer(int sock, - struct lttng_ust_object_data **_channel_data) + struct lttng_ust_abi_object_data **_channel_data) { - struct lttng_ust_object_data *channel_data; + struct lttng_ust_abi_object_data *channel_data; ssize_t len; + int wakeup_fd; int ret; channel_data = zmalloc(sizeof(*channel_data)); @@ -578,7 +867,8 @@ int ustctl_recv_channel_from_consumer(int sock, ret = -ENOMEM; goto error_alloc; } - channel_data->type = LTTNG_UST_OBJECT_TYPE_CHANNEL; + channel_data->type = LTTNG_UST_ABI_OBJECT_TYPE_CHANNEL; + channel_data->handle = -1; /* recv mmap size */ len = ustcomm_recv_unix_sock(sock, &channel_data->size, @@ -617,7 +907,18 @@ int ustctl_recv_channel_from_consumer(int sock, ret = -EINVAL; goto error_recv_data; } - + /* recv wakeup fd */ + len = ustcomm_recv_fds_unix_sock(sock, &wakeup_fd, 1); + if (len <= 0) { + if (len < 0) { + ret = len; + goto error_recv_data; + } else { + ret = -EIO; + goto error_recv_data; + } + } + channel_data->u.channel.wakeup_fd = wakeup_fd; *_channel_data = channel_data; return 0; @@ -630,9 +931,9 @@ error_alloc: } int ustctl_recv_stream_from_consumer(int sock, - struct lttng_ust_object_data **_stream_data) + struct lttng_ust_abi_object_data **_stream_data) { - struct lttng_ust_object_data *stream_data; + struct lttng_ust_abi_object_data *stream_data; ssize_t len; int ret; int fds[2]; @@ -643,7 +944,7 @@ int ustctl_recv_stream_from_consumer(int sock, goto error_alloc; } - stream_data->type = LTTNG_UST_OBJECT_TYPE_STREAM; + stream_data->type = LTTNG_UST_ABI_OBJECT_TYPE_STREAM; stream_data->handle = -1; /* recv mmap size */ @@ -695,7 +996,7 @@ error_alloc: } int ustctl_send_channel_to_ust(int sock, int session_handle, - struct lttng_ust_object_data *channel_data) + struct lttng_ust_abi_object_data *channel_data) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -706,7 +1007,7 @@ int ustctl_send_channel_to_ust(int sock, int session_handle, memset(&lum, 0, sizeof(lum)); lum.handle = session_handle; - lum.cmd = LTTNG_UST_CHANNEL; + lum.cmd = LTTNG_UST_ABI_CHANNEL; lum.u.channel.len = channel_data->size; lum.u.channel.type = channel_data->u.channel.type; ret = ustcomm_send_app_msg(sock, &lum); @@ -717,21 +1018,20 @@ int ustctl_send_channel_to_ust(int sock, int session_handle, channel_data->u.channel.type, channel_data->u.channel.data, channel_data->size, + channel_data->u.channel.wakeup_fd, 1); if (ret) return ret; ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); if (!ret) { - if (lur.ret_val >= 0) { - channel_data->handle = lur.ret_val; - } + channel_data->handle = lur.ret_val; } return ret; } int ustctl_send_stream_to_ust(int sock, - struct lttng_ust_object_data *channel_data, - struct lttng_ust_object_data *stream_data) + struct lttng_ust_abi_object_data *channel_data, + struct lttng_ust_abi_object_data *stream_data) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; @@ -739,7 +1039,7 @@ int ustctl_send_stream_to_ust(int sock, memset(&lum, 0, sizeof(lum)); lum.handle = channel_data->handle; - lum.cmd = LTTNG_UST_STREAM; + lum.cmd = LTTNG_UST_ABI_STREAM; lum.u.stream.len = stream_data->size; lum.u.stream.stream_nr = stream_data->u.stream.stream_nr; ret = ustcomm_send_app_msg(sock, &lum); @@ -747,7 +1047,7 @@ int ustctl_send_stream_to_ust(int sock, return ret; assert(stream_data); - assert(stream_data->type == LTTNG_UST_OBJECT_TYPE_STREAM); + assert(stream_data->type == LTTNG_UST_ABI_OBJECT_TYPE_STREAM); ret = ustctl_send_stream(sock, stream_data->u.stream.stream_nr, @@ -759,27 +1059,195 @@ int ustctl_send_stream_to_ust(int sock, return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); } +int ustctl_duplicate_ust_object_data(struct lttng_ust_abi_object_data **dest, + struct lttng_ust_abi_object_data *src) +{ + struct lttng_ust_abi_object_data *obj; + int ret; + + if (src->handle != -1) { + ret = -EINVAL; + goto error; + } + + obj = zmalloc(sizeof(*obj)); + if (!obj) { + ret = -ENOMEM; + goto error; + } + + obj->type = src->type; + obj->handle = src->handle; + obj->size = src->size; + + switch (obj->type) { + case LTTNG_UST_ABI_OBJECT_TYPE_CHANNEL: + { + obj->u.channel.type = src->u.channel.type; + if (src->u.channel.wakeup_fd >= 0) { + obj->u.channel.wakeup_fd = + dup(src->u.channel.wakeup_fd); + if (obj->u.channel.wakeup_fd < 0) { + ret = errno; + goto chan_error_wakeup_fd; + } + } else { + obj->u.channel.wakeup_fd = + src->u.channel.wakeup_fd; + } + obj->u.channel.data = zmalloc(obj->size); + if (!obj->u.channel.data) { + ret = -ENOMEM; + goto chan_error_alloc; + } + memcpy(obj->u.channel.data, src->u.channel.data, obj->size); + break; + + chan_error_alloc: + if (src->u.channel.wakeup_fd >= 0) { + int closeret; + + closeret = close(obj->u.channel.wakeup_fd); + if (closeret) { + PERROR("close"); + } + } + chan_error_wakeup_fd: + goto error_type; + + } + + case LTTNG_UST_ABI_OBJECT_TYPE_STREAM: + { + obj->u.stream.stream_nr = src->u.stream.stream_nr; + if (src->u.stream.wakeup_fd >= 0) { + obj->u.stream.wakeup_fd = + dup(src->u.stream.wakeup_fd); + if (obj->u.stream.wakeup_fd < 0) { + ret = errno; + goto stream_error_wakeup_fd; + } + } else { + obj->u.stream.wakeup_fd = + src->u.stream.wakeup_fd; + } + + if (src->u.stream.shm_fd >= 0) { + obj->u.stream.shm_fd = + dup(src->u.stream.shm_fd); + if (obj->u.stream.shm_fd < 0) { + ret = errno; + goto stream_error_shm_fd; + } + } else { + obj->u.stream.shm_fd = + src->u.stream.shm_fd; + } + break; + + stream_error_shm_fd: + if (src->u.stream.wakeup_fd >= 0) { + int closeret; + + closeret = close(obj->u.stream.wakeup_fd); + if (closeret) { + PERROR("close"); + } + } + stream_error_wakeup_fd: + goto error_type; + } + + case LTTNG_UST_ABI_OBJECT_TYPE_COUNTER: + { + obj->u.counter.data = zmalloc(obj->size); + if (!obj->u.counter.data) { + ret = -ENOMEM; + goto error_type; + } + memcpy(obj->u.counter.data, src->u.counter.data, obj->size); + break; + } + + case LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_GLOBAL: + { + if (src->u.counter_global.shm_fd >= 0) { + obj->u.counter_global.shm_fd = + dup(src->u.counter_global.shm_fd); + if (obj->u.counter_global.shm_fd < 0) { + ret = errno; + goto error_type; + } + } + break; + } + + case LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_CPU: + { + obj->u.counter_cpu.cpu_nr = src->u.counter_cpu.cpu_nr; + if (src->u.counter_cpu.shm_fd >= 0) { + obj->u.counter_cpu.shm_fd = + dup(src->u.counter_cpu.shm_fd); + if (obj->u.counter_cpu.shm_fd < 0) { + ret = errno; + goto error_type; + } + } + break; + } + + default: + ret = -EINVAL; + goto error_type; + } + + *dest = obj; + return 0; + +error_type: + free(obj); +error: + return ret; +} + /* Buffer operations */ +int ustctl_get_nr_stream_per_channel(void) +{ + return num_possible_cpus(); +} + struct ustctl_consumer_channel * - ustctl_create_channel(struct ustctl_consumer_channel_attr *attr) + ustctl_create_channel(struct ustctl_consumer_channel_attr *attr, + const int *stream_fds, int nr_stream_fds) { struct ustctl_consumer_channel *chan; const char *transport_name; struct lttng_transport *transport; switch (attr->type) { - case LTTNG_UST_CHAN_PER_CPU: - if (attr->output == LTTNG_UST_MMAP) { - transport_name = attr->overwrite ? - "relay-overwrite-mmap" : "relay-discard-mmap"; + case LTTNG_UST_ABI_CHAN_PER_CPU: + if (attr->output == LTTNG_UST_ABI_MMAP) { + if (attr->overwrite) { + if (attr->read_timer_interval == 0) { + transport_name = "relay-overwrite-mmap"; + } else { + transport_name = "relay-overwrite-rt-mmap"; + } + } else { + if (attr->read_timer_interval == 0) { + transport_name = "relay-discard-mmap"; + } else { + transport_name = "relay-discard-rt-mmap"; + } + } } else { return NULL; } break; - case LTTNG_UST_CHAN_METADATA: - if (attr->output == LTTNG_UST_MMAP) + case LTTNG_UST_ABI_CHAN_METADATA: + if (attr->output == LTTNG_UST_ABI_MMAP) transport_name = "relay-metadata-mmap"; else return NULL; @@ -789,7 +1257,7 @@ struct ustctl_consumer_channel * return NULL; } - transport = lttng_transport_find(transport_name); + transport = lttng_ust_transport_find(transport_name); if (!transport) { DBG("LTTng transport %s not found\n", transport_name); @@ -800,16 +1268,20 @@ struct ustctl_consumer_channel * if (!chan) return NULL; - chan->chan = transport->ops.channel_create(transport_name, NULL, + chan->chan = transport->ops.priv->channel_create(transport_name, NULL, attr->subbuf_size, attr->num_subbuf, attr->switch_timer_interval, attr->read_timer_interval, - attr->uuid); + attr->uuid, attr->chan_id, + stream_fds, nr_stream_fds, + attr->blocking_timeout); if (!chan->chan) { goto chan_error; } chan->chan->ops = &transport->ops; memcpy(&chan->attr, attr, sizeof(chan->attr)); + chan->wait_fd = ustctl_channel_get_wait_fd(chan); + chan->wakeup_fd = ustctl_channel_get_wakeup_fd(chan); return chan; chan_error: @@ -819,7 +1291,9 @@ chan_error: void ustctl_destroy_channel(struct ustctl_consumer_channel *chan) { - chan->chan->ops->channel_destroy(chan->chan); + (void) ustctl_channel_close_wait_fd(chan); + (void) ustctl_channel_close_wakeup_fd(chan); + chan->chan->ops->priv->channel_destroy(chan->chan); free(chan); } @@ -828,13 +1302,14 @@ int ustctl_send_channel_to_sessiond(int sock, { struct shm_object_table *table; - table = channel->chan->handle->table; + table = channel->chan->priv->rb_chan->handle->table; if (table->size <= 0) return -EINVAL; return ustctl_send_channel(sock, channel->attr.type, table->objects[0].memory_map, table->objects[0].memory_map_size, + channel->wakeup_fd, 0); } @@ -857,17 +1332,17 @@ int ustctl_write_metadata_to_channel( size_t len) /* metadata length */ { struct lttng_ust_lib_ring_buffer_ctx ctx; - struct lttng_channel *chan = channel->chan; + struct lttng_ust_channel_buffer *lttng_chan_buf = channel->chan; + struct lttng_ust_lib_ring_buffer_channel *rb_chan = lttng_chan_buf->priv->rb_chan; const char *str = metadata_str; int ret = 0, waitret; size_t reserve_len, pos; for (pos = 0; pos < len; pos += reserve_len) { reserve_len = min_t(size_t, - chan->ops->packet_avail_size(chan->chan, chan->handle), + lttng_chan_buf->ops->priv->packet_avail_size(lttng_chan_buf), len - pos); - lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len, - sizeof(char), -1, chan->handle); + lttng_ust_lib_ring_buffer_ctx_init(&ctx, rb_chan, reserve_len, sizeof(char), NULL); /* * We don't care about metadata buffer's records lost * count, because we always retry here. Report error if @@ -876,7 +1351,7 @@ int ustctl_write_metadata_to_channel( */ waitret = wait_cond_interruptible_timeout( ({ - ret = chan->ops->event_reserve(&ctx, 0); + ret = lttng_chan_buf->ops->event_reserve(&ctx); ret != -ENOBUFS || !ret; }), LTTNG_METADATA_TIMEOUT_MSEC); @@ -888,29 +1363,89 @@ int ustctl_write_metadata_to_channel( ret = waitret; goto end; } - chan->ops->event_write(&ctx, &str[pos], reserve_len); - chan->ops->event_commit(&ctx); + lttng_chan_buf->ops->event_write(&ctx, &str[pos], reserve_len, 1); + lttng_chan_buf->ops->event_commit(&ctx); } end: return ret; } -int ustctl_stream_close_wait_fd(struct ustctl_consumer_stream *stream) +/* + * Write at most one packet in the channel. + * Returns the number of bytes written on success, < 0 on error. + */ +ssize_t ustctl_write_one_packet_to_channel( + struct ustctl_consumer_channel *channel, + const char *metadata_str, /* NOT null-terminated */ + size_t len) /* metadata length */ { - struct channel *chan; - - chan = stream->chan->chan->chan; - return ring_buffer_close_wait_fd(&chan->backend.config, - chan, stream->handle, stream->cpu); + struct lttng_ust_lib_ring_buffer_ctx ctx; + struct lttng_ust_channel_buffer *lttng_chan_buf = channel->chan; + struct lttng_ust_lib_ring_buffer_channel *rb_chan = lttng_chan_buf->priv->rb_chan; + const char *str = metadata_str; + ssize_t reserve_len; + int ret; + + reserve_len = min_t(ssize_t, + lttng_chan_buf->ops->priv->packet_avail_size(lttng_chan_buf), + len); + lttng_ust_lib_ring_buffer_ctx_init(&ctx, rb_chan, reserve_len, sizeof(char), NULL); + ret = lttng_chan_buf->ops->event_reserve(&ctx); + if (ret != 0) { + DBG("LTTng: event reservation failed"); + assert(ret < 0); + reserve_len = ret; + goto end; + } + lttng_chan_buf->ops->event_write(&ctx, str, reserve_len, 1); + lttng_chan_buf->ops->event_commit(&ctx); + +end: + return reserve_len; +} + +int ustctl_channel_close_wait_fd(struct ustctl_consumer_channel *consumer_chan) +{ + struct lttng_ust_lib_ring_buffer_channel *chan; + int ret; + + chan = consumer_chan->chan->priv->rb_chan; + ret = ring_buffer_channel_close_wait_fd(&chan->backend.config, + chan, chan->handle); + if (!ret) + consumer_chan->wait_fd = -1; + return ret; +} + +int ustctl_channel_close_wakeup_fd(struct ustctl_consumer_channel *consumer_chan) +{ + struct lttng_ust_lib_ring_buffer_channel *chan; + int ret; + + chan = consumer_chan->chan->priv->rb_chan; + ret = ring_buffer_channel_close_wakeup_fd(&chan->backend.config, + chan, chan->handle); + if (!ret) + consumer_chan->wakeup_fd = -1; + return ret; +} + +int ustctl_stream_close_wait_fd(struct ustctl_consumer_stream *stream) +{ + struct lttng_ust_lib_ring_buffer_channel *chan; + + chan = stream->chan->chan->priv->rb_chan; + return ring_buffer_stream_close_wait_fd(&chan->backend.config, + chan, chan->handle, stream->cpu); } int ustctl_stream_close_wakeup_fd(struct ustctl_consumer_stream *stream) { - struct channel *chan; + struct lttng_ust_lib_ring_buffer_channel *chan; - chan = stream->chan->chan->chan; - return ring_buffer_close_wakeup_fd(&chan->backend.config, - chan, stream->handle, stream->cpu); + chan = stream->chan->chan->priv->rb_chan; + return ring_buffer_stream_close_wakeup_fd(&chan->backend.config, + chan, chan->handle, stream->cpu); } struct ustctl_consumer_stream * @@ -919,7 +1454,7 @@ struct ustctl_consumer_stream * { struct ustctl_consumer_stream *stream; struct lttng_ust_shm_handle *handle; - struct channel *chan; + struct lttng_ust_lib_ring_buffer_channel *rb_chan; int shm_fd, wait_fd, wakeup_fd; uint64_t memory_map_size; struct lttng_ust_lib_ring_buffer *buf; @@ -927,13 +1462,13 @@ struct ustctl_consumer_stream * if (!channel) return NULL; - handle = channel->chan->handle; + rb_chan = channel->chan->priv->rb_chan; + handle = rb_chan->handle; if (!handle) return NULL; - chan = channel->chan->chan; - buf = channel_get_ring_buffer(&chan->backend.config, - chan, cpu, handle, &shm_fd, &wait_fd, + buf = channel_get_ring_buffer(&rb_chan->backend.config, + rb_chan, cpu, handle, &shm_fd, &wait_fd, &wakeup_fd, &memory_map_size); if (!buf) return NULL; @@ -944,7 +1479,6 @@ struct ustctl_consumer_stream * stream = zmalloc(sizeof(*stream)); if (!stream) goto alloc_error; - stream->handle = handle; stream->buf = buf; stream->chan = channel; stream->shm_fd = shm_fd; @@ -966,11 +1500,29 @@ void ustctl_destroy_stream(struct ustctl_consumer_stream *stream) assert(stream); buf = stream->buf; consumer_chan = stream->chan; - lib_ring_buffer_release_read(buf, consumer_chan->chan->handle); + (void) ustctl_stream_close_wait_fd(stream); + (void) ustctl_stream_close_wakeup_fd(stream); + lib_ring_buffer_release_read(buf, consumer_chan->chan->priv->rb_chan->handle); free(stream); } -int ustctl_get_wait_fd(struct ustctl_consumer_stream *stream) +int ustctl_channel_get_wait_fd(struct ustctl_consumer_channel *chan) +{ + if (!chan) + return -EINVAL; + return shm_get_wait_fd(chan->chan->priv->rb_chan->handle, + &chan->chan->priv->rb_chan->handle->chan._ref); +} + +int ustctl_channel_get_wakeup_fd(struct ustctl_consumer_channel *chan) +{ + if (!chan) + return -EINVAL; + return shm_get_wakeup_fd(chan->chan->priv->rb_chan->handle, + &chan->chan->priv->rb_chan->handle->chan._ref); +} + +int ustctl_stream_get_wait_fd(struct ustctl_consumer_stream *stream) { struct lttng_ust_lib_ring_buffer *buf; struct ustctl_consumer_channel *consumer_chan; @@ -979,10 +1531,10 @@ int ustctl_get_wait_fd(struct ustctl_consumer_stream *stream) return -EINVAL; buf = stream->buf; consumer_chan = stream->chan; - return shm_get_wait_fd(consumer_chan->chan->handle, &buf->self._ref); + return shm_get_wait_fd(consumer_chan->chan->priv->rb_chan->handle, &buf->self._ref); } -int ustctl_get_wakeup_fd(struct ustctl_consumer_stream *stream) +int ustctl_stream_get_wakeup_fd(struct ustctl_consumer_stream *stream) { struct lttng_ust_lib_ring_buffer *buf; struct ustctl_consumer_channel *consumer_chan; @@ -991,7 +1543,7 @@ int ustctl_get_wakeup_fd(struct ustctl_consumer_stream *stream) return -EINVAL; buf = stream->buf; consumer_chan = stream->chan; - return shm_get_wakeup_fd(consumer_chan->chan->handle, &buf->self._ref); + return shm_get_wakeup_fd(consumer_chan->chan->priv->rb_chan->handle, &buf->self._ref); } /* For mmap mode, readable without "get" operation */ @@ -1005,7 +1557,7 @@ void *ustctl_get_mmap_base(struct ustctl_consumer_stream *stream) return NULL; buf = stream->buf; consumer_chan = stream->chan; - return shmp(consumer_chan->chan->handle, buf->backend.memory_map); + return shmp(consumer_chan->chan->priv->rb_chan->handle, buf->backend.memory_map); } /* returns the length to mmap. */ @@ -1014,17 +1566,17 @@ int ustctl_get_mmap_len(struct ustctl_consumer_stream *stream, { struct ustctl_consumer_channel *consumer_chan; unsigned long mmap_buf_len; - struct channel *chan; + struct lttng_ust_lib_ring_buffer_channel *rb_chan; if (!stream) return -EINVAL; consumer_chan = stream->chan; - chan = consumer_chan->chan->chan; - if (chan->backend.config.output != RING_BUFFER_MMAP) + rb_chan = consumer_chan->chan->priv->rb_chan; + if (rb_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; + mmap_buf_len = rb_chan->backend.buf_size; + if (rb_chan->backend.extra_reader_sb) + mmap_buf_len += rb_chan->backend.subbuf_size; if (mmap_buf_len > INT_MAX) return -EFBIG; *len = mmap_buf_len; @@ -1036,13 +1588,13 @@ int ustctl_get_max_subbuf_size(struct ustctl_consumer_stream *stream, unsigned long *len) { struct ustctl_consumer_channel *consumer_chan; - struct channel *chan; + struct lttng_ust_lib_ring_buffer_channel *rb_chan; if (!stream) return -EINVAL; consumer_chan = stream->chan; - chan = consumer_chan->chan->chan; - *len = chan->backend.subbuf_size; + rb_chan = consumer_chan->chan->priv->rb_chan; + *len = rb_chan->backend.subbuf_size; return 0; } @@ -1055,22 +1607,30 @@ int ustctl_get_max_subbuf_size(struct ustctl_consumer_stream *stream, int ustctl_get_mmap_read_offset(struct ustctl_consumer_stream *stream, unsigned long *off) { - struct channel *chan; + struct lttng_ust_lib_ring_buffer_channel *rb_chan; unsigned long sb_bindex; struct lttng_ust_lib_ring_buffer *buf; struct ustctl_consumer_channel *consumer_chan; + struct lttng_ust_lib_ring_buffer_backend_pages_shmp *barray_idx; + struct lttng_ust_lib_ring_buffer_backend_pages *pages; if (!stream) return -EINVAL; buf = stream->buf; consumer_chan = stream->chan; - chan = consumer_chan->chan->chan; - if (chan->backend.config.output != RING_BUFFER_MMAP) + rb_chan = consumer_chan->chan->priv->rb_chan; + if (rb_chan->backend.config.output != RING_BUFFER_MMAP) return -EINVAL; - sb_bindex = subbuffer_id_get_index(&chan->backend.config, + sb_bindex = subbuffer_id_get_index(&rb_chan->backend.config, buf->backend.buf_rsb.id); - *off = shmp(consumer_chan->chan->handle, - shmp_index(consumer_chan->chan->handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; + barray_idx = shmp_index(rb_chan->handle, buf->backend.array, + sb_bindex); + if (!barray_idx) + return -EINVAL; + pages = shmp(rb_chan->handle, barray_idx->shmp); + if (!pages) + return -EINVAL; + *off = pages->mmap_offset; return 0; } @@ -1079,7 +1639,7 @@ int ustctl_get_subbuf_size(struct ustctl_consumer_stream *stream, unsigned long *len) { struct ustctl_consumer_channel *consumer_chan; - struct channel *chan; + struct lttng_ust_lib_ring_buffer_channel *rb_chan; struct lttng_ust_lib_ring_buffer *buf; if (!stream) @@ -1087,9 +1647,9 @@ int ustctl_get_subbuf_size(struct ustctl_consumer_stream *stream, buf = stream->buf; consumer_chan = stream->chan; - chan = consumer_chan->chan->chan; - *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, - consumer_chan->chan->handle); + rb_chan = consumer_chan->chan->priv->rb_chan; + *len = lib_ring_buffer_get_read_data_size(&rb_chan->backend.config, buf, + rb_chan->handle); return 0; } @@ -1098,17 +1658,17 @@ int ustctl_get_padded_subbuf_size(struct ustctl_consumer_stream *stream, unsigned long *len) { struct ustctl_consumer_channel *consumer_chan; - struct channel *chan; + struct lttng_ust_lib_ring_buffer_channel *rb_chan; struct lttng_ust_lib_ring_buffer *buf; if (!stream) return -EINVAL; buf = stream->buf; consumer_chan = stream->chan; - chan = consumer_chan->chan->chan; - *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, - consumer_chan->chan->handle); - *len = PAGE_ALIGN(*len); + rb_chan = consumer_chan->chan->priv->rb_chan; + *len = lib_ring_buffer_get_read_data_size(&rb_chan->backend.config, buf, + rb_chan->handle); + *len = LTTNG_UST_PAGE_ALIGN(*len); return 0; } @@ -1123,7 +1683,7 @@ int ustctl_get_next_subbuf(struct ustctl_consumer_stream *stream) buf = stream->buf; consumer_chan = stream->chan; return lib_ring_buffer_get_next_subbuf(buf, - consumer_chan->chan->handle); + consumer_chan->chan->priv->rb_chan->handle); } @@ -1137,7 +1697,7 @@ int ustctl_put_next_subbuf(struct ustctl_consumer_stream *stream) return -EINVAL; buf = stream->buf; consumer_chan = stream->chan; - lib_ring_buffer_put_next_subbuf(buf, consumer_chan->chan->handle); + lib_ring_buffer_put_next_subbuf(buf, consumer_chan->chan->priv->rb_chan->handle); return 0; } @@ -1154,7 +1714,26 @@ int ustctl_snapshot(struct ustctl_consumer_stream *stream) buf = stream->buf; consumer_chan = stream->chan; return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot, - &buf->prod_snapshot, consumer_chan->chan->handle); + &buf->prod_snapshot, consumer_chan->chan->priv->rb_chan->handle); +} + +/* + * Get a snapshot of the current ring buffer producer and consumer positions + * even if the consumed and produced positions are contained within the same + * subbuffer. + */ +int ustctl_snapshot_sample_positions(struct ustctl_consumer_stream *stream) +{ + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; + return lib_ring_buffer_snapshot_sample_positions(buf, + &buf->cons_snapshot, &buf->prod_snapshot, + consumer_chan->chan->priv->rb_chan->handle); } /* Get the consumer position (iteration start) */ @@ -1195,7 +1774,7 @@ int ustctl_get_subbuf(struct ustctl_consumer_stream *stream, buf = stream->buf; consumer_chan = stream->chan; return lib_ring_buffer_get_subbuf(buf, *pos, - consumer_chan->chan->handle); + consumer_chan->chan->priv->rb_chan->handle); } /* Release exclusive sub-buffer access */ @@ -1208,7 +1787,7 @@ int ustctl_put_subbuf(struct ustctl_consumer_stream *stream) return -EINVAL; buf = stream->buf; consumer_chan = stream->chan; - lib_ring_buffer_put_subbuf(buf, consumer_chan->chan->handle); + lib_ring_buffer_put_subbuf(buf, consumer_chan->chan->priv->rb_chan->handle); return 0; } @@ -1223,9 +1802,307 @@ void ustctl_flush_buffer(struct ustctl_consumer_stream *stream, consumer_chan = stream->chan; lib_ring_buffer_switch_slow(buf, producer_active ? SWITCH_ACTIVE : SWITCH_FLUSH, - consumer_chan->chan->handle); + consumer_chan->chan->priv->rb_chan->handle); +} + +void ustctl_clear_buffer(struct ustctl_consumer_stream *stream) +{ + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + assert(stream); + buf = stream->buf; + consumer_chan = stream->chan; + lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE, + consumer_chan->chan->priv->rb_chan->handle); + lib_ring_buffer_clear_reader(buf, consumer_chan->chan->priv->rb_chan->handle); +} + +static +struct lttng_ust_client_lib_ring_buffer_client_cb *get_client_cb( + struct lttng_ust_lib_ring_buffer *buf, + struct lttng_ust_lib_ring_buffer_channel *chan) +{ + const struct lttng_ust_lib_ring_buffer_config *config; + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + + config = &chan->backend.config; + if (!config->cb_ptr) + return NULL; + client_cb = caa_container_of(config->cb_ptr, + struct lttng_ust_client_lib_ring_buffer_client_cb, + parent); + return client_cb; +} + +int ustctl_get_timestamp_begin(struct ustctl_consumer_stream *stream, + uint64_t *timestamp_begin) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !timestamp_begin) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb) + return -ENOSYS; + return client_cb->timestamp_begin(buf, chan, timestamp_begin); +} + +int ustctl_get_timestamp_end(struct ustctl_consumer_stream *stream, + uint64_t *timestamp_end) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !timestamp_end) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb) + return -ENOSYS; + return client_cb->timestamp_end(buf, chan, timestamp_end); +} + +int ustctl_get_events_discarded(struct ustctl_consumer_stream *stream, + uint64_t *events_discarded) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !events_discarded) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb) + return -ENOSYS; + return client_cb->events_discarded(buf, chan, events_discarded); +} + +int ustctl_get_content_size(struct ustctl_consumer_stream *stream, + uint64_t *content_size) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !content_size) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb) + return -ENOSYS; + return client_cb->content_size(buf, chan, content_size); +} + +int ustctl_get_packet_size(struct ustctl_consumer_stream *stream, + uint64_t *packet_size) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !packet_size) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb) + return -ENOSYS; + return client_cb->packet_size(buf, chan, packet_size); +} + +int ustctl_get_stream_id(struct ustctl_consumer_stream *stream, + uint64_t *stream_id) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !stream_id) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb) + return -ENOSYS; + return client_cb->stream_id(buf, chan, stream_id); } +int ustctl_get_current_timestamp(struct ustctl_consumer_stream *stream, + uint64_t *ts) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !ts) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb || !client_cb->current_timestamp) + return -ENOSYS; + return client_cb->current_timestamp(buf, chan, ts); +} + +int ustctl_get_sequence_number(struct ustctl_consumer_stream *stream, + uint64_t *seq) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !seq) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb || !client_cb->sequence_number) + return -ENOSYS; + return client_cb->sequence_number(buf, chan, seq); +} + +int ustctl_get_instance_id(struct ustctl_consumer_stream *stream, + uint64_t *id) +{ + struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb; + struct lttng_ust_lib_ring_buffer_channel *chan; + struct lttng_ust_lib_ring_buffer *buf; + + if (!stream || !id) + return -EINVAL; + buf = stream->buf; + chan = stream->chan->chan->priv->rb_chan; + client_cb = get_client_cb(buf, chan); + if (!client_cb) + return -ENOSYS; + return client_cb->instance_id(buf, chan, id); +} + +#ifdef HAVE_LINUX_PERF_EVENT_H + +int ustctl_has_perf_counters(void) +{ + return 1; +} + +#else + +int ustctl_has_perf_counters(void) +{ + return 0; +} + +#endif + +#ifdef __linux__ +/* + * Override application pid/uid/gid with unix socket credentials. If + * the application announced a pid matching our view, it means it is + * within the same pid namespace, so expose the ppid provided by the + * application. + */ +static +int get_cred(int sock, + const struct ustctl_reg_msg *reg_msg, + uint32_t *pid, + uint32_t *ppid, + uint32_t *uid, + uint32_t *gid) +{ + struct ucred ucred; + socklen_t ucred_len = sizeof(struct ucred); + int ret; + + ret = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len); + if (ret) { + return -LTTNG_UST_ERR_PEERCRED; + } + DBG("Unix socket peercred [ pid: %u, uid: %u, gid: %u ], " + "application registered claiming [ pid: %u, ppid: %u, uid: %u, gid: %u ]", + ucred.pid, ucred.uid, ucred.gid, + reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid); + if (!ucred.pid) { + ERR("Unix socket credential pid=0. Refusing application in distinct, non-nested pid namespace."); + return -LTTNG_UST_ERR_PEERCRED_PID; + } + *pid = ucred.pid; + *uid = ucred.uid; + *gid = ucred.gid; + if (ucred.pid == reg_msg->pid) { + *ppid = reg_msg->ppid; + } else { + *ppid = 0; + } + return 0; +} +#elif defined(__FreeBSD__) +#include +#include + +/* + * Override application uid/gid with unix socket credentials. Use the + * first group of the cr_groups. + * Use the pid and ppid provided by the application on registration. + */ +static +int get_cred(int sock, + const struct ustctl_reg_msg *reg_msg, + uint32_t *pid, + uint32_t *ppid, + uint32_t *uid, + uint32_t *gid) +{ + struct xucred xucred; + socklen_t xucred_len = sizeof(struct xucred); + int ret; + + ret = getsockopt(sock, SOL_SOCKET, LOCAL_PEERCRED, &xucred, &xucred_len); + if (ret) { + return -LTTNG_UST_ERR_PEERCRED; + } + if (xucred.cr_version != XUCRED_VERSION || xucred.cr_ngroups < 1) { + return -LTTNG_UST_ERR_PEERCRED; + } + DBG("Unix socket peercred [ uid: %u, gid: %u ], " + "application registered claiming [ pid: %d, ppid: %d, uid: %u, gid: %u ]", + xucred.cr_uid, xucred.cr_groups[0], + reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid); + *pid = reg_msg->pid; + *ppid = reg_msg->ppid; + *uid = xucred.cr_uid; + *gid = xucred.cr_groups[0]; + return 0; +} +#else +#warning "Using insecure fallback: trusting user id provided by registered applications. Please consider implementing use of unix socket credentials on your platform." +static +int get_cred(int sock, + const struct ustctl_reg_msg *reg_msg, + uint32_t *pid, + uint32_t *ppid, + uint32_t *uid, + uint32_t *gid) +{ + DBG("Application registered claiming [ pid: %u, ppid: %d, uid: %u, gid: %u ]", + reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid); + *pid = reg_msg->pid; + *ppid = reg_msg->ppid; + *uid = reg_msg->uid; + *gid = reg_msg->gid; + return 0; +} +#endif + /* * Returns 0 on success, negative error value on error. */ @@ -1257,10 +2134,10 @@ int ustctl_recv_reg_msg(int sock, if (len < 0) return len; - if (reg_msg.magic == LTTNG_UST_COMM_MAGIC) { + if (reg_msg.magic == LTTNG_UST_ABI_COMM_MAGIC) { *byte_order = BYTE_ORDER == BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN; - } else if (reg_msg.magic == bswap_32(LTTNG_UST_COMM_MAGIC)) { + } else if (reg_msg.magic == bswap_32(LTTNG_UST_ABI_COMM_MAGIC)) { *byte_order = BYTE_ORDER == BIG_ENDIAN ? LITTLE_ENDIAN : BIG_ENDIAN; } else { @@ -1276,10 +2153,6 @@ int ustctl_recv_reg_msg(int sock, } *major = reg_msg.major; *minor = reg_msg.minor; - *pid = reg_msg.pid; - *ppid = reg_msg.ppid; - *uid = reg_msg.uid; - *gid = reg_msg.gid; *bits_per_long = reg_msg.bits_per_long; *uint8_t_alignment = reg_msg.uint8_t_alignment; *uint16_t_alignment = reg_msg.uint16_t_alignment; @@ -1287,11 +2160,11 @@ int ustctl_recv_reg_msg(int sock, *uint64_t_alignment = reg_msg.uint64_t_alignment; *long_alignment = reg_msg.long_alignment; memcpy(name, reg_msg.name, LTTNG_UST_ABI_PROCNAME_LEN); - if (reg_msg.major != LTTNG_UST_ABI_MAJOR_VERSION) { + if (reg_msg.major < LTTNG_UST_ABI_MAJOR_VERSION_OLDEST_COMPATIBLE || + reg_msg.major > LTTNG_UST_ABI_MAJOR_VERSION) { return -LTTNG_UST_ERR_UNSUP_MAJOR; } - - return 0; + return get_cred(sock, ®_msg, pid, ppid, uid, gid); } int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd) @@ -1313,6 +2186,9 @@ int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd) case 1: *notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL; break; + case 2: + *notify_cmd = USTCTL_NOTIFY_CMD_ENUM; + break; default: return -EINVAL; } @@ -1348,8 +2224,8 @@ int ustctl_recv_register_event(int sock, *session_objd = msg.session_objd; *channel_objd = msg.channel_objd; - strncpy(event_name, msg.event_name, LTTNG_UST_SYM_NAME_LEN); - event_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + strncpy(event_name, msg.event_name, LTTNG_UST_ABI_SYM_NAME_LEN); + event_name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0'; *loglevel = msg.loglevel; signature_len = msg.signature_len; fields_len = msg.fields_len; @@ -1377,7 +2253,7 @@ int ustctl_recv_register_event(int sock, goto signature_error; } /* Enforce end of string */ - signature[signature_len - 1] = '\0'; + a_sign[signature_len - 1] = '\0'; /* recv fields */ if (fields_len) { @@ -1465,6 +2341,90 @@ int ustctl_reply_register_event(int sock, return 0; } +/* + * Returns 0 on success, negative UST or system error value on error. + */ +int ustctl_recv_register_enum(int sock, + int *session_objd, + char *enum_name, + struct ustctl_enum_entry **entries, + size_t *nr_entries) +{ + ssize_t len; + struct ustcomm_notify_enum_msg msg; + size_t entries_len; + struct ustctl_enum_entry *a_entries = NULL; + + len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) + return -EIO; + if (len == 0) + return -EPIPE; + if (len < 0) + return len; + + *session_objd = msg.session_objd; + strncpy(enum_name, msg.enum_name, LTTNG_UST_ABI_SYM_NAME_LEN); + enum_name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0'; + entries_len = msg.entries_len; + + if (entries_len % sizeof(*a_entries) != 0) { + return -EINVAL; + } + + /* recv entries */ + if (entries_len) { + a_entries = zmalloc(entries_len); + if (!a_entries) + return -ENOMEM; + len = ustcomm_recv_unix_sock(sock, a_entries, entries_len); + if (len > 0 && len != entries_len) { + len = -EIO; + goto entries_error; + } + if (len == 0) { + len = -EPIPE; + goto entries_error; + } + if (len < 0) { + goto entries_error; + } + } + *nr_entries = entries_len / sizeof(*a_entries); + *entries = a_entries; + + return 0; + +entries_error: + free(a_entries); + return len; +} + +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_reply_register_enum(int sock, + uint64_t id, + int ret_code) +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_enum_reply r; + } reply; + + memset(&reply, 0, sizeof(reply)); + reply.header.notify_cmd = USTCTL_NOTIFY_CMD_ENUM; + reply.r.ret_code = ret_code; + reply.r.enum_id = id; + len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply)); + if (len > 0 && len != sizeof(reply)) + return -EIO; + if (len < 0) + return len; + return 0; +} + /* * Returns 0 on success, negative UST or system error value on error. */ @@ -1564,19 +2524,417 @@ int ustctl_reply_register_channel(int sock, return 0; } +/* Regenerate the statedump. */ +int ustctl_regenerate_statedump(int sock, int handle) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + memset(&lum, 0, sizeof(lum)); + lum.handle = handle; + lum.cmd = LTTNG_UST_ABI_SESSION_STATEDUMP; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + DBG("Regenerated statedump for handle %u", handle); + return 0; +} + +/* counter operations */ + +int ustctl_get_nr_cpu_per_counter(void) +{ + return lttng_counter_num_possible_cpus(); +} + +struct ustctl_daemon_counter * + ustctl_create_counter(size_t nr_dimensions, + const struct ustctl_counter_dimension *dimensions, + int64_t global_sum_step, + int global_counter_fd, + int nr_counter_cpu_fds, + const int *counter_cpu_fds, + enum ustctl_counter_bitness bitness, + enum ustctl_counter_arithmetic arithmetic, + uint32_t alloc_flags, + bool coalesce_hits) +{ + const char *transport_name; + struct ustctl_daemon_counter *counter; + struct lttng_counter_transport *transport; + struct lttng_counter_dimension ust_dim[LTTNG_COUNTER_DIMENSION_MAX]; + size_t i; + + if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX) + return NULL; + /* Currently, only per-cpu allocation is supported. */ + switch (alloc_flags) { + case USTCTL_COUNTER_ALLOC_PER_CPU: + break; + + case USTCTL_COUNTER_ALLOC_PER_CPU | USTCTL_COUNTER_ALLOC_GLOBAL: + case USTCTL_COUNTER_ALLOC_GLOBAL: + default: + return NULL; + } + switch (bitness) { + case USTCTL_COUNTER_BITNESS_32: + switch (arithmetic) { + case USTCTL_COUNTER_ARITHMETIC_MODULAR: + transport_name = "counter-per-cpu-32-modular"; + break; + case USTCTL_COUNTER_ARITHMETIC_SATURATION: + transport_name = "counter-per-cpu-32-saturation"; + break; + default: + return NULL; + } + break; + case USTCTL_COUNTER_BITNESS_64: + switch (arithmetic) { + case USTCTL_COUNTER_ARITHMETIC_MODULAR: + transport_name = "counter-per-cpu-64-modular"; + break; + case USTCTL_COUNTER_ARITHMETIC_SATURATION: + transport_name = "counter-per-cpu-64-saturation"; + break; + default: + return NULL; + } + break; + default: + return NULL; + } + + transport = lttng_counter_transport_find(transport_name); + if (!transport) { + DBG("LTTng transport %s not found\n", + transport_name); + return NULL; + } + + counter = zmalloc(sizeof(*counter)); + if (!counter) + return NULL; + counter->attr = zmalloc(sizeof(*counter->attr)); + if (!counter->attr) + goto free_counter; + counter->attr->bitness = bitness; + counter->attr->arithmetic = arithmetic; + counter->attr->nr_dimensions = nr_dimensions; + counter->attr->global_sum_step = global_sum_step; + counter->attr->coalesce_hits = coalesce_hits; + for (i = 0; i < nr_dimensions; i++) + counter->attr->dimensions[i] = dimensions[i]; + + for (i = 0; i < nr_dimensions; i++) { + ust_dim[i].size = dimensions[i].size; + ust_dim[i].underflow_index = dimensions[i].underflow_index; + ust_dim[i].overflow_index = dimensions[i].overflow_index; + ust_dim[i].has_underflow = dimensions[i].has_underflow; + ust_dim[i].has_overflow = dimensions[i].has_overflow; + } + counter->counter = transport->ops.counter_create(nr_dimensions, + ust_dim, global_sum_step, global_counter_fd, + nr_counter_cpu_fds, counter_cpu_fds, true); + if (!counter->counter) + goto free_attr; + counter->ops = &transport->ops; + return counter; + +free_attr: + free(counter->attr); +free_counter: + free(counter); + return NULL; +} + +int ustctl_create_counter_data(struct ustctl_daemon_counter *counter, + struct lttng_ust_abi_object_data **_counter_data) +{ + struct lttng_ust_abi_object_data *counter_data; + struct lttng_ust_abi_counter_conf counter_conf = {0}; + size_t i; + int ret; + + switch (counter->attr->arithmetic) { + case USTCTL_COUNTER_ARITHMETIC_MODULAR: + counter_conf.arithmetic = LTTNG_UST_ABI_COUNTER_ARITHMETIC_MODULAR; + break; + case USTCTL_COUNTER_ARITHMETIC_SATURATION: + counter_conf.arithmetic = LTTNG_UST_ABI_COUNTER_ARITHMETIC_SATURATION; + break; + default: + return -EINVAL; + } + switch (counter->attr->bitness) { + case USTCTL_COUNTER_BITNESS_32: + counter_conf.bitness = LTTNG_UST_ABI_COUNTER_BITNESS_32; + break; + case USTCTL_COUNTER_BITNESS_64: + counter_conf.bitness = LTTNG_UST_ABI_COUNTER_BITNESS_64; + break; + default: + return -EINVAL; + } + counter_conf.number_dimensions = counter->attr->nr_dimensions; + counter_conf.global_sum_step = counter->attr->global_sum_step; + counter_conf.coalesce_hits = counter->attr->coalesce_hits; + for (i = 0; i < counter->attr->nr_dimensions; i++) { + counter_conf.dimensions[i].size = counter->attr->dimensions[i].size; + counter_conf.dimensions[i].underflow_index = counter->attr->dimensions[i].underflow_index; + counter_conf.dimensions[i].overflow_index = counter->attr->dimensions[i].overflow_index; + counter_conf.dimensions[i].has_underflow = counter->attr->dimensions[i].has_underflow; + counter_conf.dimensions[i].has_overflow = counter->attr->dimensions[i].has_overflow; + } + + counter_data = zmalloc(sizeof(*counter_data)); + if (!counter_data) { + ret = -ENOMEM; + goto error_alloc; + } + counter_data->type = LTTNG_UST_ABI_OBJECT_TYPE_COUNTER; + counter_data->handle = -1; + + counter_data->size = sizeof(counter_conf); + counter_data->u.counter.data = zmalloc(sizeof(counter_conf)); + if (!counter_data->u.counter.data) { + ret = -ENOMEM; + goto error_alloc_data; + } + + memcpy(counter_data->u.counter.data, &counter_conf, sizeof(counter_conf)); + *_counter_data = counter_data; + + return 0; + +error_alloc_data: + free(counter_data); +error_alloc: + return ret; +} + +int ustctl_create_counter_global_data(struct ustctl_daemon_counter *counter, + struct lttng_ust_abi_object_data **_counter_global_data) +{ + struct lttng_ust_abi_object_data *counter_global_data; + int ret, fd; + size_t len; + + if (lttng_counter_get_global_shm(counter->counter, &fd, &len)) + return -EINVAL; + counter_global_data = zmalloc(sizeof(*counter_global_data)); + if (!counter_global_data) { + ret = -ENOMEM; + goto error_alloc; + } + counter_global_data->type = LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_GLOBAL; + counter_global_data->handle = -1; + counter_global_data->size = len; + counter_global_data->u.counter_global.shm_fd = fd; + *_counter_global_data = counter_global_data; + return 0; + +error_alloc: + return ret; +} + +int ustctl_create_counter_cpu_data(struct ustctl_daemon_counter *counter, int cpu, + struct lttng_ust_abi_object_data **_counter_cpu_data) +{ + struct lttng_ust_abi_object_data *counter_cpu_data; + int ret, fd; + size_t len; + + if (lttng_counter_get_cpu_shm(counter->counter, cpu, &fd, &len)) + return -EINVAL; + counter_cpu_data = zmalloc(sizeof(*counter_cpu_data)); + if (!counter_cpu_data) { + ret = -ENOMEM; + goto error_alloc; + } + counter_cpu_data->type = LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_CPU; + counter_cpu_data->handle = -1; + counter_cpu_data->size = len; + counter_cpu_data->u.counter_cpu.shm_fd = fd; + counter_cpu_data->u.counter_cpu.cpu_nr = cpu; + *_counter_cpu_data = counter_cpu_data; + return 0; + +error_alloc: + return ret; +} + +void ustctl_destroy_counter(struct ustctl_daemon_counter *counter) +{ + counter->ops->counter_destroy(counter->counter); + free(counter->attr); + free(counter); +} + +int ustctl_send_counter_data_to_ust(int sock, int parent_handle, + struct lttng_ust_abi_object_data *counter_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + size_t size; + ssize_t len; + + if (!counter_data) + return -EINVAL; + + size = counter_data->size; + memset(&lum, 0, sizeof(lum)); + lum.handle = parent_handle; + lum.cmd = LTTNG_UST_ABI_COUNTER; + lum.u.counter.len = size; + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + return ret; + + /* Send counter data */ + len = ustcomm_send_unix_sock(sock, counter_data->u.counter.data, size); + if (len != size) { + if (len < 0) + return len; + else + return -EIO; + } + + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (!ret) { + counter_data->handle = lur.ret_val; + } + return ret; +} + +int ustctl_send_counter_global_data_to_ust(int sock, + struct lttng_ust_abi_object_data *counter_data, + struct lttng_ust_abi_object_data *counter_global_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret, shm_fd[1]; + size_t size; + ssize_t len; + + if (!counter_data || !counter_global_data) + return -EINVAL; + + size = counter_global_data->size; + memset(&lum, 0, sizeof(lum)); + lum.handle = counter_data->handle; /* parent handle */ + lum.cmd = LTTNG_UST_ABI_COUNTER_GLOBAL; + lum.u.counter_global.len = size; + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + return ret; + + shm_fd[0] = counter_global_data->u.counter_global.shm_fd; + len = ustcomm_send_fds_unix_sock(sock, shm_fd, 1); + if (len <= 0) { + if (len < 0) + return len; + else + return -EIO; + } + + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (!ret) { + counter_global_data->handle = lur.ret_val; + } + return ret; +} + +int ustctl_send_counter_cpu_data_to_ust(int sock, + struct lttng_ust_abi_object_data *counter_data, + struct lttng_ust_abi_object_data *counter_cpu_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret, shm_fd[1]; + size_t size; + ssize_t len; + + if (!counter_data || !counter_cpu_data) + return -EINVAL; + + size = counter_cpu_data->size; + memset(&lum, 0, sizeof(lum)); + lum.handle = counter_data->handle; /* parent handle */ + lum.cmd = LTTNG_UST_ABI_COUNTER_CPU; + lum.u.counter_cpu.len = size; + lum.u.counter_cpu.cpu_nr = counter_cpu_data->u.counter_cpu.cpu_nr; + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + return ret; + + shm_fd[0] = counter_cpu_data->u.counter_global.shm_fd; + len = ustcomm_send_fds_unix_sock(sock, shm_fd, 1); + if (len <= 0) { + if (len < 0) + return len; + else + return -EIO; + } + + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (!ret) { + counter_cpu_data->handle = lur.ret_val; + } + return ret; +} + +int ustctl_counter_read(struct ustctl_daemon_counter *counter, + const size_t *dimension_indexes, + int cpu, int64_t *value, + bool *overflow, bool *underflow) +{ + return counter->ops->counter_read(counter->counter, dimension_indexes, cpu, + value, overflow, underflow); +} + +int ustctl_counter_aggregate(struct ustctl_daemon_counter *counter, + const size_t *dimension_indexes, + int64_t *value, + bool *overflow, bool *underflow) +{ + return counter->ops->counter_aggregate(counter->counter, dimension_indexes, + value, overflow, underflow); +} + +int ustctl_counter_clear(struct ustctl_daemon_counter *counter, + const size_t *dimension_indexes) +{ + return counter->ops->counter_clear(counter->counter, dimension_indexes); +} + static __attribute__((constructor)) void ustctl_init(void) { - init_usterr(); + ust_err_init(); + lttng_ust_getenv_init(); /* Needs ust_err_init() to be completed. */ + lttng_ust_clock_init(); lttng_ring_buffer_metadata_client_init(); lttng_ring_buffer_client_overwrite_init(); + lttng_ring_buffer_client_overwrite_rt_init(); lttng_ring_buffer_client_discard_init(); + lttng_ring_buffer_client_discard_rt_init(); + lttng_counter_client_percpu_32_modular_init(); + lttng_counter_client_percpu_64_modular_init(); + lib_ringbuffer_signal_init(); } static __attribute__((destructor)) void ustctl_exit(void) { + lttng_ring_buffer_client_discard_rt_exit(); lttng_ring_buffer_client_discard_exit(); + lttng_ring_buffer_client_overwrite_rt_exit(); lttng_ring_buffer_client_overwrite_exit(); lttng_ring_buffer_metadata_client_exit(); + lttng_counter_client_percpu_32_modular_exit(); + lttng_counter_client_percpu_64_modular_exit(); }