#include <urcu/list.h>
+#include <common/mi-lttng.h>
+
#include "../command.h"
#define PRINT_LINE_LEN 80
static int opt_kernel;
static int opt_userspace;
static char *opt_type;
+
#if 0
/* Not implemented yet */
static char *opt_cmd_name;
};
static struct lttng_handle *handle;
+static struct mi_writer *writer;
/*
* Taken from the LTTng ABI
*/
static int add_context(char *session_name)
{
- int ret = CMD_SUCCESS, warn = 0;
+ int ret = CMD_SUCCESS, warn = 0, success = 0;
struct lttng_event_context context;
struct lttng_domain dom;
struct ctx_type *type;
goto error;
}
+ if (lttng_opt_mi) {
+ /* Open a contexts element */
+ ret = mi_lttng_writer_open_element(writer, config_element_contexts);
+ if (ret) {
+ goto error;
+ }
+ }
+
/* Iterate over all the context types given */
cds_list_for_each_entry(type, &ctx_type_list.head, list) {
context.ctx = (enum lttng_event_context_type) type->opt->ctx_type;
}
DBG("Adding context...");
+ if (lttng_opt_mi) {
+ /* We leave context open the update the success of the command */
+ ret = mi_lttng_context(writer, &context, 1);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto error;
+ }
+ }
+
ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
if (ret < 0) {
ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
warn = 1;
- continue;
+ success = 0;
} else {
if (opt_channel_name) {
MSG("%s context %s added to channel %s",
MSG("%s context %s added to all channels",
opt_kernel ? "kernel" : "UST", type->opt->symbol)
}
+ success = 1;
+ }
+
+ if (lttng_opt_mi) {
+ /* Is the single operation a success ? */
+ ret = mi_lttng_writer_write_element_bool(writer,
+ mi_lttng_element_success, success);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto error;
+ }
+
+ /* Close the context element */
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto error;
+ }
+ }
+ }
+
+ if (lttng_opt_mi) {
+ /* Close contexts element */
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ goto error;
}
}
* This means that at least one add_context failed and tells the user to
* look on stderr for error(s).
*/
- if (warn) {
+ if (!ret && warn) {
ret = CMD_WARNING;
}
return ret;
*/
int cmd_add_context(int argc, const char **argv)
{
- int index, opt, ret = CMD_SUCCESS;
+ int index, opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
+ int success = 1;
static poptContext pc;
struct ctx_type *type, *tmptype;
char *session_name = NULL;
goto end;
}
- /* TODO: mi support */
- if (lttng_opt_mi) {
- ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED;
- ERR("mi option not supported");
- goto end;
- }
-
pc = poptGetContext(NULL, argc, argv, long_options, 0);
poptReadDefaultConfig(pc, 0);
session_name = opt_session_name;
}
- ret = add_context(session_name);
+ /* Mi check */
+ if (lttng_opt_mi) {
+ writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+ if (!writer) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ /* Open command element */
+ ret = mi_lttng_writer_command_open(writer,
+ mi_lttng_element_command_add_context);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ /* Open output element */
+ ret = mi_lttng_writer_open_element(writer,
+ mi_lttng_element_command_output);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+ }
+
+ command_ret = add_context(session_name);
+ if (command_ret) {
+ success = 0;
+ }
+
+ /* Mi closing */
+ if (lttng_opt_mi) {
+ /* Close output element */
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+ /* Success ? */
+ ret = mi_lttng_writer_write_element_bool(writer,
+ mi_lttng_element_command_success, success);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ /* Command element close */
+ ret = mi_lttng_writer_command_close(writer);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+ }
+
+end:
if (!opt_session_name) {
free(session_name);
}
-end:
+ /* Mi clean-up */
+ if (writer && mi_lttng_writer_destroy(writer)) {
+ /* Preserve original error code */
+ ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
+ }
+
/* Cleanup allocated memory */
cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
free(type);
}
+ /* Overwrite ret if an error occurred during add_context() */
+ ret = command_ret ? command_ret : ret;
+
poptFreeContext(pc);
return ret;
}
const char * const mi_lttng_element_command_create = "create";
const char * const mi_lttng_element_command_destroy = "destroy";
const char * const mi_lttng_element_command_calibrate = "calibrate";
+const char * const mi_lttng_element_command_add_context = "add-context";
const char * const mi_lttng_element_command_output = "output";
const char * const mi_lttng_element_command_success = "success";
const char * const mi_lttng_element_event_field = "event_field";
const char * const mi_lttng_element_event_fields = "event_fields";
+/* String related to lttng_event_context */
+const char * const mi_lttng_context_type_perf_counter = "PERF_COUNTER";
+const char * const mi_lttng_context_type_perf_cpu_counter = "PERF_CPU_COUNTER";
+const char * const mi_lttng_context_type_perf_thread_counter = "PERF_THREAD_COUNTER";
+
+/* String related to lttng_event_perf_counter_ctx */
+const char * const mi_lttng_element_perf_counter_context = "perf_counter_context";
+
/* General elements of mi_lttng */
const char * const mi_lttng_element_type_other = "OTHER";
const char * const mi_lttng_element_type_integer = "INTEGER";
const char * const mi_lttng_element_type_float = "FLOAT";
const char * const mi_lttng_element_type_string = "STRING";
const char * const mi_lttng_element_nowrite = "nowrite";
+const char * const mi_lttng_element_success = "success";
/* String related to loglevel */
const char * const mi_lttng_loglevel_str_alert = "TRACE_ALERT";
}
}
+const char *mi_lttng_event_contexttype_string(enum lttng_event_context_type val)
+{
+ switch (val) {
+ case LTTNG_EVENT_CONTEXT_PID:
+ return config_event_context_pid;
+ case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
+ return mi_lttng_context_type_perf_counter;
+ case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
+ return mi_lttng_context_type_perf_thread_counter;
+ case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
+ return mi_lttng_context_type_perf_cpu_counter;
+ case LTTNG_EVENT_CONTEXT_PROCNAME:
+ return config_event_context_procname;
+ case LTTNG_EVENT_CONTEXT_PRIO:
+ return config_event_context_prio;
+ case LTTNG_EVENT_CONTEXT_NICE:
+ return config_event_context_nice;
+ case LTTNG_EVENT_CONTEXT_VPID:
+ return config_event_context_vpid;
+ case LTTNG_EVENT_CONTEXT_TID:
+ return config_event_context_tid;
+ case LTTNG_EVENT_CONTEXT_VTID:
+ return config_event_context_vtid;
+ case LTTNG_EVENT_CONTEXT_PPID:
+ return config_event_context_ppid;
+ case LTTNG_EVENT_CONTEXT_VPPID:
+ return config_event_context_vppid;
+ case LTTNG_EVENT_CONTEXT_PTHREAD_ID:
+ return config_event_context_pthread_id;
+ case LTTNG_EVENT_CONTEXT_HOSTNAME:
+ return config_event_context_hostname;
+ case LTTNG_EVENT_CONTEXT_IP:
+ return config_event_context_ip;
+ default:
+ return NULL;
+ }
+}
+
const char *mi_lttng_eventfieldtype_string(enum lttng_event_field_type val)
{
switch (val) {
end:
return ret;
}
+LTTNG_HIDDEN
+int mi_lttng_context(struct mi_writer *writer,
+ struct lttng_event_context *context, int is_open)
+{
+ int ret;
+ const char *type_string;
+ struct lttng_event_perf_counter_ctx *perf_context;
+ /* Open context */
+ ret = mi_lttng_writer_open_element(writer , config_element_context);
+ if (ret) {
+ goto end;
+ }
+
+ type_string = mi_lttng_event_contexttype_string(context->ctx);
+ if (!type_string) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ /* Print context type */
+ ret = mi_lttng_writer_write_element_string(writer, config_element_type,
+ type_string);
+
+ /* Special case for PERF_*_COUNTER
+ * print the lttng_event_perf_counter_ctx*/
+ switch (context->ctx) {
+ case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
+ case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
+ case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
+ perf_context = &context->u.perf_counter;
+ ret = mi_lttng_perf_counter_context(writer, perf_context);
+ if (ret) {
+ goto end;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Close context */
+ if (!is_open) {
+ ret = mi_lttng_writer_close_element(writer);
+ }
+
+end:
+ return ret;
+}
+
+LTTNG_HIDDEN
+int mi_lttng_perf_counter_context(struct mi_writer *writer,
+ struct lttng_event_perf_counter_ctx *perf_context)
+{
+ int ret;
+
+ /* Open perf_counter_context */
+ ret = mi_lttng_writer_open_element(writer,
+ mi_lttng_element_perf_counter_context);
+ if (ret) {
+ goto end;
+ }
+
+ /* Type */
+ ret = mi_lttng_writer_write_element_unsigned_int(writer,
+ config_element_type, perf_context->type);
+ if (ret) {
+ goto end;
+ }
+
+ /* Config */
+ ret = mi_lttng_writer_write_element_unsigned_int(writer,
+ config_element_config, perf_context->config);
+ if (ret) {
+ goto end;
+ }
+
+ /* Name of the perf counter */
+ ret = mi_lttng_writer_write_element_string(writer,
+ config_element_name, perf_context->name);
+ if (ret) {
+ goto end;
+ }
+
+ /* Close perf_counter_context */
+ ret = mi_lttng_writer_close_element(writer);
+end:
+ return ret;
+}
const char * const mi_lttng_element_command_create;
const char * const mi_lttng_element_command_destroy;
const char * const mi_lttng_element_command_calibrate;
+const char * const mi_lttng_element_command_add_context;
const char * const mi_lttng_element_command_output;
const char * const mi_lttng_element_command_success;
const char * const mi_lttng_element_event_field;
const char * const mi_lttng_element_event_fields;
+/* String related to lttng_event_context */
+const char * const mi_lttng_context_type_perf_counter;
+const char * const mi_lttng_context_type_perf_cpu_counter;
+const char * const mi_lttng_context_type_perf_thread_counter;
+
+/* String related to lttng_event_perf_counter_ctx */
+const char * const mi_lttng_element_perf_counter_context;
+
/* Strings related to pid */
const char * const mi_lttng_element_pids;
const char * const mi_lttng_element_pid;
const char * const mi_lttng_element_type_float;
const char * const mi_lttng_element_type_string;
const char * const mi_lttng_element_nowrite;
+const char * const mi_lttng_element_success;
/* String related to loglevel */
const char * const mi_lttng_loglevel_str_alert;
*
* writer An instance of a machine interface writer.
*
- * Returns zero if the element's value could be written.
+ * Returns zero if the element could be written.
* Negative values indicate an error.
*/
int mi_lttng_event_fields_open(struct mi_writer *writer);
int mi_lttng_calibrate(struct mi_writer *writer,
struct lttng_calibrate *calibrate);
+/*
+ * Machine interface of a context.
+ *
+ * writer An instance of a machine interface writer
+ *
+ * context An instance of a lttng_event_context
+ *
+ * is_open Define if we close the context element
+ * This should be used carefully and the client
+ * need to close the context element.
+ * 0-> False
+ * 1-> True
+ * Returns zero if the element's value could be written.
+ * Negative values indicate an error.
+ */
+int mi_lttng_context(struct mi_writer *writer,
+ struct lttng_event_context *context, int is_open);
+
+/*
+ * Machine interface of a perf_counter_context.
+ *
+ * writer An instance of a machine interface writer
+ *
+ * contest An instance of a lttng_event_perf_counter_ctx
+ *
+ * Returns zero if the element's value could be written.
+ * Negative values indicate an error.
+ */
+int mi_lttng_perf_counter_context(struct mi_writer *writer,
+ struct lttng_event_perf_counter_ctx *perf_context);
+
#endif /* _MI_LTTNG_H */
</xs:restriction>
</xs:simpleType>
+ <!-- Maps to the lttng_loglevel_type enum -->
+ <xs:simpleType name="context_type_type">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="PERF_COUNTER" />
+ <xs:enumeration value="PERF_CPU_COUNTER" />
+ <xs:enumeration value="PERF_THREAD_COUNTER" />
+ <xs:enumeration value="PID" />
+ <xs:enumeration value="PROCNAME" />
+ <xs:enumeration value="PRIO" />
+ <xs:enumeration value="NICE" />
+ <xs:enumeration value="VPID" />
+ <xs:enumeration value="TID" />
+ <xs:enumeration value="VTID" />
+ <xs:enumeration value="PPID" />
+ <xs:enumeration value="VPPID" />
+ <xs:enumeration value="PTHREAD_ID" />
+ <xs:enumeration value="HOSTNAME" />
+ <xs:enumeration value="IP" />
+ </xs:restriction>
+ </xs:simpleType>
+
<!-- Maps to loglevel_string char * -->
<xs:simpleType name="loglevel_string_type">
<xs:restriction base="xs:string">
</xs:all>
</xs:complexType>
+ <!-- Map to lttng_event_perf_counter_ctx -->
+ <xs:complexType name="perf_counter_context_type">
+ <xs:all>
+ <xs:element name="type" type="uint32_type" />
+ <xs:element name="config" type="uint64_type" />
+ <xs:element name="name" type="name_type" />
+ </xs:all>
+ </xs:complexType>
+
+ <!-- Map to lttng_event_context -->
+ <xs:complexType name="context_type">
+ <xs:all>
+ <xs:element name="type" type="context_type_type" />
+ <xs:element name="perf_counter_context" type="perf_counter_context_type" minOccurs="0" />
+ <!-- The success element is present only for lttng cli command add-context -->
+ <xs:element name="success" type="xs:boolean" default="false" minOccurs="0" />
+ </xs:all>
+ </xs:complexType>
+
<xs:complexType name="domains_type">
<xs:sequence>
<xs:element name="domain" type="domain_type" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
+ <xs:complexType name="contexts_type">
+ <xs:sequence>
+ <xs:element name="context" type="context_type" minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:complexType>
+
<xs:complexType name="output_type">
<xs:choice>
<xs:element name="domains" type="domains_type" minOccurs="0" />
<xs:element name="save" type="save_type" minOccurs="0" />
<xs:element name="load" type="load_type" minOccurs="0" />
<xs:element name="calibrate" type="calibrate_type" minOccurs="0" />
+ <xs:element name="contexts" type="contexts_type" minOccurs="0" />
</xs:choice>
</xs:complexType>
<xs:enumeration value="stop" />
<xs:enumeration value="destroy" />
<xs:enumeration value="calibrate" />
+ <xs:enumeration value="add-context" />
</xs:restriction>
</xs:simpleType>