summaryrefslogtreecommitdiffstats
path: root/src/tracefs-marker.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tracefs-marker.c')
-rw-r--r--src/tracefs-marker.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/tracefs-marker.c b/src/tracefs-marker.c
new file mode 100644
index 0000000..61a07ab
--- /dev/null
+++ b/src/tracefs-marker.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * Copyright (C) 2021, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include "tracefs.h"
+#include "tracefs-local.h"
+
+/* File descriptors for Top level trace markers */
+static int ftrace_marker_fd = -1;
+static int ftrace_marker_raw_fd = -1;
+
+static inline int *get_marker_fd(struct tracefs_instance *instance, bool raw)
+{
+ if (raw)
+ return instance ? &instance->ftrace_marker_raw_fd : &ftrace_marker_raw_fd;
+ return instance ? &instance->ftrace_marker_fd : &ftrace_marker_fd;
+}
+
+static int marker_init(struct tracefs_instance *instance, bool raw)
+{
+ const char *file = raw ? "trace_marker_raw" : "trace_marker";
+ pthread_mutex_t *lock = trace_get_lock(instance);
+ int *fd = get_marker_fd(instance, raw);
+ int ret;
+
+ if (*fd >= 0)
+ return 0;
+
+ /*
+ * The mutex is only to hold the integrity of the file descriptor
+ * to prevent opening it more than once, or closing the same
+ * file descriptor more than once. It does not protect against
+ * one thread closing the file descriptor and another thread
+ * writing to it. That is up to the application to prevent
+ * from happening.
+ */
+ pthread_mutex_lock(lock);
+ /* The file could have been opened since we taken the lock */
+ if (*fd < 0)
+ *fd = tracefs_instance_file_open(instance, file, O_WRONLY | O_CLOEXEC);
+
+ ret = *fd < 0 ? -1 : 0;
+ pthread_mutex_unlock(lock);
+
+ return ret;
+}
+
+static void marker_close(struct tracefs_instance *instance, bool raw)
+{
+ pthread_mutex_t *lock = trace_get_lock(instance);
+ int *fd = get_marker_fd(instance, raw);
+
+ pthread_mutex_lock(lock);
+ if (*fd >= 0) {
+ close(*fd);
+ *fd = -1;
+ }
+ pthread_mutex_unlock(lock);
+}
+
+static int marker_write(struct tracefs_instance *instance, bool raw, void *data, int len)
+{
+ int *fd = get_marker_fd(instance, raw);
+ int ret;
+
+ /*
+ * The lock does not need to be taken for writes. As a write
+ * does not modify the file descriptor. It's up to the application
+ * to prevent it from being closed if another thread is doing a write.
+ */
+ if (!data || len < 1)
+ return -1;
+ if (*fd < 0) {
+ ret = marker_init(instance, raw);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = write(*fd, data, len);
+
+ return ret == len ? 0 : -1;
+}
+
+/**
+ * tracefs_print_init - Open trace marker of selected instance for writing
+ * @instance: ftrace instance, can be NULL for top tracing instance.
+ *
+ * Returns 0 if the trace marker is opened successfully, or -1 in case of an error
+ */
+int tracefs_print_init(struct tracefs_instance *instance)
+{
+ return marker_init(instance, false);
+}
+
+/**
+ * tracefs_vprintf - Write a formatted string in the trace marker
+ * @instance: ftrace instance, can be NULL for top tracing instance.
+ * @fmt: pritnf formatted string
+ * @ap: list of arguments for the formatted string
+ *
+ * If the trace marker of the desired instance is not open already,
+ * this API will open it for writing. It will stay open until
+ * tracefs_print_close() is called.
+ *
+ * Returns 0 if the string is written correctly, or -1 in case of an error
+ */
+int tracefs_vprintf(struct tracefs_instance *instance, const char *fmt, va_list ap)
+{
+ char *str = NULL;
+ int ret;
+
+ ret = vasprintf(&str, fmt, ap);
+ if (ret < 0)
+ return ret;
+ ret = marker_write(instance, false, str, strlen(str));
+ free(str);
+
+ return ret;
+}
+
+/**
+ * tracefs_printf - Write a formatted string in the trace marker
+ * @instance: ftrace instance, can be NULL for top tracing instance.
+ * @fmt: pritnf formatted string with variable arguments ...
+ *
+ * If the trace marker of the desired instance is not open already,
+ * this API will open it for writing. It will stay open until
+ * tracefs_print_close() is called.
+ *
+ * Returns 0 if the string is written correctly, or -1 in case of an error
+ */
+int tracefs_printf(struct tracefs_instance *instance, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = tracefs_vprintf(instance, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/**
+ * tracefs_print_close - Close trace marker of selected instance
+ * @instance: ftrace instance, can be NULL for top tracing instance.
+ *
+ * Closes the trace marker, previously opened with any of the other tracefs_print APIs
+ */
+void tracefs_print_close(struct tracefs_instance *instance)
+{
+ marker_close(instance, false);
+}
+
+/**
+ * tracefs_binary_init - Open raw trace marker of selected instance for writing
+ * @instance: ftrace instance, can be NULL for top tracing instance.
+ *
+ * Returns 0 if the raw trace marker is opened successfully, or -1 in case of an error
+ */
+int tracefs_binary_init(struct tracefs_instance *instance)
+{
+ return marker_init(instance, true);
+}
+
+/**
+ * tracefs_binary_write - Write binary data in the raw trace marker
+ * @instance: ftrace instance, can be NULL for top tracing instance.
+ * @data: binary data, that is going to be written in the trace marker
+ * @len: length of the @data
+ *
+ * If the raw trace marker of the desired instance is not open already,
+ * this API will open it for writing. It will stay open until
+ * tracefs_binary_close() is called.
+ *
+ * Returns 0 if the data is written correctly, or -1 in case of an error
+ */
+int tracefs_binary_write(struct tracefs_instance *instance, void *data, int len)
+{
+ return marker_write(instance, true, data, len);
+}
+
+/**
+ * tracefs_binary_close - Close raw trace marker of selected instance
+ * @instance: ftrace instance, can be NULL for top tracing instance.
+ *
+ * Closes the raw trace marker, previously opened with any of the other tracefs_binary APIs
+ */
+void tracefs_binary_close(struct tracefs_instance *instance)
+{
+ marker_close(instance, true);
+}