aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-09-22 10:29:46 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2011-09-22 10:29:46 -0500
commitbea09f657f95219cc76f90b7eeaec4de77ab664e (patch)
tree4edb0ef10a669cac6d1506086d983c3d8d4eb2ae
parent9ba2a054db309646946d7e01f87693b09a6bdb11 (diff)
parent4b710a3cd410eb4eb39fbad2e38efe82c502250e (diff)
downloadqemu-bea09f657f95219cc76f90b7eeaec4de77ab664e.zip
qemu-bea09f657f95219cc76f90b7eeaec4de77ab664e.tar.gz
qemu-bea09f657f95219cc76f90b7eeaec4de77ab664e.tar.bz2
Merge remote-tracking branch 'stefanha/tracing' into staging
-rw-r--r--MAINTAINERS6
-rw-r--r--docs/tracing.txt24
-rw-r--r--trace/simple.c76
3 files changed, 67 insertions, 39 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 72b2099..7c5ea87 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -459,6 +459,12 @@ S: Maintained
F: slirp/
T: git://git.kiszka.org/qemu.git queues/slirp
+Tracing
+M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+S: Maintained
+F: trace/
+T: git://repo.or.cz/qemu/stefanha.git tracing
+
Usermode Emulation
------------------
BSD user
diff --git a/docs/tracing.txt b/docs/tracing.txt
index d0171aa..95ca16c 100644
--- a/docs/tracing.txt
+++ b/docs/tracing.txt
@@ -31,8 +31,8 @@ There is a set of static trace events declared in the "trace-events" source
file. Each trace event declaration names the event, its arguments, and the
format string which can be used for pretty-printing:
- qemu_malloc(size_t size, void *ptr) "size %zu ptr %p"
- qemu_free(void *ptr) "ptr %p"
+ qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p"
+ qemu_vfree(void *ptr) "ptr %p"
The "trace-events" file is processed by the "tracetool" script during build to
generate code for the trace events. Trace events are invoked directly from
@@ -40,14 +40,16 @@ source code like this:
#include "trace.h" /* needed for trace event prototype */
- void *qemu_malloc(size_t size)
+ void *qemu_vmalloc(size_t size)
{
void *ptr;
- if (!size && !allow_zero_malloc()) {
- abort();
+ size_t align = QEMU_VMALLOC_ALIGN;
+
+ if (size < align) {
+ align = getpagesize();
}
- ptr = oom_check(malloc(size ? size : 1));
- trace_qemu_malloc(size, ptr); /* <-- trace event */
+ ptr = qemu_memalign(align, size);
+ trace_qemu_vmalloc(size, ptr);
return ptr;
}
@@ -70,11 +72,6 @@ Trace events should use types as follows:
cannot include all user-defined struct declarations and it is therefore
necessary to use void * for pointers to structs.
- Pointers (including char *) cannot be dereferenced easily (or at all) in
- some trace backends. If pointers are used, ensure they are meaningful by
- themselves and do not assume the data they point to will be traced. Do
- not pass in string arguments.
-
* For everything else, use primitive scalar types (char, int, long) with the
appropriate signedness.
@@ -182,6 +179,9 @@ source tree. It may not be as powerful as platform-specific or third-party
trace backends but it is portable. This is the recommended trace backend
unless you have specific needs for more advanced backends.
+The "simple" backend currently does not capture string arguments, it simply
+records the char* pointer value instead of the string that is pointed to.
+
==== Monitor commands ====
* info trace
diff --git a/trace/simple.c b/trace/simple.c
index a609368..b639dda 100644
--- a/trace/simple.c
+++ b/trace/simple.c
@@ -12,8 +12,10 @@
#include <stdint.h>
#include <stdio.h>
#include <time.h>
+#ifndef _WIN32
#include <signal.h>
#include <pthread.h>
+#endif
#include "qemu-timer.h"
#include "trace.h"
#include "trace/control.h"
@@ -54,9 +56,9 @@ enum {
* Trace records are written out by a dedicated thread. The thread waits for
* records to become available, writes them out, and then waits again.
*/
-static pthread_mutex_t trace_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t trace_available_cond = PTHREAD_COND_INITIALIZER;
-static pthread_cond_t trace_empty_cond = PTHREAD_COND_INITIALIZER;
+static GStaticMutex trace_lock = G_STATIC_MUTEX_INIT;
+static GCond *trace_available_cond;
+static GCond *trace_empty_cond;
static bool trace_available;
static bool trace_writeout_enabled;
@@ -93,29 +95,30 @@ static bool get_trace_record(unsigned int idx, TraceRecord *record)
*/
static void flush_trace_file(bool wait)
{
- pthread_mutex_lock(&trace_lock);
+ g_static_mutex_lock(&trace_lock);
trace_available = true;
- pthread_cond_signal(&trace_available_cond);
+ g_cond_signal(trace_available_cond);
if (wait) {
- pthread_cond_wait(&trace_empty_cond, &trace_lock);
+ g_cond_wait(trace_empty_cond, g_static_mutex_get_mutex(&trace_lock));
}
- pthread_mutex_unlock(&trace_lock);
+ g_static_mutex_unlock(&trace_lock);
}
static void wait_for_trace_records_available(void)
{
- pthread_mutex_lock(&trace_lock);
+ g_static_mutex_lock(&trace_lock);
while (!(trace_available && trace_writeout_enabled)) {
- pthread_cond_signal(&trace_empty_cond);
- pthread_cond_wait(&trace_available_cond, &trace_lock);
+ g_cond_signal(trace_empty_cond);
+ g_cond_wait(trace_available_cond,
+ g_static_mutex_get_mutex(&trace_lock));
}
trace_available = false;
- pthread_mutex_unlock(&trace_lock);
+ g_static_mutex_unlock(&trace_lock);
}
-static void *writeout_thread(void *opaque)
+static gpointer writeout_thread(gpointer opaque)
{
TraceRecord record;
unsigned int writeout_idx = 0;
@@ -159,7 +162,7 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
timestamp = get_clock();
- idx = __sync_fetch_and_add(&trace_idx, 1) % TRACE_BUF_LEN;
+ idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
trace_buf[idx] = (TraceRecord){
.event = event,
.timestamp_ns = timestamp,
@@ -231,7 +234,7 @@ void st_set_trace_file_enabled(bool enable)
.x1 = HEADER_VERSION,
};
- trace_fp = fopen(trace_file_name, "w");
+ trace_fp = fopen(trace_file_name, "wb");
if (!trace_fp) {
return;
}
@@ -331,28 +334,47 @@ bool trace_event_set_state(const char *name, bool state)
return false;
}
-bool trace_backend_init(const char *events, const char *file)
+/* Helper function to create a thread with signals blocked. Use glib's
+ * portable threads since QEMU abstractions cannot be used due to reentrancy in
+ * the tracer. Also note the signal masking on POSIX hosts so that the thread
+ * does not steal signals when the rest of the program wants them blocked.
+ */
+static GThread *trace_thread_create(GThreadFunc fn)
{
- pthread_t thread;
- pthread_attr_t attr;
+ GThread *thread;
+#ifndef _WIN32
sigset_t set, oldset;
- int ret;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
sigfillset(&set);
pthread_sigmask(SIG_SETMASK, &set, &oldset);
- ret = pthread_create(&thread, &attr, writeout_thread, NULL);
+#endif
+ thread = g_thread_create(writeout_thread, NULL, FALSE, NULL);
+#ifndef _WIN32
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+#endif
- if (ret != 0) {
+ return thread;
+}
+
+bool trace_backend_init(const char *events, const char *file)
+{
+ GThread *thread;
+
+ if (!g_thread_supported()) {
+ g_thread_init(NULL);
+ }
+
+ trace_available_cond = g_cond_new();
+ trace_empty_cond = g_cond_new();
+
+ thread = trace_thread_create(writeout_thread);
+ if (!thread) {
fprintf(stderr, "warning: unable to initialize simple trace backend\n");
- } else {
- atexit(st_flush_trace_buffer);
- trace_backend_init_events(events);
- st_set_trace_file(file);
+ return false;
}
+ atexit(st_flush_trace_buffer);
+ trace_backend_init_events(events);
+ st_set_trace_file(file);
return true;
}