1edb47ec4SLluís /* 2edb47ec4SLluís * Simple trace backend 3edb47ec4SLluís * 4edb47ec4SLluís * Copyright IBM, Corp. 2010 5edb47ec4SLluís * 6edb47ec4SLluís * This work is licensed under the terms of the GNU GPL, version 2. See 7edb47ec4SLluís * the COPYING file in the top-level directory. 8edb47ec4SLluís * 9edb47ec4SLluís */ 10edb47ec4SLluís 11edb47ec4SLluís #include <stdlib.h> 12edb47ec4SLluís #include <stdint.h> 13edb47ec4SLluís #include <stdio.h> 14edb47ec4SLluís #include <time.h> 1585aff158SStefan Hajnoczi #ifndef _WIN32 16edb47ec4SLluís #include <signal.h> 17edb47ec4SLluís #include <pthread.h> 1885aff158SStefan Hajnoczi #endif 191de7afc9SPaolo Bonzini #include "qemu/timer.h" 20edb47ec4SLluís #include "trace.h" 21e4858974SLluís #include "trace/control.h" 22edb47ec4SLluís 23edb47ec4SLluís /** Trace file header event ID */ 24edb47ec4SLluís #define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */ 25edb47ec4SLluís 26edb47ec4SLluís /** Trace file magic number */ 27edb47ec4SLluís #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL 28edb47ec4SLluís 29edb47ec4SLluís /** Trace file version number, bump if format changes */ 3062bab732SHarsh Prateek Bora #define HEADER_VERSION 2 31edb47ec4SLluís 32edb47ec4SLluís /** Records were dropped event ID */ 33edb47ec4SLluís #define DROPPED_EVENT_ID (~(uint64_t)0 - 1) 34edb47ec4SLluís 35edb47ec4SLluís /** Trace record is valid */ 36edb47ec4SLluís #define TRACE_RECORD_VALID ((uint64_t)1 << 63) 37edb47ec4SLluís 38edb47ec4SLluís /* 39edb47ec4SLluís * Trace records are written out by a dedicated thread. The thread waits for 40edb47ec4SLluís * records to become available, writes them out, and then waits again. 41edb47ec4SLluís */ 4285aff158SStefan Hajnoczi static GStaticMutex trace_lock = G_STATIC_MUTEX_INIT; 43*4a0e6714SStefan Hajnoczi 44*4a0e6714SStefan Hajnoczi /* g_cond_new() was deprecated in glib 2.31 but we still need to support it */ 45*4a0e6714SStefan Hajnoczi #if GLIB_CHECK_VERSION(2, 31, 0) 46*4a0e6714SStefan Hajnoczi static GCond the_trace_available_cond; 47*4a0e6714SStefan Hajnoczi static GCond the_trace_empty_cond; 48*4a0e6714SStefan Hajnoczi static GCond *trace_available_cond = &the_trace_available_cond; 49*4a0e6714SStefan Hajnoczi static GCond *trace_empty_cond = &the_trace_empty_cond; 50*4a0e6714SStefan Hajnoczi #else 5185aff158SStefan Hajnoczi static GCond *trace_available_cond; 5285aff158SStefan Hajnoczi static GCond *trace_empty_cond; 53*4a0e6714SStefan Hajnoczi #endif 54*4a0e6714SStefan Hajnoczi 55edb47ec4SLluís static bool trace_available; 56edb47ec4SLluís static bool trace_writeout_enabled; 57edb47ec4SLluís 5862bab732SHarsh Prateek Bora enum { 5962bab732SHarsh Prateek Bora TRACE_BUF_LEN = 4096 * 64, 6062bab732SHarsh Prateek Bora TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4, 6162bab732SHarsh Prateek Bora }; 6262bab732SHarsh Prateek Bora 6362bab732SHarsh Prateek Bora uint8_t trace_buf[TRACE_BUF_LEN]; 6430d94087SStefan Hajnoczi static volatile gint trace_idx; 6562bab732SHarsh Prateek Bora static unsigned int writeout_idx; 6630d94087SStefan Hajnoczi static volatile gint dropped_events; 67edb47ec4SLluís static FILE *trace_fp; 684552e410SStefan Weil static char *trace_file_name; 69edb47ec4SLluís 7062bab732SHarsh Prateek Bora /* * Trace buffer entry */ 7162bab732SHarsh Prateek Bora typedef struct { 7262bab732SHarsh Prateek Bora uint64_t event; /* TraceEventID */ 7362bab732SHarsh Prateek Bora uint64_t timestamp_ns; 7462bab732SHarsh Prateek Bora uint32_t length; /* in bytes */ 7562bab732SHarsh Prateek Bora uint32_t reserved; /* unused */ 76fb3a5085SMarkus Armbruster uint64_t arguments[]; 7762bab732SHarsh Prateek Bora } TraceRecord; 7862bab732SHarsh Prateek Bora 7962bab732SHarsh Prateek Bora typedef struct { 8062bab732SHarsh Prateek Bora uint64_t header_event_id; /* HEADER_EVENT_ID */ 8162bab732SHarsh Prateek Bora uint64_t header_magic; /* HEADER_MAGIC */ 8262bab732SHarsh Prateek Bora uint64_t header_version; /* HEADER_VERSION */ 838ae601e8SHarsh Prateek Bora } TraceLogHeader; 8462bab732SHarsh Prateek Bora 8562bab732SHarsh Prateek Bora 8662bab732SHarsh Prateek Bora static void read_from_buffer(unsigned int idx, void *dataptr, size_t size); 8762bab732SHarsh Prateek Bora static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size); 8862bab732SHarsh Prateek Bora 8962bab732SHarsh Prateek Bora static void clear_buffer_range(unsigned int idx, size_t len) 9062bab732SHarsh Prateek Bora { 9162bab732SHarsh Prateek Bora uint32_t num = 0; 9262bab732SHarsh Prateek Bora while (num < len) { 9362bab732SHarsh Prateek Bora if (idx >= TRACE_BUF_LEN) { 9462bab732SHarsh Prateek Bora idx = idx % TRACE_BUF_LEN; 9562bab732SHarsh Prateek Bora } 9662bab732SHarsh Prateek Bora trace_buf[idx++] = 0; 9762bab732SHarsh Prateek Bora num++; 9862bab732SHarsh Prateek Bora } 9962bab732SHarsh Prateek Bora } 100edb47ec4SLluís /** 101edb47ec4SLluís * Read a trace record from the trace buffer 102edb47ec4SLluís * 103edb47ec4SLluís * @idx Trace buffer index 104edb47ec4SLluís * @record Trace record to fill 105edb47ec4SLluís * 106edb47ec4SLluís * Returns false if the record is not valid. 107edb47ec4SLluís */ 10862bab732SHarsh Prateek Bora static bool get_trace_record(unsigned int idx, TraceRecord **recordptr) 109edb47ec4SLluís { 11062bab732SHarsh Prateek Bora uint64_t event_flag = 0; 11162bab732SHarsh Prateek Bora TraceRecord record; 11262bab732SHarsh Prateek Bora /* read the event flag to see if its a valid record */ 11362bab732SHarsh Prateek Bora read_from_buffer(idx, &record, sizeof(event_flag)); 11462bab732SHarsh Prateek Bora 11562bab732SHarsh Prateek Bora if (!(record.event & TRACE_RECORD_VALID)) { 116edb47ec4SLluís return false; 117edb47ec4SLluís } 118edb47ec4SLluís 11962bab732SHarsh Prateek Bora smp_rmb(); /* read memory barrier before accessing record */ 12062bab732SHarsh Prateek Bora /* read the record header to know record length */ 12162bab732SHarsh Prateek Bora read_from_buffer(idx, &record, sizeof(TraceRecord)); 12262bab732SHarsh Prateek Bora *recordptr = malloc(record.length); /* dont use g_malloc, can deadlock when traced */ 12362bab732SHarsh Prateek Bora /* make a copy of record to avoid being overwritten */ 12462bab732SHarsh Prateek Bora read_from_buffer(idx, *recordptr, record.length); 12562bab732SHarsh Prateek Bora smp_rmb(); /* memory barrier before clearing valid flag */ 12662bab732SHarsh Prateek Bora (*recordptr)->event &= ~TRACE_RECORD_VALID; 12762bab732SHarsh Prateek Bora /* clear the trace buffer range for consumed record otherwise any byte 12862bab732SHarsh Prateek Bora * with its MSB set may be considered as a valid event id when the writer 12962bab732SHarsh Prateek Bora * thread crosses this range of buffer again. 13062bab732SHarsh Prateek Bora */ 13162bab732SHarsh Prateek Bora clear_buffer_range(idx, record.length); 132edb47ec4SLluís return true; 133edb47ec4SLluís } 134edb47ec4SLluís 135edb47ec4SLluís /** 136edb47ec4SLluís * Kick writeout thread 137edb47ec4SLluís * 138edb47ec4SLluís * @wait Whether to wait for writeout thread to complete 139edb47ec4SLluís */ 140edb47ec4SLluís static void flush_trace_file(bool wait) 141edb47ec4SLluís { 14285aff158SStefan Hajnoczi g_static_mutex_lock(&trace_lock); 143edb47ec4SLluís trace_available = true; 14485aff158SStefan Hajnoczi g_cond_signal(trace_available_cond); 145edb47ec4SLluís 146edb47ec4SLluís if (wait) { 14785aff158SStefan Hajnoczi g_cond_wait(trace_empty_cond, g_static_mutex_get_mutex(&trace_lock)); 148edb47ec4SLluís } 149edb47ec4SLluís 15085aff158SStefan Hajnoczi g_static_mutex_unlock(&trace_lock); 151edb47ec4SLluís } 152edb47ec4SLluís 153edb47ec4SLluís static void wait_for_trace_records_available(void) 154edb47ec4SLluís { 15585aff158SStefan Hajnoczi g_static_mutex_lock(&trace_lock); 156edb47ec4SLluís while (!(trace_available && trace_writeout_enabled)) { 15785aff158SStefan Hajnoczi g_cond_signal(trace_empty_cond); 15885aff158SStefan Hajnoczi g_cond_wait(trace_available_cond, 15985aff158SStefan Hajnoczi g_static_mutex_get_mutex(&trace_lock)); 160edb47ec4SLluís } 161edb47ec4SLluís trace_available = false; 16285aff158SStefan Hajnoczi g_static_mutex_unlock(&trace_lock); 163edb47ec4SLluís } 164edb47ec4SLluís 16585aff158SStefan Hajnoczi static gpointer writeout_thread(gpointer opaque) 166edb47ec4SLluís { 16762bab732SHarsh Prateek Bora TraceRecord *recordptr; 16862bab732SHarsh Prateek Bora union { 16962bab732SHarsh Prateek Bora TraceRecord rec; 17062bab732SHarsh Prateek Bora uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)]; 17162bab732SHarsh Prateek Bora } dropped; 17262bab732SHarsh Prateek Bora unsigned int idx = 0; 173fb3a5085SMarkus Armbruster int dropped_count; 174edb47ec4SLluís size_t unused __attribute__ ((unused)); 175edb47ec4SLluís 176edb47ec4SLluís for (;;) { 177edb47ec4SLluís wait_for_trace_records_available(); 178edb47ec4SLluís 179e722d705SMarkus Armbruster if (g_atomic_int_get(&dropped_events)) { 18062bab732SHarsh Prateek Bora dropped.rec.event = DROPPED_EVENT_ID, 18162bab732SHarsh Prateek Bora dropped.rec.timestamp_ns = get_clock(); 182fb3a5085SMarkus Armbruster dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t), 18362bab732SHarsh Prateek Bora dropped.rec.reserved = 0; 184b6b2c962SMarkus Armbruster do { 185e722d705SMarkus Armbruster dropped_count = g_atomic_int_get(&dropped_events); 186b6b2c962SMarkus Armbruster } while (!g_atomic_int_compare_and_exchange(&dropped_events, 187b6b2c962SMarkus Armbruster dropped_count, 0)); 188fb3a5085SMarkus Armbruster dropped.rec.arguments[0] = dropped_count; 18962bab732SHarsh Prateek Bora unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); 190edb47ec4SLluís } 191edb47ec4SLluís 19262bab732SHarsh Prateek Bora while (get_trace_record(idx, &recordptr)) { 19362bab732SHarsh Prateek Bora unused = fwrite(recordptr, recordptr->length, 1, trace_fp); 19462bab732SHarsh Prateek Bora writeout_idx += recordptr->length; 19562bab732SHarsh Prateek Bora free(recordptr); /* dont use g_free, can deadlock when traced */ 196edb47ec4SLluís idx = writeout_idx % TRACE_BUF_LEN; 197edb47ec4SLluís } 198edb47ec4SLluís 199edb47ec4SLluís fflush(trace_fp); 200edb47ec4SLluís } 201edb47ec4SLluís return NULL; 202edb47ec4SLluís } 203edb47ec4SLluís 20462bab732SHarsh Prateek Bora void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val) 205edb47ec4SLluís { 20662bab732SHarsh Prateek Bora rec->rec_off = write_to_buffer(rec->rec_off, &val, sizeof(uint64_t)); 207edb47ec4SLluís } 208edb47ec4SLluís 20962bab732SHarsh Prateek Bora void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen) 21062bab732SHarsh Prateek Bora { 21162bab732SHarsh Prateek Bora /* Write string length first */ 21262bab732SHarsh Prateek Bora rec->rec_off = write_to_buffer(rec->rec_off, &slen, sizeof(slen)); 21362bab732SHarsh Prateek Bora /* Write actual string now */ 21462bab732SHarsh Prateek Bora rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen); 21562bab732SHarsh Prateek Bora } 216edb47ec4SLluís 21762bab732SHarsh Prateek Bora int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasize) 21862bab732SHarsh Prateek Bora { 21962bab732SHarsh Prateek Bora unsigned int idx, rec_off, old_idx, new_idx; 22062bab732SHarsh Prateek Bora uint32_t rec_len = sizeof(TraceRecord) + datasize; 22162bab732SHarsh Prateek Bora uint64_t timestamp_ns = get_clock(); 22262bab732SHarsh Prateek Bora 223b6b2c962SMarkus Armbruster do { 224e722d705SMarkus Armbruster old_idx = g_atomic_int_get(&trace_idx); 22562bab732SHarsh Prateek Bora smp_rmb(); 22662bab732SHarsh Prateek Bora new_idx = old_idx + rec_len; 22762bab732SHarsh Prateek Bora 22862bab732SHarsh Prateek Bora if (new_idx - writeout_idx > TRACE_BUF_LEN) { 22962bab732SHarsh Prateek Bora /* Trace Buffer Full, Event dropped ! */ 230fb3a5085SMarkus Armbruster g_atomic_int_inc(&dropped_events); 23162bab732SHarsh Prateek Bora return -ENOSPC; 23262bab732SHarsh Prateek Bora } 233b6b2c962SMarkus Armbruster } while (!g_atomic_int_compare_and_exchange(&trace_idx, old_idx, new_idx)); 23462bab732SHarsh Prateek Bora 23562bab732SHarsh Prateek Bora idx = old_idx % TRACE_BUF_LEN; 23662bab732SHarsh Prateek Bora 23762bab732SHarsh Prateek Bora rec_off = idx; 23883d35d3eSHarsh Prateek Bora rec_off = write_to_buffer(rec_off, &event, sizeof(event)); 23983d35d3eSHarsh Prateek Bora rec_off = write_to_buffer(rec_off, ×tamp_ns, sizeof(timestamp_ns)); 24083d35d3eSHarsh Prateek Bora rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len)); 24162bab732SHarsh Prateek Bora 24262bab732SHarsh Prateek Bora rec->tbuf_idx = idx; 24362bab732SHarsh Prateek Bora rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN; 24462bab732SHarsh Prateek Bora return 0; 24562bab732SHarsh Prateek Bora } 24662bab732SHarsh Prateek Bora 24762bab732SHarsh Prateek Bora static void read_from_buffer(unsigned int idx, void *dataptr, size_t size) 24862bab732SHarsh Prateek Bora { 24962bab732SHarsh Prateek Bora uint8_t *data_ptr = dataptr; 25062bab732SHarsh Prateek Bora uint32_t x = 0; 25162bab732SHarsh Prateek Bora while (x < size) { 25262bab732SHarsh Prateek Bora if (idx >= TRACE_BUF_LEN) { 25362bab732SHarsh Prateek Bora idx = idx % TRACE_BUF_LEN; 25462bab732SHarsh Prateek Bora } 25562bab732SHarsh Prateek Bora data_ptr[x++] = trace_buf[idx++]; 25662bab732SHarsh Prateek Bora } 25762bab732SHarsh Prateek Bora } 25862bab732SHarsh Prateek Bora 25962bab732SHarsh Prateek Bora static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size) 26062bab732SHarsh Prateek Bora { 26162bab732SHarsh Prateek Bora uint8_t *data_ptr = dataptr; 26262bab732SHarsh Prateek Bora uint32_t x = 0; 26362bab732SHarsh Prateek Bora while (x < size) { 26462bab732SHarsh Prateek Bora if (idx >= TRACE_BUF_LEN) { 26562bab732SHarsh Prateek Bora idx = idx % TRACE_BUF_LEN; 26662bab732SHarsh Prateek Bora } 26762bab732SHarsh Prateek Bora trace_buf[idx++] = data_ptr[x++]; 26862bab732SHarsh Prateek Bora } 26962bab732SHarsh Prateek Bora return idx; /* most callers wants to know where to write next */ 27062bab732SHarsh Prateek Bora } 27162bab732SHarsh Prateek Bora 27262bab732SHarsh Prateek Bora void trace_record_finish(TraceBufferRecord *rec) 27362bab732SHarsh Prateek Bora { 274db8894f2SHarsh Prateek Bora TraceRecord record; 275db8894f2SHarsh Prateek Bora read_from_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); 27662bab732SHarsh Prateek Bora smp_wmb(); /* write barrier before marking as valid */ 277db8894f2SHarsh Prateek Bora record.event |= TRACE_RECORD_VALID; 278db8894f2SHarsh Prateek Bora write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); 27962bab732SHarsh Prateek Bora 28030d94087SStefan Hajnoczi if (((unsigned int)g_atomic_int_get(&trace_idx) - writeout_idx) 281e722d705SMarkus Armbruster > TRACE_BUF_FLUSH_THRESHOLD) { 282edb47ec4SLluís flush_trace_file(false); 283edb47ec4SLluís } 284edb47ec4SLluís } 285edb47ec4SLluís 286edb47ec4SLluís void st_set_trace_file_enabled(bool enable) 287edb47ec4SLluís { 288edb47ec4SLluís if (enable == !!trace_fp) { 289edb47ec4SLluís return; /* no change */ 290edb47ec4SLluís } 291edb47ec4SLluís 292edb47ec4SLluís /* Halt trace writeout */ 293edb47ec4SLluís flush_trace_file(true); 294edb47ec4SLluís trace_writeout_enabled = false; 295edb47ec4SLluís flush_trace_file(true); 296edb47ec4SLluís 297edb47ec4SLluís if (enable) { 2988ae601e8SHarsh Prateek Bora static const TraceLogHeader header = { 29962bab732SHarsh Prateek Bora .header_event_id = HEADER_EVENT_ID, 30062bab732SHarsh Prateek Bora .header_magic = HEADER_MAGIC, 30162bab732SHarsh Prateek Bora /* Older log readers will check for version at next location */ 30262bab732SHarsh Prateek Bora .header_version = HEADER_VERSION, 303edb47ec4SLluís }; 304edb47ec4SLluís 3056c2a4074SStefan Hajnoczi trace_fp = fopen(trace_file_name, "wb"); 306edb47ec4SLluís if (!trace_fp) { 307edb47ec4SLluís return; 308edb47ec4SLluís } 309edb47ec4SLluís 310edb47ec4SLluís if (fwrite(&header, sizeof header, 1, trace_fp) != 1) { 311edb47ec4SLluís fclose(trace_fp); 312edb47ec4SLluís trace_fp = NULL; 313edb47ec4SLluís return; 314edb47ec4SLluís } 315edb47ec4SLluís 316edb47ec4SLluís /* Resume trace writeout */ 317edb47ec4SLluís trace_writeout_enabled = true; 318edb47ec4SLluís flush_trace_file(false); 319edb47ec4SLluís } else { 320edb47ec4SLluís fclose(trace_fp); 321edb47ec4SLluís trace_fp = NULL; 322edb47ec4SLluís } 323edb47ec4SLluís } 324edb47ec4SLluís 325edb47ec4SLluís /** 326edb47ec4SLluís * Set the name of a trace file 327edb47ec4SLluís * 328edb47ec4SLluís * @file The trace file name or NULL for the default name-<pid> set at 329edb47ec4SLluís * config time 330edb47ec4SLluís */ 331edb47ec4SLluís bool st_set_trace_file(const char *file) 332edb47ec4SLluís { 333edb47ec4SLluís st_set_trace_file_enabled(false); 334edb47ec4SLluís 3354552e410SStefan Weil g_free(trace_file_name); 336edb47ec4SLluís 337edb47ec4SLluís if (!file) { 3384552e410SStefan Weil trace_file_name = g_strdup_printf(CONFIG_TRACE_FILE, getpid()); 339edb47ec4SLluís } else { 3404552e410SStefan Weil trace_file_name = g_strdup_printf("%s", file); 341edb47ec4SLluís } 342edb47ec4SLluís 343edb47ec4SLluís st_set_trace_file_enabled(true); 344edb47ec4SLluís return true; 345edb47ec4SLluís } 346edb47ec4SLluís 347edb47ec4SLluís void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)) 348edb47ec4SLluís { 349edb47ec4SLluís stream_printf(stream, "Trace file \"%s\" %s.\n", 350edb47ec4SLluís trace_file_name, trace_fp ? "on" : "off"); 351edb47ec4SLluís } 352edb47ec4SLluís 353fc764105SLluís void st_flush_trace_buffer(void) 354fc764105SLluís { 355fc764105SLluís flush_trace_file(true); 356fc764105SLluís } 357fc764105SLluís 358fc764105SLluís void trace_print_events(FILE *stream, fprintf_function stream_printf) 359edb47ec4SLluís { 360edb47ec4SLluís unsigned int i; 361edb47ec4SLluís 362edb47ec4SLluís for (i = 0; i < NR_TRACE_EVENTS; i++) { 363edb47ec4SLluís stream_printf(stream, "%s [Event ID %u] : state %u\n", 364edb47ec4SLluís trace_list[i].tp_name, i, trace_list[i].state); 365edb47ec4SLluís } 366edb47ec4SLluís } 367edb47ec4SLluís 368fc764105SLluís bool trace_event_set_state(const char *name, bool state) 369edb47ec4SLluís { 370edb47ec4SLluís unsigned int i; 371454e202dSMark Wu unsigned int len; 372454e202dSMark Wu bool wildcard = false; 373454e202dSMark Wu bool matched = false; 374edb47ec4SLluís 375454e202dSMark Wu len = strlen(name); 376454e202dSMark Wu if (len > 0 && name[len - 1] == '*') { 377454e202dSMark Wu wildcard = true; 378454e202dSMark Wu len -= 1; 379454e202dSMark Wu } 380edb47ec4SLluís for (i = 0; i < NR_TRACE_EVENTS; i++) { 381454e202dSMark Wu if (wildcard) { 382454e202dSMark Wu if (!strncmp(trace_list[i].tp_name, name, len)) { 383454e202dSMark Wu trace_list[i].state = state; 384454e202dSMark Wu matched = true; 385454e202dSMark Wu } 386454e202dSMark Wu continue; 387454e202dSMark Wu } 388edb47ec4SLluís if (!strcmp(trace_list[i].tp_name, name)) { 389fc764105SLluís trace_list[i].state = state; 390edb47ec4SLluís return true; 391edb47ec4SLluís } 392edb47ec4SLluís } 393454e202dSMark Wu return matched; 394edb47ec4SLluís } 395edb47ec4SLluís 39685aff158SStefan Hajnoczi /* Helper function to create a thread with signals blocked. Use glib's 39785aff158SStefan Hajnoczi * portable threads since QEMU abstractions cannot be used due to reentrancy in 39885aff158SStefan Hajnoczi * the tracer. Also note the signal masking on POSIX hosts so that the thread 39985aff158SStefan Hajnoczi * does not steal signals when the rest of the program wants them blocked. 40085aff158SStefan Hajnoczi */ 40185aff158SStefan Hajnoczi static GThread *trace_thread_create(GThreadFunc fn) 402edb47ec4SLluís { 40385aff158SStefan Hajnoczi GThread *thread; 40485aff158SStefan Hajnoczi #ifndef _WIN32 405edb47ec4SLluís sigset_t set, oldset; 406edb47ec4SLluís 407edb47ec4SLluís sigfillset(&set); 408edb47ec4SLluís pthread_sigmask(SIG_SETMASK, &set, &oldset); 40985aff158SStefan Hajnoczi #endif 410*4a0e6714SStefan Hajnoczi 411*4a0e6714SStefan Hajnoczi #if GLIB_CHECK_VERSION(2, 31, 0) 412*4a0e6714SStefan Hajnoczi thread = g_thread_new("trace-thread", fn, NULL); 413*4a0e6714SStefan Hajnoczi #else 414db3bf869SJun Koi thread = g_thread_create(fn, NULL, FALSE, NULL); 415*4a0e6714SStefan Hajnoczi #endif 416*4a0e6714SStefan Hajnoczi 41785aff158SStefan Hajnoczi #ifndef _WIN32 418edb47ec4SLluís pthread_sigmask(SIG_SETMASK, &oldset, NULL); 41985aff158SStefan Hajnoczi #endif 420edb47ec4SLluís 42185aff158SStefan Hajnoczi return thread; 42285aff158SStefan Hajnoczi } 42385aff158SStefan Hajnoczi 42485aff158SStefan Hajnoczi bool trace_backend_init(const char *events, const char *file) 42585aff158SStefan Hajnoczi { 42685aff158SStefan Hajnoczi GThread *thread; 42785aff158SStefan Hajnoczi 42885aff158SStefan Hajnoczi if (!g_thread_supported()) { 42942ed3727SAlon Levy #if !GLIB_CHECK_VERSION(2, 31, 0) 43085aff158SStefan Hajnoczi g_thread_init(NULL); 43142ed3727SAlon Levy #else 43242ed3727SAlon Levy fprintf(stderr, "glib threading failed to initialize.\n"); 43342ed3727SAlon Levy exit(1); 43442ed3727SAlon Levy #endif 43585aff158SStefan Hajnoczi } 43685aff158SStefan Hajnoczi 437*4a0e6714SStefan Hajnoczi #if !GLIB_CHECK_VERSION(2, 31, 0) 43885aff158SStefan Hajnoczi trace_available_cond = g_cond_new(); 43985aff158SStefan Hajnoczi trace_empty_cond = g_cond_new(); 440*4a0e6714SStefan Hajnoczi #endif 44185aff158SStefan Hajnoczi 44285aff158SStefan Hajnoczi thread = trace_thread_create(writeout_thread); 44385aff158SStefan Hajnoczi if (!thread) { 444e4858974SLluís fprintf(stderr, "warning: unable to initialize simple trace backend\n"); 44585aff158SStefan Hajnoczi return false; 44685aff158SStefan Hajnoczi } 44785aff158SStefan Hajnoczi 448edb47ec4SLluís atexit(st_flush_trace_buffer); 44923d15e86SLluís trace_backend_init_events(events); 450edb47ec4SLluís st_set_trace_file(file); 451edb47ec4SLluís return true; 452edb47ec4SLluís } 453