#include "../utils.h"
+static struct lttng_channel chan_opts;
static char *opt_channels;
static int opt_kernel;
static char *opt_session_name;
static int opt_userspace;
-static struct lttng_channel chan;
static char *opt_output;
static int opt_buffer_uid;
static int opt_buffer_pid;
static int opt_buffer_global;
+static struct {
+ bool set;
+ uint32_t interval;
+} opt_monitor_timer;
static struct mi_writer *writer;
OPT_SUBBUF_SIZE,
OPT_NUM_SUBBUF,
OPT_SWITCH_TIMER,
+ OPT_MONITOR_TIMER,
OPT_READ_TIMER,
OPT_USERSPACE,
OPT_LIST_OPTIONS,
{"subbuf-size", 0, POPT_ARG_STRING, 0, OPT_SUBBUF_SIZE, 0, 0},
{"num-subbuf", 0, POPT_ARG_INT, 0, OPT_NUM_SUBBUF, 0, 0},
{"switch-timer", 0, POPT_ARG_INT, 0, OPT_SWITCH_TIMER, 0, 0},
+ {"monitor-timer", 0, POPT_ARG_INT, 0, OPT_MONITOR_TIMER, 0, 0},
{"read-timer", 0, POPT_ARG_INT, 0, OPT_READ_TIMER, 0, 0},
{"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
{"output", 0, POPT_ARG_STRING, &opt_output, 0, 0, 0},
/* Set attributes */
lttng_channel_set_default_attr(dom, &default_attr);
- if (chan.attr.overwrite == -1) {
- chan.attr.overwrite = default_attr.overwrite;
+ if (chan_opts.attr.overwrite == -1) {
+ chan_opts.attr.overwrite = default_attr.overwrite;
}
- if (chan.attr.subbuf_size == -1) {
- chan.attr.subbuf_size = default_attr.subbuf_size;
+ if (chan_opts.attr.subbuf_size == -1) {
+ chan_opts.attr.subbuf_size = default_attr.subbuf_size;
}
- if (chan.attr.num_subbuf == -1) {
- chan.attr.num_subbuf = default_attr.num_subbuf;
+ if (chan_opts.attr.num_subbuf == -1) {
+ chan_opts.attr.num_subbuf = default_attr.num_subbuf;
}
- if (chan.attr.switch_timer_interval == -1) {
- chan.attr.switch_timer_interval = default_attr.switch_timer_interval;
+ if (chan_opts.attr.switch_timer_interval == -1) {
+ chan_opts.attr.switch_timer_interval = default_attr.switch_timer_interval;
}
- if (chan.attr.read_timer_interval == -1) {
- chan.attr.read_timer_interval = default_attr.read_timer_interval;
+ if (chan_opts.attr.read_timer_interval == -1) {
+ chan_opts.attr.read_timer_interval = default_attr.read_timer_interval;
}
- if ((int) chan.attr.output == -1) {
- chan.attr.output = default_attr.output;
+ if ((int) chan_opts.attr.output == -1) {
+ chan_opts.attr.output = default_attr.output;
}
- if (chan.attr.tracefile_count == -1) {
- chan.attr.tracefile_count = default_attr.tracefile_count;
+ if (chan_opts.attr.tracefile_count == -1) {
+ chan_opts.attr.tracefile_count = default_attr.tracefile_count;
}
- if (chan.attr.tracefile_size == -1) {
- chan.attr.tracefile_size = default_attr.tracefile_size;
+ if (chan_opts.attr.tracefile_size == -1) {
+ chan_opts.attr.tracefile_size = default_attr.tracefile_size;
}
}
*/
static int enable_channel(char *session_name)
{
+ struct lttng_channel *channel = NULL;
int ret = CMD_SUCCESS, warn = 0, error = 0, success = 0;
char *channel_name;
struct lttng_domain dom;
set_default_attr(&dom);
- if (chan.attr.tracefile_size == 0 && chan.attr.tracefile_count) {
+ if (chan_opts.attr.tracefile_size == 0 && chan_opts.attr.tracefile_count) {
ERR("Missing option --tracefile-size. "
"A file count without a size won't do anything.");
ret = CMD_ERROR;
goto error;
}
- if ((chan.attr.tracefile_size > 0) &&
- (chan.attr.tracefile_size < chan.attr.subbuf_size)) {
+ if ((chan_opts.attr.tracefile_size > 0) &&
+ (chan_opts.attr.tracefile_size < chan_opts.attr.subbuf_size)) {
WARN("Tracefile size rounded up from (%" PRIu64 ") to subbuffer size (%" PRIu64 ")",
- chan.attr.tracefile_size, chan.attr.subbuf_size);
- chan.attr.tracefile_size = chan.attr.subbuf_size;
+ chan_opts.attr.tracefile_size, chan_opts.attr.subbuf_size);
+ chan_opts.attr.tracefile_size = chan_opts.attr.subbuf_size;
}
/* Setting channel output */
if (opt_output) {
if (!strncmp(output_mmap, opt_output, strlen(output_mmap))) {
- chan.attr.output = LTTNG_EVENT_MMAP;
+ chan_opts.attr.output = LTTNG_EVENT_MMAP;
} else if (!strncmp(output_splice, opt_output, strlen(output_splice))) {
- chan.attr.output = LTTNG_EVENT_SPLICE;
+ chan_opts.attr.output = LTTNG_EVENT_SPLICE;
} else {
ERR("Unknown output type %s. Possible values are: %s, %s\n",
opt_output, output_mmap, output_splice);
/* Strip channel list (format: chan1,chan2,...) */
channel_name = strtok(opt_channels, ",");
while (channel_name != NULL) {
+ void *extended_ptr;
+
/* Validate channel name's length */
if (strlen(channel_name) >= NAME_MAX) {
ERR("Channel name is too long (max. %zu characters)",
- sizeof(chan.name) - 1);
+ sizeof(chan_opts.name) - 1);
error = 1;
goto skip_enable;
}
+ /*
+ * A dynamically-allocated channel is used in order to allow
+ * the configuration of extended attributes (post-2.9).
+ */
+ channel = lttng_channel_create(&dom);
+ if (!channel) {
+ ERR("Unable to create channel object");
+ error = 1;
+ goto error;
+ }
+
/* Copy channel name */
- strcpy(chan.name, channel_name);
+ strcpy(channel->name, channel_name);
+ channel->enabled = 1;
+ extended_ptr = channel->attr.extended.ptr;
+ memcpy(&channel->attr, &chan_opts.attr, sizeof(chan_opts.attr));
+ channel->attr.extended.ptr = extended_ptr;
+ if (opt_monitor_timer.set) {
+ ret = lttng_channel_set_monitor_timer_interval(channel,
+ opt_monitor_timer.interval);
+ if (ret) {
+ ERR("Failed to set the channel's monitor timer interval");
+ error = 1;
+ goto error;
+ }
+ }
DBG("Enabling channel %s", channel_name);
- ret = lttng_enable_channel(handle, &chan);
+ ret = lttng_enable_channel(handle, channel);
if (ret < 0) {
success = 0;
switch (-ret) {
skip_enable:
if (lttng_opt_mi) {
/* Mi print the channel element and leave it open */
- ret = mi_lttng_channel(writer, &chan, 1);
+ ret = mi_lttng_channel(writer, channel, 1);
if (ret) {
ret = CMD_ERROR;
goto error;
/* Next channel */
channel_name = strtok(NULL, ",");
+ lttng_channel_destroy(channel);
+ channel = NULL;
}
if (lttng_opt_mi) {
ret = CMD_SUCCESS;
error:
+ if (channel) {
+ lttng_channel_destroy(channel);
+ }
/* If more important error happen bypass the warning */
if (!ret && warn) {
ret = CMD_WARNING;
* Put -1 everywhere so we can identify those set by the command line and
* those needed to be set by the default values.
*/
- memset(&chan.attr, -1, sizeof(chan.attr));
- chan.attr.extended.ptr = NULL;
+ memset(&chan_opts.attr, -1, sizeof(chan_opts.attr));
+ chan_opts.attr.extended.ptr = NULL;
}
/*
SHOW_HELP();
goto end;
case OPT_DISCARD:
- chan.attr.overwrite = 0;
+ chan_opts.attr.overwrite = 0;
DBG("Channel set to discard");
break;
case OPT_OVERWRITE:
- chan.attr.overwrite = 1;
+ chan_opts.attr.overwrite = 1;
DBG("Channel set to overwrite");
break;
case OPT_SUBBUF_SIZE:
/* Parse the size */
opt_arg = poptGetOptArg(pc);
- if (utils_parse_size_suffix(opt_arg, &chan.attr.subbuf_size) < 0 || !chan.attr.subbuf_size) {
+ if (utils_parse_size_suffix(opt_arg, &chan_opts.attr.subbuf_size) < 0 || !chan_opts.attr.subbuf_size) {
ERR("Wrong value in --subbuf-size parameter: %s", opt_arg);
ret = CMD_ERROR;
goto end;
}
- order = get_count_order_u64(chan.attr.subbuf_size);
+ order = get_count_order_u64(chan_opts.attr.subbuf_size);
assert(order >= 0);
rounded_size = 1ULL << order;
- if (rounded_size < chan.attr.subbuf_size) {
+ if (rounded_size < chan_opts.attr.subbuf_size) {
ERR("The subbuf size (%" PRIu64 ") is rounded and overflows!",
- chan.attr.subbuf_size);
+ chan_opts.attr.subbuf_size);
ret = CMD_ERROR;
goto end;
}
- if (rounded_size != chan.attr.subbuf_size) {
+ if (rounded_size != chan_opts.attr.subbuf_size) {
WARN("The subbuf size (%" PRIu64 ") is rounded to the next power of 2 (%" PRIu64 ")",
- chan.attr.subbuf_size, rounded_size);
- chan.attr.subbuf_size = rounded_size;
+ chan_opts.attr.subbuf_size, rounded_size);
+ chan_opts.attr.subbuf_size = rounded_size;
}
/* Should now be power of 2 */
- assert(!((chan.attr.subbuf_size - 1) & chan.attr.subbuf_size));
+ assert(!((chan_opts.attr.subbuf_size - 1) & chan_opts.attr.subbuf_size));
- DBG("Channel subbuf size set to %" PRIu64, chan.attr.subbuf_size);
+ DBG("Channel subbuf size set to %" PRIu64, chan_opts.attr.subbuf_size);
break;
}
case OPT_NUM_SUBBUF:
errno = 0;
opt_arg = poptGetOptArg(pc);
- chan.attr.num_subbuf = strtoull(opt_arg, NULL, 0);
- if (errno != 0 || !chan.attr.num_subbuf || !isdigit(opt_arg[0])) {
+ chan_opts.attr.num_subbuf = strtoull(opt_arg, NULL, 0);
+ if (errno != 0 || !chan_opts.attr.num_subbuf || !isdigit(opt_arg[0])) {
ERR("Wrong value in --num-subbuf parameter: %s", opt_arg);
ret = CMD_ERROR;
goto end;
}
- order = get_count_order_u64(chan.attr.num_subbuf);
+ order = get_count_order_u64(chan_opts.attr.num_subbuf);
assert(order >= 0);
rounded_size = 1ULL << order;
- if (rounded_size < chan.attr.num_subbuf) {
+ if (rounded_size < chan_opts.attr.num_subbuf) {
ERR("The number of subbuffers (%" PRIu64 ") is rounded and overflows!",
- chan.attr.num_subbuf);
+ chan_opts.attr.num_subbuf);
ret = CMD_ERROR;
goto end;
}
- if (rounded_size != chan.attr.num_subbuf) {
+ if (rounded_size != chan_opts.attr.num_subbuf) {
WARN("The number of subbuffers (%" PRIu64 ") is rounded to the next power of 2 (%" PRIu64 ")",
- chan.attr.num_subbuf, rounded_size);
- chan.attr.num_subbuf = rounded_size;
+ chan_opts.attr.num_subbuf, rounded_size);
+ chan_opts.attr.num_subbuf = rounded_size;
}
/* Should now be power of 2 */
- assert(!((chan.attr.num_subbuf - 1) & chan.attr.num_subbuf));
+ assert(!((chan_opts.attr.num_subbuf - 1) & chan_opts.attr.num_subbuf));
- DBG("Channel subbuf num set to %" PRIu64, chan.attr.num_subbuf);
+ DBG("Channel subbuf num set to %" PRIu64, chan_opts.attr.num_subbuf);
break;
}
case OPT_SWITCH_TIMER:
ret = CMD_ERROR;
goto end;
}
- chan.attr.switch_timer_interval = (uint32_t) v;
- DBG("Channel switch timer interval set to %d", chan.attr.switch_timer_interval);
+ chan_opts.attr.switch_timer_interval = (uint32_t) v;
+ DBG("Channel switch timer interval set to %d", chan_opts.attr.switch_timer_interval);
break;
}
case OPT_READ_TIMER:
ret = CMD_ERROR;
goto end;
}
- chan.attr.read_timer_interval = (uint32_t) v;
- DBG("Channel read timer interval set to %d", chan.attr.read_timer_interval);
+ chan_opts.attr.read_timer_interval = (uint32_t) v;
+ DBG("Channel read timer interval set to %d", chan_opts.attr.read_timer_interval);
+ break;
+ }
+ case OPT_MONITOR_TIMER:
+ {
+ unsigned long v;
+
+ errno = 0;
+ opt_arg = poptGetOptArg(pc);
+ v = strtoul(opt_arg, NULL, 0);
+ if (errno != 0 || !isdigit(opt_arg[0])) {
+ ERR("Wrong value in --monitor-timer parameter: %s", opt_arg);
+ ret = CMD_ERROR;
+ goto end;
+ }
+ if (v != (uint32_t) v) {
+ ERR("32-bit overflow in --monitor-timer parameter: %s", opt_arg);
+ ret = CMD_ERROR;
+ goto end;
+ }
+ opt_monitor_timer.interval = (uint32_t) v;
+ opt_monitor_timer.set = true;
+ DBG("Channel monitor timer interval set to %d", opt_monitor_timer.interval);
break;
}
case OPT_USERSPACE:
break;
case OPT_TRACEFILE_SIZE:
opt_arg = poptGetOptArg(pc);
- if (utils_parse_size_suffix(opt_arg, &chan.attr.tracefile_size) < 0) {
+ if (utils_parse_size_suffix(opt_arg, &chan_opts.attr.tracefile_size) < 0) {
ERR("Wrong value in --tracefile-size parameter: %s", opt_arg);
ret = CMD_ERROR;
goto end;
}
DBG("Maximum tracefile size set to %" PRIu64,
- chan.attr.tracefile_size);
+ chan_opts.attr.tracefile_size);
break;
case OPT_TRACEFILE_COUNT:
{
ret = CMD_ERROR;
goto end;
}
- chan.attr.tracefile_count = (uint32_t) v;
+ chan_opts.attr.tracefile_count = (uint32_t) v;
DBG("Maximum tracefile count set to %" PRIu64,
- chan.attr.tracefile_count);
+ chan_opts.attr.tracefile_count);
break;
}
case OPT_LIST_OPTIONS:
return lttng_disable_event_ext(handle, &ev, channel_name, NULL);
}
+struct lttng_channel *lttng_channel_create(struct lttng_domain *domain)
+{
+ struct lttng_channel *channel = NULL;
+ struct lttng_channel_extended *extended = NULL;
+
+ if (!domain) {
+ goto error;
+ }
+
+ /* Validate domain. */
+ switch (domain->type) {
+ case LTTNG_DOMAIN_UST:
+ switch (domain->buf_type) {
+ case LTTNG_BUFFER_PER_UID:
+ case LTTNG_BUFFER_PER_PID:
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ if (domain->buf_type != LTTNG_BUFFER_GLOBAL) {
+ goto error;
+ }
+ break;
+ default:
+ goto error;
+ }
+
+ channel = zmalloc(sizeof(*channel));
+ if (!channel) {
+ goto error;
+ }
+
+ extended = zmalloc(sizeof(*extended));
+ if (!extended) {
+ goto error;
+ }
+
+ channel->attr.extended.ptr = extended;
+
+ lttng_channel_set_default_attr(domain, &channel->attr);
+ return channel;
+error:
+ free(channel);
+ free(extended);
+ return NULL;
+}
+
+void lttng_channel_destroy(struct lttng_channel *channel)
+{
+ if (!channel) {
+ return;
+ }
+
+ if (channel->attr.extended.ptr) {
+ free(channel->attr.extended.ptr);
+ }
+ free(channel);
+}
+
/*
* Enable channel per domain
* Returns size of returned session payload data or a negative error code.
*/
int lttng_enable_channel(struct lttng_handle *handle,
- struct lttng_channel *chan)
+ struct lttng_channel *in_chan)
{
struct lttcomm_session_msg lsm;
/* NULL arguments are forbidden. No default values. */
- if (handle == NULL || chan == NULL) {
+ if (handle == NULL || in_chan == NULL) {
return -LTTNG_ERR_INVALID;
}
memset(&lsm, 0, sizeof(lsm));
+ memcpy(&lsm.u.channel.chan, in_chan, sizeof(lsm.u.channel.chan));
+ lsm.u.channel.chan.attr.extended.ptr = NULL;
- memcpy(&lsm.u.channel.chan, chan, sizeof(lsm.u.channel.chan));
+ if (!in_chan->attr.extended.ptr) {
+ struct lttng_channel *channel;
+ struct lttng_channel_extended *extended;
- lsm.cmd_type = LTTNG_ENABLE_CHANNEL;
+ channel = lttng_channel_create(&handle->domain);
+ if (!channel) {
+ return -LTTNG_ERR_NOMEM;
+ }
+
+ /*
+ * Create a new channel in order to use default extended
+ * attribute values.
+ */
+ extended = (struct lttng_channel_extended *)
+ channel->attr.extended.ptr;
+ memcpy(&lsm.u.channel.extended, extended, sizeof(*extended));
+ lttng_channel_destroy(channel);
+ } else {
+ struct lttng_channel_extended *extended;
+
+ extended = (struct lttng_channel_extended *)
+ in_chan->attr.extended.ptr;
+ memcpy(&lsm.u.channel.extended, extended, sizeof(*extended));
+ }
+ lsm.cmd_type = LTTNG_ENABLE_CHANNEL;
lttng_ctl_copy_lttng_domain(&lsm.domain, &handle->domain);
lttng_ctl_copy_string(lsm.session.name, handle->session_name,
int ret;
size_t channel_count, i;
const size_t channel_size = sizeof(struct lttng_channel) +
- sizeof(struct lttcomm_channel_extended);
+ sizeof(struct lttng_channel_extended);
struct lttcomm_session_msg lsm;
void *extended_at;
struct lttng_channel *chan = &(*channels)[i];
chan->attr.extended.ptr = extended_at;
- extended_at += sizeof(struct lttcomm_channel_extended);
+ extended_at += sizeof(struct lttng_channel_extended);
}
ret = (int) channel_count;
void lttng_channel_set_default_attr(struct lttng_domain *domain,
struct lttng_channel_attr *attr)
{
+ struct lttng_channel_extended *extended =
+ (struct lttng_channel_extended *) attr->extended.ptr;
+
/* Safety check */
if (attr == NULL || domain == NULL) {
return;
attr->subbuf_size = default_get_kernel_channel_subbuf_size();
attr->num_subbuf = DEFAULT_KERNEL_CHANNEL_SUBBUF_NUM;
attr->output = DEFAULT_KERNEL_CHANNEL_OUTPUT;
+ if (extended) {
+ extended->monitor_timer_interval =
+ DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER;
+ }
break;
case LTTNG_DOMAIN_UST:
switch (domain->buf_type) {
DEFAULT_UST_UID_CHANNEL_SWITCH_TIMER;
attr->read_timer_interval =
DEFAULT_UST_UID_CHANNEL_READ_TIMER;
+ if (extended) {
+ extended->monitor_timer_interval =
+ DEFAULT_UST_UID_CHANNEL_MONITOR_TIMER;
+ }
break;
case LTTNG_BUFFER_PER_PID:
default:
DEFAULT_UST_PID_CHANNEL_SWITCH_TIMER;
attr->read_timer_interval =
DEFAULT_UST_PID_CHANNEL_READ_TIMER;
+ if (extended) {
+ extended->monitor_timer_interval =
+ DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER;
+ }
break;
}
default:
/* Default behavior: leave set to 0. */
break;
}
+
+ attr->extended.ptr = extended;
}
int lttng_channel_get_discarded_event_count(struct lttng_channel *channel,
uint64_t *discarded_events)
{
int ret = 0;
- struct lttcomm_channel_extended *chan_ext;
+ struct lttng_channel_extended *chan_ext;
if (!channel || !discarded_events) {
ret = -LTTNG_ERR_INVALID;
uint64_t *lost_packets)
{
int ret = 0;
- struct lttcomm_channel_extended *chan_ext;
+ struct lttng_channel_extended *chan_ext;
if (!channel || !lost_packets) {
ret = -LTTNG_ERR_INVALID;
return ret;
}
+int lttng_channel_get_monitor_timer_interval(struct lttng_channel *chan,
+ uint64_t *monitor_timer_interval)
+{
+ int ret = 0;
+
+ if (!chan || !monitor_timer_interval) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (!chan->attr.extended.ptr) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ *monitor_timer_interval = ((struct lttng_channel_extended *)
+ chan->attr.extended.ptr)->monitor_timer_interval;
+end:
+ return ret;
+}
+
+int lttng_channel_set_monitor_timer_interval(struct lttng_channel *chan,
+ uint64_t monitor_timer_interval)
+{
+ int ret = 0;
+
+ if (!chan || !chan->attr.extended.ptr) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ ((struct lttng_channel_extended *)
+ chan->attr.extended.ptr)->monitor_timer_interval =
+ monitor_timer_interval;
+end:
+ return ret;
+}
+
/*
* Check if session daemon is alive.
*