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 11d38ea87aSPeter Maydell #include "qemu/osdep.h" 1285aff158SStefan Hajnoczi #ifndef _WIN32 13edb47ec4SLluís #include <pthread.h> 1485aff158SStefan Hajnoczi #endif 151de7afc9SPaolo Bonzini #include "qemu/timer.h" 16e4858974SLluís #include "trace/control.h" 17b618c288SLluís Vilanova #include "trace/simple.h" 182ab4b135SAlistair Francis #include "qemu/error-report.h" 19ba4912cbSMarkus Armbruster #include "qemu/qemu-print.h" 20edb47ec4SLluís 21ef4c9fc8SDaniel P. Berrange /** Trace file header event ID, picked to avoid conflict with real event IDs */ 22ef4c9fc8SDaniel P. Berrange #define HEADER_EVENT_ID (~(uint64_t)0) 23edb47ec4SLluís 24edb47ec4SLluís /** Trace file magic number */ 25edb47ec4SLluís #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL 26edb47ec4SLluís 27edb47ec4SLluís /** Trace file version number, bump if format changes */ 287f1b588fSDaniel P. Berrange #define HEADER_VERSION 4 29edb47ec4SLluís 30edb47ec4SLluís /** Records were dropped event ID */ 31edb47ec4SLluís #define DROPPED_EVENT_ID (~(uint64_t)0 - 1) 32edb47ec4SLluís 33edb47ec4SLluís /** Trace record is valid */ 34edb47ec4SLluís #define TRACE_RECORD_VALID ((uint64_t)1 << 63) 35edb47ec4SLluís 36edb47ec4SLluís /* 37edb47ec4SLluís * Trace records are written out by a dedicated thread. The thread waits for 38edb47ec4SLluís * records to become available, writes them out, and then waits again. 39edb47ec4SLluís */ 40e7b3af81SDaniel P. Berrangé static GMutex trace_lock; 41e7b3af81SDaniel P. Berrangé static GCond trace_available_cond; 42e7b3af81SDaniel P. Berrangé static GCond trace_empty_cond; 434a0e6714SStefan Hajnoczi 44edb47ec4SLluís static bool trace_available; 45edb47ec4SLluís static bool trace_writeout_enabled; 46edb47ec4SLluís 4762bab732SHarsh Prateek Bora enum { 4862bab732SHarsh Prateek Bora TRACE_BUF_LEN = 4096 * 64, 4962bab732SHarsh Prateek Bora TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4, 5062bab732SHarsh Prateek Bora }; 5162bab732SHarsh Prateek Bora 5262bab732SHarsh Prateek Bora uint8_t trace_buf[TRACE_BUF_LEN]; 5330d94087SStefan Hajnoczi static volatile gint trace_idx; 5462bab732SHarsh Prateek Bora static unsigned int writeout_idx; 5530d94087SStefan Hajnoczi static volatile gint dropped_events; 5626896cbfSStefan Hajnoczi static uint32_t trace_pid; 57edb47ec4SLluís static FILE *trace_fp; 584552e410SStefan Weil static char *trace_file_name; 59edb47ec4SLluís 607f1b588fSDaniel P. Berrange #define TRACE_RECORD_TYPE_MAPPING 0 617f1b588fSDaniel P. Berrange #define TRACE_RECORD_TYPE_EVENT 1 627f1b588fSDaniel P. Berrange 6362bab732SHarsh Prateek Bora /* * Trace buffer entry */ 6462bab732SHarsh Prateek Bora typedef struct { 65ef4c9fc8SDaniel P. Berrange uint64_t event; /* event ID value */ 6662bab732SHarsh Prateek Bora uint64_t timestamp_ns; 6762bab732SHarsh Prateek Bora uint32_t length; /* in bytes */ 6826896cbfSStefan Hajnoczi uint32_t pid; 69fb3a5085SMarkus Armbruster uint64_t arguments[]; 7062bab732SHarsh Prateek Bora } TraceRecord; 7162bab732SHarsh Prateek Bora 7262bab732SHarsh Prateek Bora typedef struct { 7362bab732SHarsh Prateek Bora uint64_t header_event_id; /* HEADER_EVENT_ID */ 7462bab732SHarsh Prateek Bora uint64_t header_magic; /* HEADER_MAGIC */ 7562bab732SHarsh Prateek Bora uint64_t header_version; /* HEADER_VERSION */ 768ae601e8SHarsh Prateek Bora } TraceLogHeader; 7762bab732SHarsh Prateek Bora 7862bab732SHarsh Prateek Bora 7962bab732SHarsh Prateek Bora static void read_from_buffer(unsigned int idx, void *dataptr, size_t size); 8062bab732SHarsh Prateek Bora static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size); 8162bab732SHarsh Prateek Bora 8262bab732SHarsh Prateek Bora static void clear_buffer_range(unsigned int idx, size_t len) 8362bab732SHarsh Prateek Bora { 8462bab732SHarsh Prateek Bora uint32_t num = 0; 8562bab732SHarsh Prateek Bora while (num < len) { 8662bab732SHarsh Prateek Bora if (idx >= TRACE_BUF_LEN) { 8762bab732SHarsh Prateek Bora idx = idx % TRACE_BUF_LEN; 8862bab732SHarsh Prateek Bora } 8962bab732SHarsh Prateek Bora trace_buf[idx++] = 0; 9062bab732SHarsh Prateek Bora num++; 9162bab732SHarsh Prateek Bora } 9262bab732SHarsh Prateek Bora } 93edb47ec4SLluís /** 94edb47ec4SLluís * Read a trace record from the trace buffer 95edb47ec4SLluís * 96edb47ec4SLluís * @idx Trace buffer index 97edb47ec4SLluís * @record Trace record to fill 98edb47ec4SLluís * 99edb47ec4SLluís * Returns false if the record is not valid. 100edb47ec4SLluís */ 10162bab732SHarsh Prateek Bora static bool get_trace_record(unsigned int idx, TraceRecord **recordptr) 102edb47ec4SLluís { 10362bab732SHarsh Prateek Bora uint64_t event_flag = 0; 10462bab732SHarsh Prateek Bora TraceRecord record; 10562bab732SHarsh Prateek Bora /* read the event flag to see if its a valid record */ 10662bab732SHarsh Prateek Bora read_from_buffer(idx, &record, sizeof(event_flag)); 10762bab732SHarsh Prateek Bora 10862bab732SHarsh Prateek Bora if (!(record.event & TRACE_RECORD_VALID)) { 109edb47ec4SLluís return false; 110edb47ec4SLluís } 111edb47ec4SLluís 11262bab732SHarsh Prateek Bora smp_rmb(); /* read memory barrier before accessing record */ 11362bab732SHarsh Prateek Bora /* read the record header to know record length */ 11462bab732SHarsh Prateek Bora read_from_buffer(idx, &record, sizeof(TraceRecord)); 115cb8d4c8fSStefan Weil *recordptr = malloc(record.length); /* don't use g_malloc, can deadlock when traced */ 11662bab732SHarsh Prateek Bora /* make a copy of record to avoid being overwritten */ 11762bab732SHarsh Prateek Bora read_from_buffer(idx, *recordptr, record.length); 11862bab732SHarsh Prateek Bora smp_rmb(); /* memory barrier before clearing valid flag */ 11962bab732SHarsh Prateek Bora (*recordptr)->event &= ~TRACE_RECORD_VALID; 12062bab732SHarsh Prateek Bora /* clear the trace buffer range for consumed record otherwise any byte 12162bab732SHarsh Prateek Bora * with its MSB set may be considered as a valid event id when the writer 12262bab732SHarsh Prateek Bora * thread crosses this range of buffer again. 12362bab732SHarsh Prateek Bora */ 12462bab732SHarsh Prateek Bora clear_buffer_range(idx, record.length); 125edb47ec4SLluís return true; 126edb47ec4SLluís } 127edb47ec4SLluís 128edb47ec4SLluís /** 129edb47ec4SLluís * Kick writeout thread 130edb47ec4SLluís * 131edb47ec4SLluís * @wait Whether to wait for writeout thread to complete 132edb47ec4SLluís */ 133edb47ec4SLluís static void flush_trace_file(bool wait) 134edb47ec4SLluís { 13586946a2dSMichael Tokarev g_mutex_lock(&trace_lock); 136edb47ec4SLluís trace_available = true; 13786946a2dSMichael Tokarev g_cond_signal(&trace_available_cond); 138edb47ec4SLluís 139edb47ec4SLluís if (wait) { 14086946a2dSMichael Tokarev g_cond_wait(&trace_empty_cond, &trace_lock); 141edb47ec4SLluís } 142edb47ec4SLluís 14386946a2dSMichael Tokarev g_mutex_unlock(&trace_lock); 144edb47ec4SLluís } 145edb47ec4SLluís 146edb47ec4SLluís static void wait_for_trace_records_available(void) 147edb47ec4SLluís { 14886946a2dSMichael Tokarev g_mutex_lock(&trace_lock); 149edb47ec4SLluís while (!(trace_available && trace_writeout_enabled)) { 15086946a2dSMichael Tokarev g_cond_signal(&trace_empty_cond); 15186946a2dSMichael Tokarev g_cond_wait(&trace_available_cond, &trace_lock); 152edb47ec4SLluís } 153edb47ec4SLluís trace_available = false; 15486946a2dSMichael Tokarev g_mutex_unlock(&trace_lock); 155edb47ec4SLluís } 156edb47ec4SLluís 15785aff158SStefan Hajnoczi static gpointer writeout_thread(gpointer opaque) 158edb47ec4SLluís { 15962bab732SHarsh Prateek Bora TraceRecord *recordptr; 16062bab732SHarsh Prateek Bora union { 16162bab732SHarsh Prateek Bora TraceRecord rec; 16262bab732SHarsh Prateek Bora uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)]; 16362bab732SHarsh Prateek Bora } dropped; 16462bab732SHarsh Prateek Bora unsigned int idx = 0; 165fb3a5085SMarkus Armbruster int dropped_count; 166edb47ec4SLluís size_t unused __attribute__ ((unused)); 1677f1b588fSDaniel P. Berrange uint64_t type = TRACE_RECORD_TYPE_EVENT; 168edb47ec4SLluís 169edb47ec4SLluís for (;;) { 170edb47ec4SLluís wait_for_trace_records_available(); 171edb47ec4SLluís 172e722d705SMarkus Armbruster if (g_atomic_int_get(&dropped_events)) { 1737ff59207SLarry Dewey dropped.rec.event = DROPPED_EVENT_ID; 17462bab732SHarsh Prateek Bora dropped.rec.timestamp_ns = get_clock(); 1757ff59207SLarry Dewey dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t); 17626896cbfSStefan Hajnoczi dropped.rec.pid = trace_pid; 177b6b2c962SMarkus Armbruster do { 178e722d705SMarkus Armbruster dropped_count = g_atomic_int_get(&dropped_events); 179b6b2c962SMarkus Armbruster } while (!g_atomic_int_compare_and_exchange(&dropped_events, 180b6b2c962SMarkus Armbruster dropped_count, 0)); 181fb3a5085SMarkus Armbruster dropped.rec.arguments[0] = dropped_count; 1827f1b588fSDaniel P. Berrange unused = fwrite(&type, sizeof(type), 1, trace_fp); 18362bab732SHarsh Prateek Bora unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); 184edb47ec4SLluís } 185edb47ec4SLluís 18662bab732SHarsh Prateek Bora while (get_trace_record(idx, &recordptr)) { 1877f1b588fSDaniel P. Berrange unused = fwrite(&type, sizeof(type), 1, trace_fp); 18862bab732SHarsh Prateek Bora unused = fwrite(recordptr, recordptr->length, 1, trace_fp); 18962bab732SHarsh Prateek Bora writeout_idx += recordptr->length; 190cb8d4c8fSStefan Weil free(recordptr); /* don't use g_free, can deadlock when traced */ 191edb47ec4SLluís idx = writeout_idx % TRACE_BUF_LEN; 192edb47ec4SLluís } 193edb47ec4SLluís 194edb47ec4SLluís fflush(trace_fp); 195edb47ec4SLluís } 196edb47ec4SLluís return NULL; 197edb47ec4SLluís } 198edb47ec4SLluís 19962bab732SHarsh Prateek Bora void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val) 200edb47ec4SLluís { 20162bab732SHarsh Prateek Bora rec->rec_off = write_to_buffer(rec->rec_off, &val, sizeof(uint64_t)); 202edb47ec4SLluís } 203edb47ec4SLluís 20462bab732SHarsh Prateek Bora void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen) 20562bab732SHarsh Prateek Bora { 20662bab732SHarsh Prateek Bora /* Write string length first */ 20762bab732SHarsh Prateek Bora rec->rec_off = write_to_buffer(rec->rec_off, &slen, sizeof(slen)); 20862bab732SHarsh Prateek Bora /* Write actual string now */ 20962bab732SHarsh Prateek Bora rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen); 21062bab732SHarsh Prateek Bora } 211edb47ec4SLluís 212ef4c9fc8SDaniel P. Berrange int trace_record_start(TraceBufferRecord *rec, uint32_t event, size_t datasize) 21362bab732SHarsh Prateek Bora { 21462bab732SHarsh Prateek Bora unsigned int idx, rec_off, old_idx, new_idx; 21562bab732SHarsh Prateek Bora uint32_t rec_len = sizeof(TraceRecord) + datasize; 21660481e21SLluís Vilanova uint64_t event_u64 = event; 21762bab732SHarsh Prateek Bora uint64_t timestamp_ns = get_clock(); 21862bab732SHarsh Prateek Bora 219b6b2c962SMarkus Armbruster do { 220e722d705SMarkus Armbruster old_idx = g_atomic_int_get(&trace_idx); 22162bab732SHarsh Prateek Bora smp_rmb(); 22262bab732SHarsh Prateek Bora new_idx = old_idx + rec_len; 22362bab732SHarsh Prateek Bora 22462bab732SHarsh Prateek Bora if (new_idx - writeout_idx > TRACE_BUF_LEN) { 22562bab732SHarsh Prateek Bora /* Trace Buffer Full, Event dropped ! */ 226fb3a5085SMarkus Armbruster g_atomic_int_inc(&dropped_events); 22762bab732SHarsh Prateek Bora return -ENOSPC; 22862bab732SHarsh Prateek Bora } 229b6b2c962SMarkus Armbruster } while (!g_atomic_int_compare_and_exchange(&trace_idx, old_idx, new_idx)); 23062bab732SHarsh Prateek Bora 23162bab732SHarsh Prateek Bora idx = old_idx % TRACE_BUF_LEN; 23262bab732SHarsh Prateek Bora 23362bab732SHarsh Prateek Bora rec_off = idx; 23460481e21SLluís Vilanova rec_off = write_to_buffer(rec_off, &event_u64, sizeof(event_u64)); 23583d35d3eSHarsh Prateek Bora rec_off = write_to_buffer(rec_off, ×tamp_ns, sizeof(timestamp_ns)); 23683d35d3eSHarsh Prateek Bora rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len)); 23726896cbfSStefan Hajnoczi rec_off = write_to_buffer(rec_off, &trace_pid, sizeof(trace_pid)); 23862bab732SHarsh Prateek Bora 23962bab732SHarsh Prateek Bora rec->tbuf_idx = idx; 24062bab732SHarsh Prateek Bora rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN; 24162bab732SHarsh Prateek Bora return 0; 24262bab732SHarsh Prateek Bora } 24362bab732SHarsh Prateek Bora 24462bab732SHarsh Prateek Bora static void read_from_buffer(unsigned int idx, void *dataptr, size_t size) 24562bab732SHarsh Prateek Bora { 24662bab732SHarsh Prateek Bora uint8_t *data_ptr = dataptr; 24762bab732SHarsh Prateek Bora uint32_t x = 0; 24862bab732SHarsh Prateek Bora while (x < size) { 24962bab732SHarsh Prateek Bora if (idx >= TRACE_BUF_LEN) { 25062bab732SHarsh Prateek Bora idx = idx % TRACE_BUF_LEN; 25162bab732SHarsh Prateek Bora } 25262bab732SHarsh Prateek Bora data_ptr[x++] = trace_buf[idx++]; 25362bab732SHarsh Prateek Bora } 25462bab732SHarsh Prateek Bora } 25562bab732SHarsh Prateek Bora 25662bab732SHarsh Prateek Bora static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size) 25762bab732SHarsh Prateek Bora { 25862bab732SHarsh Prateek Bora uint8_t *data_ptr = dataptr; 25962bab732SHarsh Prateek Bora uint32_t x = 0; 26062bab732SHarsh Prateek Bora while (x < size) { 26162bab732SHarsh Prateek Bora if (idx >= TRACE_BUF_LEN) { 26262bab732SHarsh Prateek Bora idx = idx % TRACE_BUF_LEN; 26362bab732SHarsh Prateek Bora } 26462bab732SHarsh Prateek Bora trace_buf[idx++] = data_ptr[x++]; 26562bab732SHarsh Prateek Bora } 26662bab732SHarsh Prateek Bora return idx; /* most callers wants to know where to write next */ 26762bab732SHarsh Prateek Bora } 26862bab732SHarsh Prateek Bora 26962bab732SHarsh Prateek Bora void trace_record_finish(TraceBufferRecord *rec) 27062bab732SHarsh Prateek Bora { 271db8894f2SHarsh Prateek Bora TraceRecord record; 272db8894f2SHarsh Prateek Bora read_from_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); 27362bab732SHarsh Prateek Bora smp_wmb(); /* write barrier before marking as valid */ 274db8894f2SHarsh Prateek Bora record.event |= TRACE_RECORD_VALID; 275db8894f2SHarsh Prateek Bora write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); 27662bab732SHarsh Prateek Bora 27730d94087SStefan Hajnoczi if (((unsigned int)g_atomic_int_get(&trace_idx) - writeout_idx) 278e722d705SMarkus Armbruster > TRACE_BUF_FLUSH_THRESHOLD) { 279edb47ec4SLluís flush_trace_file(false); 280edb47ec4SLluís } 281edb47ec4SLluís } 282edb47ec4SLluís 2833f2a0984SGerd Hoffmann static int st_write_event_mapping(TraceEventIter *iter) 2847f1b588fSDaniel P. Berrange { 2857f1b588fSDaniel P. Berrange uint64_t type = TRACE_RECORD_TYPE_MAPPING; 2867f1b588fSDaniel P. Berrange TraceEvent *ev; 2877f1b588fSDaniel P. Berrange 2883f2a0984SGerd Hoffmann while ((ev = trace_event_iter_next(iter)) != NULL) { 2897f1b588fSDaniel P. Berrange uint64_t id = trace_event_get_id(ev); 2907f1b588fSDaniel P. Berrange const char *name = trace_event_get_name(ev); 2917f1b588fSDaniel P. Berrange uint32_t len = strlen(name); 2927f1b588fSDaniel P. Berrange if (fwrite(&type, sizeof(type), 1, trace_fp) != 1 || 2937f1b588fSDaniel P. Berrange fwrite(&id, sizeof(id), 1, trace_fp) != 1 || 2947f1b588fSDaniel P. Berrange fwrite(&len, sizeof(len), 1, trace_fp) != 1 || 2957f1b588fSDaniel P. Berrange fwrite(name, len, 1, trace_fp) != 1) { 2967f1b588fSDaniel P. Berrange return -1; 2977f1b588fSDaniel P. Berrange } 2987f1b588fSDaniel P. Berrange } 2997f1b588fSDaniel P. Berrange 3007f1b588fSDaniel P. Berrange return 0; 3017f1b588fSDaniel P. Berrange } 3027f1b588fSDaniel P. Berrange 303db25d56cSMarkus Armbruster /** 304db25d56cSMarkus Armbruster * Enable / disable tracing, return whether it was enabled. 305db25d56cSMarkus Armbruster * 306db25d56cSMarkus Armbruster * @enable: enable if %true, else disable. 307db25d56cSMarkus Armbruster */ 308db25d56cSMarkus Armbruster bool st_set_trace_file_enabled(bool enable) 309edb47ec4SLluís { 3103f2a0984SGerd Hoffmann TraceEventIter iter; 311db25d56cSMarkus Armbruster bool was_enabled = trace_fp; 312db25d56cSMarkus Armbruster 313edb47ec4SLluís if (enable == !!trace_fp) { 314db25d56cSMarkus Armbruster return was_enabled; /* no change */ 315edb47ec4SLluís } 316edb47ec4SLluís 317edb47ec4SLluís /* Halt trace writeout */ 318edb47ec4SLluís flush_trace_file(true); 319edb47ec4SLluís trace_writeout_enabled = false; 320edb47ec4SLluís flush_trace_file(true); 321edb47ec4SLluís 322edb47ec4SLluís if (enable) { 3238ae601e8SHarsh Prateek Bora static const TraceLogHeader header = { 32462bab732SHarsh Prateek Bora .header_event_id = HEADER_EVENT_ID, 32562bab732SHarsh Prateek Bora .header_magic = HEADER_MAGIC, 32662bab732SHarsh Prateek Bora /* Older log readers will check for version at next location */ 32762bab732SHarsh Prateek Bora .header_version = HEADER_VERSION, 328edb47ec4SLluís }; 329edb47ec4SLluís 3306c2a4074SStefan Hajnoczi trace_fp = fopen(trace_file_name, "wb"); 331edb47ec4SLluís if (!trace_fp) { 332db25d56cSMarkus Armbruster return was_enabled; 333edb47ec4SLluís } 334edb47ec4SLluís 3353f2a0984SGerd Hoffmann trace_event_iter_init_all(&iter); 3367f1b588fSDaniel P. Berrange if (fwrite(&header, sizeof header, 1, trace_fp) != 1 || 3373f2a0984SGerd Hoffmann st_write_event_mapping(&iter) < 0) { 338edb47ec4SLluís fclose(trace_fp); 339edb47ec4SLluís trace_fp = NULL; 340db25d56cSMarkus Armbruster return was_enabled; 341edb47ec4SLluís } 342edb47ec4SLluís 343edb47ec4SLluís /* Resume trace writeout */ 344edb47ec4SLluís trace_writeout_enabled = true; 345edb47ec4SLluís flush_trace_file(false); 346edb47ec4SLluís } else { 347edb47ec4SLluís fclose(trace_fp); 348edb47ec4SLluís trace_fp = NULL; 349edb47ec4SLluís } 350db25d56cSMarkus Armbruster return was_enabled; 351edb47ec4SLluís } 352edb47ec4SLluís 353edb47ec4SLluís /** 354edb47ec4SLluís * Set the name of a trace file 355edb47ec4SLluís * 356edb47ec4SLluís * @file The trace file name or NULL for the default name-<pid> set at 357edb47ec4SLluís * config time 358edb47ec4SLluís */ 35941fc57e4SPaolo Bonzini void st_set_trace_file(const char *file) 360edb47ec4SLluís { 361db25d56cSMarkus Armbruster bool saved_enable = st_set_trace_file_enabled(false); 362edb47ec4SLluís 3634552e410SStefan Weil g_free(trace_file_name); 364edb47ec4SLluís 365edb47ec4SLluís if (!file) { 366857a0e38SStefan Weil /* Type cast needed for Windows where getpid() returns an int. */ 367857a0e38SStefan Weil trace_file_name = g_strdup_printf(CONFIG_TRACE_FILE, (pid_t)getpid()); 368edb47ec4SLluís } else { 3694552e410SStefan Weil trace_file_name = g_strdup_printf("%s", file); 370edb47ec4SLluís } 371edb47ec4SLluís 372db25d56cSMarkus Armbruster st_set_trace_file_enabled(saved_enable); 373edb47ec4SLluís } 374edb47ec4SLluís 375ba4912cbSMarkus Armbruster void st_print_trace_file_status(void) 376edb47ec4SLluís { 377ba4912cbSMarkus Armbruster qemu_printf("Trace file \"%s\" %s.\n", 378edb47ec4SLluís trace_file_name, trace_fp ? "on" : "off"); 379edb47ec4SLluís } 380edb47ec4SLluís 381fc764105SLluís void st_flush_trace_buffer(void) 382fc764105SLluís { 383fc764105SLluís flush_trace_file(true); 384fc764105SLluís } 385fc764105SLluís 38685aff158SStefan Hajnoczi /* Helper function to create a thread with signals blocked. Use glib's 38785aff158SStefan Hajnoczi * portable threads since QEMU abstractions cannot be used due to reentrancy in 38885aff158SStefan Hajnoczi * the tracer. Also note the signal masking on POSIX hosts so that the thread 38985aff158SStefan Hajnoczi * does not steal signals when the rest of the program wants them blocked. 39085aff158SStefan Hajnoczi */ 39185aff158SStefan Hajnoczi static GThread *trace_thread_create(GThreadFunc fn) 392edb47ec4SLluís { 39385aff158SStefan Hajnoczi GThread *thread; 39485aff158SStefan Hajnoczi #ifndef _WIN32 395edb47ec4SLluís sigset_t set, oldset; 396edb47ec4SLluís 397edb47ec4SLluís sigfillset(&set); 398edb47ec4SLluís pthread_sigmask(SIG_SETMASK, &set, &oldset); 39985aff158SStefan Hajnoczi #endif 4004a0e6714SStefan Hajnoczi 4014a0e6714SStefan Hajnoczi thread = g_thread_new("trace-thread", fn, NULL); 4024a0e6714SStefan Hajnoczi 40385aff158SStefan Hajnoczi #ifndef _WIN32 404edb47ec4SLluís pthread_sigmask(SIG_SETMASK, &oldset, NULL); 40585aff158SStefan Hajnoczi #endif 406edb47ec4SLluís 40785aff158SStefan Hajnoczi return thread; 40885aff158SStefan Hajnoczi } 40985aff158SStefan Hajnoczi 41041fc57e4SPaolo Bonzini bool st_init(void) 41185aff158SStefan Hajnoczi { 41285aff158SStefan Hajnoczi GThread *thread; 41385aff158SStefan Hajnoczi 41426896cbfSStefan Hajnoczi trace_pid = getpid(); 41526896cbfSStefan Hajnoczi 41685aff158SStefan Hajnoczi thread = trace_thread_create(writeout_thread); 41785aff158SStefan Hajnoczi if (!thread) { 4182ab4b135SAlistair Francis warn_report("unable to initialize simple trace backend"); 41985aff158SStefan Hajnoczi return false; 42085aff158SStefan Hajnoczi } 42185aff158SStefan Hajnoczi 422edb47ec4SLluís atexit(st_flush_trace_buffer); 423edb47ec4SLluís return true; 424edb47ec4SLluís } 425*263b6e96SGerd Hoffmann 426*263b6e96SGerd Hoffmann void st_init_group(size_t group) 427*263b6e96SGerd Hoffmann { 428*263b6e96SGerd Hoffmann TraceEventIter iter; 429*263b6e96SGerd Hoffmann 430*263b6e96SGerd Hoffmann if (!trace_writeout_enabled) { 431*263b6e96SGerd Hoffmann return; 432*263b6e96SGerd Hoffmann } 433*263b6e96SGerd Hoffmann 434*263b6e96SGerd Hoffmann trace_event_iter_init_group(&iter, group); 435*263b6e96SGerd Hoffmann st_write_event_mapping(&iter); 436*263b6e96SGerd Hoffmann } 437