@@ -3,9 +3,16 @@
/* A small part of this API is split into its own header */
#include "qemu/log-for-trace.h"
+#include "qemu/rcu.h"
+
+typedef struct QemuLogFile {
+ struct rcu_head rcu;
+ FILE *fd;
+} QemuLogFile;
/* Private global variable, don't use */
-extern FILE *qemu_logfile;
+extern QemuLogFile *qemu_logfile;
+
/*
* The new API:
@@ -25,7 +32,16 @@ static inline bool qemu_log_enabled(void)
*/
static inline bool qemu_log_separate(void)
{
- return qemu_logfile != NULL && qemu_logfile != stderr;
+ QemuLogFile *logfile;
+ bool res = false;
+
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile && logfile->fd != stderr) {
+ res = true;
+ }
+ rcu_read_unlock();
+ return res;
}
#define CPU_LOG_TB_OUT_ASM (1 << 0)
@@ -55,8 +71,15 @@ static inline bool qemu_log_separate(void)
static inline FILE *qemu_log_lock(void)
{
- qemu_flockfile(qemu_logfile);
- return logfile->fd;
+ QemuLogFile *logfile;
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
+ qemu_flockfile(logfile->fd);
+ return logfile->fd;
+ } else {
+ return NULL;
+ }
}
static inline void qemu_log_unlock(FILE *fd)
@@ -64,6 +87,7 @@ static inline void qemu_log_unlock(FILE *fd)
if (fd) {
qemu_funlockfile(fd);
}
+ rcu_read_unlock();
}
/* Logging functions: */
@@ -73,9 +97,14 @@ static inline void qemu_log_unlock(FILE *fd)
static inline void GCC_FMT_ATTR(1, 0)
qemu_log_vprintf(const char *fmt, va_list va)
{
- if (qemu_logfile) {
- vfprintf(qemu_logfile, fmt, va);
+ QemuLogFile *logfile;
+
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
+ vfprintf(logfile->fd, fmt, va);
}
+ rcu_read_unlock();
}
/* log only if a bit is set on the current loglevel mask:
@@ -28,7 +28,7 @@
static char *logfilename;
static QemuMutex qemu_logfile_mutex;
-FILE *qemu_logfile;
+QemuLogFile *qemu_logfile;
int qemu_loglevel;
static int log_append = 0;
static GArray *debug_regions;
@@ -37,10 +37,14 @@ static GArray *debug_regions;
int qemu_log(const char *fmt, ...)
{
int ret = 0;
- if (qemu_logfile) {
+ QemuLogFile *logfile;
+
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
va_list ap;
va_start(ap, fmt);
- ret = vfprintf(qemu_logfile, fmt, ap);
+ ret = vfprintf(logfile->fd, fmt, ap);
va_end(ap);
/* Don't pass back error results. */
@@ -48,6 +52,7 @@ int qemu_log(const char *fmt, ...)
ret = 0;
}
}
+ rcu_read_unlock();
return ret;
}
@@ -56,12 +61,24 @@ static void __attribute__((__constructor__)) qemu_logfile_init(void)
qemu_mutex_init(&qemu_logfile_mutex);
}
+static void qemu_logfile_free(QemuLogFile *logfile)
+{
+ g_assert(logfile);
+
+ if (logfile->fd != stderr) {
+ fclose(logfile->fd);
+ }
+ g_free(logfile);
+}
+
static bool log_uses_own_buffers;
/* enable or disable low levels log */
void qemu_set_log(int log_flags)
{
bool need_to_open_file = false;
+ QemuLogFile *logfile;
+
qemu_loglevel = log_flags;
#ifdef CONFIG_TRACE_LOG
qemu_loglevel |= LOG_TRACE;
@@ -79,43 +96,47 @@ void qemu_set_log(int log_flags)
}
qemu_mutex_lock(&qemu_logfile_mutex);
if (qemu_logfile && !need_to_open_file) {
- qemu_mutex_unlock(&qemu_logfile_mutex);
- qemu_log_close();
+ logfile = qemu_logfile;
+ atomic_rcu_set(&qemu_logfile, NULL);
+ call_rcu(logfile, qemu_logfile_free, rcu);
} else if (!qemu_logfile && need_to_open_file) {
+ logfile = g_new0(QemuLogFile, 1);
if (logfilename) {
- qemu_logfile = fopen(logfilename, log_append ? "a" : "w");
- if (!qemu_logfile) {
+ logfile->fd = fopen(logfilename, log_append ? "a" : "w");
+ if (!logfile->fd) {
+ g_free(logfile);
perror(logfilename);
_exit(1);
}
/* In case we are a daemon redirect stderr to logfile */
if (is_daemonized()) {
- dup2(fileno(qemu_logfile), STDERR_FILENO);
- fclose(qemu_logfile);
+ dup2(fileno(logfile->fd), STDERR_FILENO);
+ fclose(logfile->fd);
/* This will skip closing logfile in qemu_log_close() */
- qemu_logfile = stderr;
+ logfile->fd = stderr;
}
} else {
/* Default to stderr if no log file specified */
assert(!is_daemonized());
- qemu_logfile = stderr;
+ logfile->fd = stderr;
}
/* must avoid mmap() usage of glibc by setting a buffer "by hand" */
if (log_uses_own_buffers) {
static char logfile_buf[4096];
- setvbuf(qemu_logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
+ setvbuf(logfile->fd, logfile_buf, _IOLBF, sizeof(logfile_buf));
} else {
#if defined(_WIN32)
/* Win32 doesn't support line-buffering, so use unbuffered output. */
- setvbuf(qemu_logfile, NULL, _IONBF, 0);
+ setvbuf(logfile->fd, NULL, _IONBF, 0);
#else
- setvbuf(qemu_logfile, NULL, _IOLBF, 0);
+ setvbuf(logfile->fd, NULL, _IOLBF, 0);
#endif
log_append = 1;
}
- qemu_mutex_unlock(&qemu_logfile_mutex);
+ atomic_rcu_set(&qemu_logfile, logfile);
}
+ qemu_mutex_unlock(&qemu_logfile_mutex);
}
void qemu_log_needs_buffers(void)
@@ -244,18 +265,27 @@ out:
/* fflush() the log file */
void qemu_log_flush(void)
{
- fflush(qemu_logfile);
+ QemuLogFile *logfile;
+
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
+ fflush(logfile->fd);
+ }
+ rcu_read_unlock();
}
/* Close the log file */
void qemu_log_close(void)
{
+ QemuLogFile *logfile;
+
qemu_mutex_lock(&qemu_logfile_mutex);
- if (qemu_logfile) {
- if (qemu_logfile != stderr) {
- fclose(qemu_logfile);
- }
- qemu_logfile = NULL;
+ logfile = qemu_logfile;
+
+ if (logfile) {
+ atomic_rcu_set(&qemu_logfile, NULL);
+ call_rcu(logfile, qemu_logfile_free, rcu);
}
qemu_mutex_unlock(&qemu_logfile_mutex);
}
@@ -15,8 +15,15 @@
*/
static inline void log_cpu_state(CPUState *cpu, int flags)
{
+ QemuLogFile *logfile;
+
if (qemu_log_enabled()) {
- cpu_dump_state(cpu, qemu_logfile, flags);
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
+ cpu_dump_state(cpu, logfile->fd, flags);
+ }
+ rcu_read_unlock();
}
}
@@ -40,19 +47,37 @@ static inline void log_cpu_state_mask(int mask, CPUState *cpu, int flags)
static inline void log_target_disas(CPUState *cpu, target_ulong start,
target_ulong len)
{
- target_disas(qemu_logfile, cpu, start, len);
+ QemuLogFile *logfile;
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
+ target_disas(logfile->fd, cpu, start, len);
+ }
+ rcu_read_unlock();
}
static inline void log_disas(void *code, unsigned long size)
{
- disas(qemu_logfile, code, size);
+ QemuLogFile *logfile;
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
+ disas(logfile->fd, code, size);
+ }
+ rcu_read_unlock();
}
#if defined(CONFIG_USER_ONLY)
/* page_dump() output to the log file: */
static inline void log_page_dump(void)
{
- page_dump(qemu_logfile);
+ QemuLogFile *logfile;
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
+ page_dump(logfile->fd);
+ }
+ rcu_read_unlock();
}
#endif
#endif
@@ -2114,9 +2114,17 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs)
}
if (have_prefs || op->life) {
- for (; col < 40; ++col) {
- putc(' ', qemu_logfile);
+
+ QemuLogFile *logfile;
+
+ rcu_read_lock();
+ logfile = atomic_rcu_read(&qemu_logfile);
+ if (logfile) {
+ for (; col < 40; ++col) {
+ putc(' ', logfile->fd);
+ }
}
+ rcu_read_unlock();
}
if (op->life) {