@@ -549,6 +549,29 @@ static void do_change_trace_event_state(Monitor *mon, const QDict *qdict)
bool new_state = qdict_get_bool(qdict, "option");
st_change_trace_event_state(tp_name, new_state);
}
+
+static void do_trace_file(Monitor *mon, const QDict *qdict)
+{
+ const char *op = qdict_get_try_str(qdict, "op");
+ const char *arg = qdict_get_try_str(qdict, "arg");
+
+ if (!op) {
+ st_print_trace_file_status((FILE *)mon, &monitor_fprintf);
+ } else if (!strcmp(op, "on")) {
+ st_set_trace_file_enabled(true);
+ } else if (!strcmp(op, "off")) {
+ st_set_trace_file_enabled(false);
+ } else if (!strcmp(op, "flush")) {
+ st_flush_trace_buffer();
+ } else if (!strcmp(op, "set")) {
+ if (arg) {
+ st_set_trace_file(arg);
+ }
+ } else {
+ monitor_printf(mon, "unexpected argument \"%s\"\n", op);
+ help_cmd(mon, "trace-file");
+ }
+}
#endif
static void user_monitor_complete(void *opaque, QObject *ret_data)
@@ -273,6 +273,20 @@ STEXI
@findex trace-event
changes status of a trace event
ETEXI
+
+ {
+ .name = "trace-file",
+ .args_type = "op:s?,arg:F?",
+ .params = "on|off|flush|set [arg]",
+ .help = "open, close, or flush trace file, or set a new file name",
+ .mhandler.cmd = do_trace_file,
+ },
+
+STEXI
+@item trace-file on|off|flush
+@findex trace-file
+Open, close, or flush the trace file. If no argument is given, the status of the trace file is displayed.
+ETEXI
#endif
{
@@ -41,6 +41,14 @@ enum {
static TraceRecord trace_buf[TRACE_BUF_LEN];
static unsigned int trace_idx;
static FILE *trace_fp;
+static char *trace_file_name = NULL;
+static bool trace_file_enabled = false;
+
+void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
+{
+ stream_printf(stream, "Trace file \"%s\" %s.\n",
+ trace_file_name, trace_file_enabled ? "on" : "off");
+}
static bool write_header(FILE *fp)
{
@@ -53,38 +61,81 @@ static bool write_header(FILE *fp)
return fwrite(&header, sizeof header, 1, fp) == 1;
}
-static bool open_trace_file(void)
+/**
+ * set_trace_file : To set the name of a trace file.
+ * @file : pointer to the name to be set.
+ * If NULL, set to the default name-<pid> set at config time.
+ */
+bool st_set_trace_file(const char *file)
{
- char *filename;
+ st_set_trace_file_enabled(false);
- if (asprintf(&filename, CONFIG_TRACE_FILE, getpid()) < 0) {
- return false;
- }
+ free(trace_file_name);
- trace_fp = fopen(filename, "w");
- free(filename);
- if (!trace_fp) {
- return false;
+ if (!file) {
+ if (asprintf(&trace_file_name, CONFIG_TRACE_FILE, getpid()) < 0) {
+ trace_file_name = NULL;
+ return false;
+ }
+ } else {
+ if (asprintf(&trace_file_name, "%s", file) < 0) {
+ trace_file_name = NULL;
+ return false;
+ }
}
- return write_header(trace_fp);
+
+ st_set_trace_file_enabled(true);
+ return true;
}
-static void flush_trace_buffer(void)
+static void flush_trace_file(void)
{
+ /* If the trace file is not open yet, open it now */
if (!trace_fp) {
- if (open_trace_file()) {
- atexit(flush_trace_buffer);
+ trace_fp = fopen(trace_file_name, "w");
+ if (!trace_fp) {
+ /* Avoid repeatedly trying to open file on failure */
+ trace_file_enabled = false;
+ return;
}
+ write_header(trace_fp);
+ atexit(st_flush_trace_buffer);
}
+
if (trace_fp) {
size_t unused; /* for when fwrite(3) is declared warn_unused_result */
unused = fwrite(trace_buf, trace_idx * sizeof(trace_buf[0]), 1, trace_fp);
}
+}
+
+void st_flush_trace_buffer(void)
+{
+ if (trace_file_enabled) {
+ flush_trace_file();
+ }
/* Discard written trace records */
trace_idx = 0;
}
+void st_set_trace_file_enabled(bool enable)
+{
+ if (enable == trace_file_enabled) {
+ return; /* no change */
+ }
+
+ /* Flush/discard trace buffer */
+ st_flush_trace_buffer();
+
+ /* To disable, close trace file */
+ if (!enable) {
+ fclose(trace_fp);
+ trace_fp = NULL;
+ }
+
+ trace_file_enabled = enable;
+}
+
static void trace(TraceEventID event, unsigned long x1,
unsigned long x2, unsigned long x3,
unsigned long x4, unsigned long x5)
@@ -111,7 +162,7 @@ static void trace(TraceEventID event, unsigned long x1,
rec->x5 = x5;
if (++trace_idx == TRACE_BUF_LEN) {
- flush_trace_buffer();
+ st_flush_trace_buffer();
}
}
@@ -31,5 +31,9 @@ void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t
void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
void st_change_trace_event_state(const char *tname, bool tstate);
+void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
+void st_set_trace_file_enabled(bool enable);
+bool st_set_trace_file(const char *file);
+void st_flush_trace_buffer(void);
#endif /* SIMPLETRACE_H */