blob: a221a3f70310bc72344f83b55689bf6e9b7f289b [file] [log] [blame]
Stefan Hajnoczi26f72272010-05-22 19:24:51 +01001/*
2 * Simple trace backend
3 *
4 * Copyright IBM, Corp. 2010
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2. See
7 * the COPYING file in the top-level directory.
8 *
9 */
10
Peter Maydelld38ea872016-01-29 17:50:05 +000011#include "qemu/osdep.h"
Stefan Hajnoczi85aff152011-09-05 08:30:17 +010012#ifndef _WIN32
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +000013#include <pthread.h>
Stefan Hajnoczi85aff152011-09-05 08:30:17 +010014#endif
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010015#include "qemu/timer.h"
Lluíse4858972011-08-31 20:31:03 +020016#include "trace/control.h"
Lluís Vilanovab618c282014-01-14 16:52:55 +010017#include "trace/simple.h"
Stefan Hajnoczi26f72272010-05-22 19:24:51 +010018
Daniel P. Berrangeef4c9fc2016-10-04 14:35:49 +010019/** Trace file header event ID, picked to avoid conflict with real event IDs */
20#define HEADER_EVENT_ID (~(uint64_t)0)
Stefan Hajnoczi26f72272010-05-22 19:24:51 +010021
22/** Trace file magic number */
23#define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
24
25/** Trace file version number, bump if format changes */
Daniel P. Berrange7f1b5882016-10-04 14:35:50 +010026#define HEADER_VERSION 4
Stefan Hajnoczi26f72272010-05-22 19:24:51 +010027
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +000028/** Records were dropped event ID */
29#define DROPPED_EVENT_ID (~(uint64_t)0 - 1)
30
31/** Trace record is valid */
32#define TRACE_RECORD_VALID ((uint64_t)1 << 63)
33
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +000034/*
35 * Trace records are written out by a dedicated thread. The thread waits for
36 * records to become available, writes them out, and then waits again.
37 */
Michael Tokarev86946a22014-05-08 12:30:46 +040038static CompatGMutex trace_lock;
39static CompatGCond trace_available_cond;
40static CompatGCond trace_empty_cond;
Stefan Hajnoczi4a0e6712013-02-12 14:34:05 +010041
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +000042static bool trace_available;
43static bool trace_writeout_enabled;
44
Harsh Prateek Bora62bab732012-07-18 15:15:59 +053045enum {
46 TRACE_BUF_LEN = 4096 * 64,
47 TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4,
48};
49
50uint8_t trace_buf[TRACE_BUF_LEN];
Stefan Hajnoczi30d94082013-02-12 14:34:04 +010051static volatile gint trace_idx;
Harsh Prateek Bora62bab732012-07-18 15:15:59 +053052static unsigned int writeout_idx;
Stefan Hajnoczi30d94082013-02-12 14:34:04 +010053static volatile gint dropped_events;
Stefan Hajnoczi26896cb2014-05-07 19:24:10 +020054static uint32_t trace_pid;
Stefan Hajnoczi26f72272010-05-22 19:24:51 +010055static FILE *trace_fp;
Stefan Weil4552e412012-08-13 21:51:16 +020056static char *trace_file_name;
Stefan Hajnoczi26f72272010-05-22 19:24:51 +010057
Daniel P. Berrange7f1b5882016-10-04 14:35:50 +010058#define TRACE_RECORD_TYPE_MAPPING 0
59#define TRACE_RECORD_TYPE_EVENT 1
60
Harsh Prateek Bora62bab732012-07-18 15:15:59 +053061/* * Trace buffer entry */
62typedef struct {
Daniel P. Berrangeef4c9fc2016-10-04 14:35:49 +010063 uint64_t event; /* event ID value */
Harsh Prateek Bora62bab732012-07-18 15:15:59 +053064 uint64_t timestamp_ns;
65 uint32_t length; /* in bytes */
Stefan Hajnoczi26896cb2014-05-07 19:24:10 +020066 uint32_t pid;
Markus Armbrusterfb3a5082013-01-25 16:43:37 +010067 uint64_t arguments[];
Harsh Prateek Bora62bab732012-07-18 15:15:59 +053068} TraceRecord;
69
70typedef struct {
71 uint64_t header_event_id; /* HEADER_EVENT_ID */
72 uint64_t header_magic; /* HEADER_MAGIC */
73 uint64_t header_version; /* HEADER_VERSION */
Harsh Prateek Bora8ae601e2012-07-20 18:52:12 +053074} TraceLogHeader;
Harsh Prateek Bora62bab732012-07-18 15:15:59 +053075
76
77static void read_from_buffer(unsigned int idx, void *dataptr, size_t size);
78static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size);
79
80static void clear_buffer_range(unsigned int idx, size_t len)
81{
82 uint32_t num = 0;
83 while (num < len) {
84 if (idx >= TRACE_BUF_LEN) {
85 idx = idx % TRACE_BUF_LEN;
86 }
87 trace_buf[idx++] = 0;
88 num++;
89 }
90}
Stefan Hajnoczic5ceb522010-07-13 09:26:33 +010091/**
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +000092 * Read a trace record from the trace buffer
93 *
94 * @idx Trace buffer index
95 * @record Trace record to fill
96 *
97 * Returns false if the record is not valid.
Stefan Hajnoczic5ceb522010-07-13 09:26:33 +010098 */
Harsh Prateek Bora62bab732012-07-18 15:15:59 +053099static bool get_trace_record(unsigned int idx, TraceRecord **recordptr)
Prerna Saxena9410b562010-07-13 09:26:32 +0100100{
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530101 uint64_t event_flag = 0;
102 TraceRecord record;
103 /* read the event flag to see if its a valid record */
104 read_from_buffer(idx, &record, sizeof(event_flag));
105
106 if (!(record.event & TRACE_RECORD_VALID)) {
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000107 return false;
Prerna Saxena9410b562010-07-13 09:26:32 +0100108 }
109
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530110 smp_rmb(); /* read memory barrier before accessing record */
111 /* read the record header to know record length */
112 read_from_buffer(idx, &record, sizeof(TraceRecord));
Stefan Weilcb8d4c82016-03-23 15:59:57 +0100113 *recordptr = malloc(record.length); /* don't use g_malloc, can deadlock when traced */
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530114 /* make a copy of record to avoid being overwritten */
115 read_from_buffer(idx, *recordptr, record.length);
116 smp_rmb(); /* memory barrier before clearing valid flag */
117 (*recordptr)->event &= ~TRACE_RECORD_VALID;
118 /* clear the trace buffer range for consumed record otherwise any byte
119 * with its MSB set may be considered as a valid event id when the writer
120 * thread crosses this range of buffer again.
121 */
122 clear_buffer_range(idx, record.length);
Stefan Hajnoczic5ceb522010-07-13 09:26:33 +0100123 return true;
Prerna Saxena9410b562010-07-13 09:26:32 +0100124}
125
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000126/**
127 * Kick writeout thread
128 *
129 * @wait Whether to wait for writeout thread to complete
130 */
131static void flush_trace_file(bool wait)
Stefan Hajnoczi26f72272010-05-22 19:24:51 +0100132{
Michael Tokarev86946a22014-05-08 12:30:46 +0400133 g_mutex_lock(&trace_lock);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000134 trace_available = true;
Michael Tokarev86946a22014-05-08 12:30:46 +0400135 g_cond_signal(&trace_available_cond);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000136
137 if (wait) {
Michael Tokarev86946a22014-05-08 12:30:46 +0400138 g_cond_wait(&trace_empty_cond, &trace_lock);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000139 }
140
Michael Tokarev86946a22014-05-08 12:30:46 +0400141 g_mutex_unlock(&trace_lock);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000142}
143
144static void wait_for_trace_records_available(void)
145{
Michael Tokarev86946a22014-05-08 12:30:46 +0400146 g_mutex_lock(&trace_lock);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000147 while (!(trace_available && trace_writeout_enabled)) {
Michael Tokarev86946a22014-05-08 12:30:46 +0400148 g_cond_signal(&trace_empty_cond);
149 g_cond_wait(&trace_available_cond, &trace_lock);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000150 }
151 trace_available = false;
Michael Tokarev86946a22014-05-08 12:30:46 +0400152 g_mutex_unlock(&trace_lock);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000153}
154
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100155static gpointer writeout_thread(gpointer opaque)
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000156{
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530157 TraceRecord *recordptr;
158 union {
159 TraceRecord rec;
160 uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)];
161 } dropped;
162 unsigned int idx = 0;
Markus Armbrusterfb3a5082013-01-25 16:43:37 +0100163 int dropped_count;
Blue Swirl0caf4482011-07-23 21:21:14 +0000164 size_t unused __attribute__ ((unused));
Daniel P. Berrange7f1b5882016-10-04 14:35:50 +0100165 uint64_t type = TRACE_RECORD_TYPE_EVENT;
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000166
167 for (;;) {
168 wait_for_trace_records_available();
169
Markus Armbrustere722d702013-01-25 16:43:38 +0100170 if (g_atomic_int_get(&dropped_events)) {
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530171 dropped.rec.event = DROPPED_EVENT_ID,
172 dropped.rec.timestamp_ns = get_clock();
Markus Armbrusterfb3a5082013-01-25 16:43:37 +0100173 dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t),
Stefan Hajnoczi26896cb2014-05-07 19:24:10 +0200174 dropped.rec.pid = trace_pid;
Markus Armbrusterb6b2c962013-01-25 16:43:39 +0100175 do {
Markus Armbrustere722d702013-01-25 16:43:38 +0100176 dropped_count = g_atomic_int_get(&dropped_events);
Markus Armbrusterb6b2c962013-01-25 16:43:39 +0100177 } while (!g_atomic_int_compare_and_exchange(&dropped_events,
178 dropped_count, 0));
Markus Armbrusterfb3a5082013-01-25 16:43:37 +0100179 dropped.rec.arguments[0] = dropped_count;
Daniel P. Berrange7f1b5882016-10-04 14:35:50 +0100180 unused = fwrite(&type, sizeof(type), 1, trace_fp);
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530181 unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp);
Stefan Hajnoczic5ceb522010-07-13 09:26:33 +0100182 }
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000183
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530184 while (get_trace_record(idx, &recordptr)) {
Daniel P. Berrange7f1b5882016-10-04 14:35:50 +0100185 unused = fwrite(&type, sizeof(type), 1, trace_fp);
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530186 unused = fwrite(recordptr, recordptr->length, 1, trace_fp);
187 writeout_idx += recordptr->length;
Stefan Weilcb8d4c82016-03-23 15:59:57 +0100188 free(recordptr); /* don't use g_free, can deadlock when traced */
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530189 idx = writeout_idx % TRACE_BUF_LEN;
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000190 }
191
192 fflush(trace_fp);
Stefan Hajnoczi26f72272010-05-22 19:24:51 +0100193 }
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000194 return NULL;
Stefan Hajnoczi26f72272010-05-22 19:24:51 +0100195}
196
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530197void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val)
Stefan Hajnoczi26f72272010-05-22 19:24:51 +0100198{
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530199 rec->rec_off = write_to_buffer(rec->rec_off, &val, sizeof(uint64_t));
200}
Stefan Hajnoczi26f72272010-05-22 19:24:51 +0100201
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530202void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen)
203{
204 /* Write string length first */
205 rec->rec_off = write_to_buffer(rec->rec_off, &slen, sizeof(slen));
206 /* Write actual string now */
207 rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen);
208}
209
Daniel P. Berrangeef4c9fc2016-10-04 14:35:49 +0100210int trace_record_start(TraceBufferRecord *rec, uint32_t event, size_t datasize)
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530211{
212 unsigned int idx, rec_off, old_idx, new_idx;
213 uint32_t rec_len = sizeof(TraceRecord) + datasize;
Lluís Vilanova60481e22013-03-05 14:47:55 +0100214 uint64_t event_u64 = event;
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530215 uint64_t timestamp_ns = get_clock();
216
Markus Armbrusterb6b2c962013-01-25 16:43:39 +0100217 do {
Markus Armbrustere722d702013-01-25 16:43:38 +0100218 old_idx = g_atomic_int_get(&trace_idx);
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530219 smp_rmb();
220 new_idx = old_idx + rec_len;
221
222 if (new_idx - writeout_idx > TRACE_BUF_LEN) {
223 /* Trace Buffer Full, Event dropped ! */
Markus Armbrusterfb3a5082013-01-25 16:43:37 +0100224 g_atomic_int_inc(&dropped_events);
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530225 return -ENOSPC;
226 }
Markus Armbrusterb6b2c962013-01-25 16:43:39 +0100227 } while (!g_atomic_int_compare_and_exchange(&trace_idx, old_idx, new_idx));
Prerna Saxena22890ab2010-06-24 17:04:53 +0530228
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530229 idx = old_idx % TRACE_BUF_LEN;
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000230
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530231 rec_off = idx;
Lluís Vilanova60481e22013-03-05 14:47:55 +0100232 rec_off = write_to_buffer(rec_off, &event_u64, sizeof(event_u64));
Harsh Prateek Bora83d35d32012-07-20 18:52:13 +0530233 rec_off = write_to_buffer(rec_off, &timestamp_ns, sizeof(timestamp_ns));
234 rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len));
Stefan Hajnoczi26896cb2014-05-07 19:24:10 +0200235 rec_off = write_to_buffer(rec_off, &trace_pid, sizeof(trace_pid));
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530236
237 rec->tbuf_idx = idx;
238 rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN;
239 return 0;
240}
241
242static void read_from_buffer(unsigned int idx, void *dataptr, size_t size)
243{
244 uint8_t *data_ptr = dataptr;
245 uint32_t x = 0;
246 while (x < size) {
247 if (idx >= TRACE_BUF_LEN) {
248 idx = idx % TRACE_BUF_LEN;
249 }
250 data_ptr[x++] = trace_buf[idx++];
251 }
252}
253
254static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size)
255{
256 uint8_t *data_ptr = dataptr;
257 uint32_t x = 0;
258 while (x < size) {
259 if (idx >= TRACE_BUF_LEN) {
260 idx = idx % TRACE_BUF_LEN;
261 }
262 trace_buf[idx++] = data_ptr[x++];
263 }
264 return idx; /* most callers wants to know where to write next */
265}
266
267void trace_record_finish(TraceBufferRecord *rec)
268{
Harsh Prateek Boradb8894f2012-07-20 18:52:15 +0530269 TraceRecord record;
270 read_from_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord));
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530271 smp_wmb(); /* write barrier before marking as valid */
Harsh Prateek Boradb8894f2012-07-20 18:52:15 +0530272 record.event |= TRACE_RECORD_VALID;
273 write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord));
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530274
Stefan Hajnoczi30d94082013-02-12 14:34:04 +0100275 if (((unsigned int)g_atomic_int_get(&trace_idx) - writeout_idx)
Markus Armbrustere722d702013-01-25 16:43:38 +0100276 > TRACE_BUF_FLUSH_THRESHOLD) {
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000277 flush_trace_file(false);
Stefan Hajnoczi26f72272010-05-22 19:24:51 +0100278 }
279}
280
Daniel P. Berrange7f1b5882016-10-04 14:35:50 +0100281static int st_write_event_mapping(void)
282{
283 uint64_t type = TRACE_RECORD_TYPE_MAPPING;
284 TraceEventIter iter;
285 TraceEvent *ev;
286
287 trace_event_iter_init(&iter, NULL);
288 while ((ev = trace_event_iter_next(&iter)) != NULL) {
289 uint64_t id = trace_event_get_id(ev);
290 const char *name = trace_event_get_name(ev);
291 uint32_t len = strlen(name);
292 if (fwrite(&type, sizeof(type), 1, trace_fp) != 1 ||
293 fwrite(&id, sizeof(id), 1, trace_fp) != 1 ||
294 fwrite(&len, sizeof(len), 1, trace_fp) != 1 ||
295 fwrite(name, len, 1, trace_fp) != 1) {
296 return -1;
297 }
298 }
299
300 return 0;
301}
302
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000303void st_set_trace_file_enabled(bool enable)
Stefan Hajnoczi26f72272010-05-22 19:24:51 +0100304{
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000305 if (enable == !!trace_fp) {
306 return; /* no change */
307 }
308
309 /* Halt trace writeout */
310 flush_trace_file(true);
311 trace_writeout_enabled = false;
312 flush_trace_file(true);
313
314 if (enable) {
Harsh Prateek Bora8ae601e2012-07-20 18:52:12 +0530315 static const TraceLogHeader header = {
Harsh Prateek Bora62bab732012-07-18 15:15:59 +0530316 .header_event_id = HEADER_EVENT_ID,
317 .header_magic = HEADER_MAGIC,
318 /* Older log readers will check for version at next location */
319 .header_version = HEADER_VERSION,
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000320 };
321
Stefan Hajnoczi6c2a4072011-09-05 18:31:21 +0100322 trace_fp = fopen(trace_file_name, "wb");
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000323 if (!trace_fp) {
324 return;
325 }
326
Daniel P. Berrange7f1b5882016-10-04 14:35:50 +0100327 if (fwrite(&header, sizeof header, 1, trace_fp) != 1 ||
328 st_write_event_mapping() < 0) {
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000329 fclose(trace_fp);
330 trace_fp = NULL;
331 return;
332 }
333
334 /* Resume trace writeout */
335 trace_writeout_enabled = true;
336 flush_trace_file(false);
337 } else {
338 fclose(trace_fp);
339 trace_fp = NULL;
340 }
341}
342
343/**
344 * Set the name of a trace file
345 *
346 * @file The trace file name or NULL for the default name-<pid> set at
347 * config time
348 */
Paolo Bonzini41fc57e2016-01-07 16:55:24 +0300349void st_set_trace_file(const char *file)
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000350{
351 st_set_trace_file_enabled(false);
352
Stefan Weil4552e412012-08-13 21:51:16 +0200353 g_free(trace_file_name);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000354
355 if (!file) {
Stefan Weil857a0e32015-03-11 22:08:56 +0100356 /* Type cast needed for Windows where getpid() returns an int. */
357 trace_file_name = g_strdup_printf(CONFIG_TRACE_FILE, (pid_t)getpid());
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000358 } else {
Stefan Weil4552e412012-08-13 21:51:16 +0200359 trace_file_name = g_strdup_printf("%s", file);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000360 }
361
362 st_set_trace_file_enabled(true);
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000363}
364
365void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
366{
367 stream_printf(stream, "Trace file \"%s\" %s.\n",
368 trace_file_name, trace_fp ? "on" : "off");
Stefan Hajnoczi26f72272010-05-22 19:24:51 +0100369}
Prerna Saxena22890ab2010-06-24 17:04:53 +0530370
Lluísfc764102011-08-31 20:31:18 +0200371void st_flush_trace_buffer(void)
372{
373 flush_trace_file(true);
374}
375
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100376/* Helper function to create a thread with signals blocked. Use glib's
377 * portable threads since QEMU abstractions cannot be used due to reentrancy in
378 * the tracer. Also note the signal masking on POSIX hosts so that the thread
379 * does not steal signals when the rest of the program wants them blocked.
380 */
381static GThread *trace_thread_create(GThreadFunc fn)
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000382{
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100383 GThread *thread;
384#ifndef _WIN32
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000385 sigset_t set, oldset;
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000386
387 sigfillset(&set);
388 pthread_sigmask(SIG_SETMASK, &set, &oldset);
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100389#endif
Stefan Hajnoczi4a0e6712013-02-12 14:34:05 +0100390
Stefan Hajnoczi4a0e6712013-02-12 14:34:05 +0100391 thread = g_thread_new("trace-thread", fn, NULL);
Stefan Hajnoczi4a0e6712013-02-12 14:34:05 +0100392
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100393#ifndef _WIN32
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000394 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100395#endif
Stefan Hajnoczi0b5538c2011-02-26 18:38:39 +0000396
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100397 return thread;
398}
399
Paolo Bonzini41fc57e2016-01-07 16:55:24 +0300400bool st_init(void)
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100401{
402 GThread *thread;
403
Stefan Hajnoczi26896cb2014-05-07 19:24:10 +0200404 trace_pid = getpid();
405
Stefan Hajnoczi85aff152011-09-05 08:30:17 +0100406 thread = trace_thread_create(writeout_thread);
407 if (!thread) {
408 fprintf(stderr, "warning: unable to initialize simple trace backend\n");
409 return false;
410 }
411
412 atexit(st_flush_trace_buffer);
Stefan Hajnoczi31d3c9b2011-03-13 20:14:30 +0000413 return true;
Prerna Saxena22890ab2010-06-24 17:04:53 +0530414}