diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/Makefile.objs | 1 | ||||
-rw-r--r-- | util/aio-posix.c | 2 | ||||
-rw-r--r-- | util/atomic64.c | 83 | ||||
-rw-r--r-- | util/cacheinfo.c | 11 | ||||
-rw-r--r-- | util/cutils.c | 5 | ||||
-rw-r--r-- | util/error.c | 13 | ||||
-rw-r--r-- | util/hbitmap.c | 14 | ||||
-rw-r--r-- | util/memfd.c | 35 | ||||
-rw-r--r-- | util/oslib-posix.c | 73 | ||||
-rw-r--r-- | util/oslib-win32.c | 27 | ||||
-rw-r--r-- | util/qemu-error.c | 5 | ||||
-rw-r--r-- | util/qemu-option.c | 71 | ||||
-rw-r--r-- | util/qemu-timer.c | 63 | ||||
-rw-r--r-- | util/qsp.c | 49 |
14 files changed, 349 insertions, 103 deletions
diff --git a/util/Makefile.objs b/util/Makefile.objs index 0e88899011..0820923c18 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -3,6 +3,7 @@ util-obj-y += bufferiszero.o util-obj-y += lockcnt.o util-obj-y += aiocb.o async.o aio-wait.o thread-pool.o qemu-timer.o util-obj-y += main-loop.o iohandler.o +util-obj-$(call lnot,$(CONFIG_ATOMIC64)) += atomic64.o util-obj-$(CONFIG_POSIX) += aio-posix.o util-obj-$(CONFIG_POSIX) += compatfd.o util-obj-$(CONFIG_POSIX) += event_notifier-posix.o diff --git a/util/aio-posix.c b/util/aio-posix.c index 621b3025d8..51c41ed3c9 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -40,7 +40,7 @@ struct AioHandler #ifdef CONFIG_EPOLL_CREATE1 -/* The fd number threashold to switch to epoll */ +/* The fd number threshold to switch to epoll */ #define EPOLL_ENABLE_THRESHOLD 64 static void aio_epoll_disable(AioContext *ctx) diff --git a/util/atomic64.c b/util/atomic64.c new file mode 100644 index 0000000000..b198a6c9c8 --- /dev/null +++ b/util/atomic64.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018, Emilio G. Cota <cota@braap.org> + * + * License: GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "qemu/atomic.h" +#include "qemu/thread.h" + +#ifdef CONFIG_ATOMIC64 +#error This file must only be compiled if !CONFIG_ATOMIC64 +#endif + +/* + * When !CONFIG_ATOMIC64, we serialize both reads and writes with spinlocks. + * We use an array of spinlocks, with padding computed at run-time based on + * the host's dcache line size. + * We point to the array with a void * to simplify the padding's computation. + * Each spinlock is located every lock_size bytes. + */ +static void *lock_array; +static size_t lock_size; + +/* + * Systems without CONFIG_ATOMIC64 are unlikely to have many cores, so we use a + * small array of locks. + */ +#define NR_LOCKS 16 + +static QemuSpin *addr_to_lock(const void *addr) +{ + uintptr_t a = (uintptr_t)addr; + uintptr_t idx; + + idx = a >> qemu_dcache_linesize_log; + idx ^= (idx >> 8) ^ (idx >> 16); + idx &= NR_LOCKS - 1; + return lock_array + idx * lock_size; +} + +#define GEN_READ(name, type) \ + type name(const type *ptr) \ + { \ + QemuSpin *lock = addr_to_lock(ptr); \ + type ret; \ + \ + qemu_spin_lock(lock); \ + ret = *ptr; \ + qemu_spin_unlock(lock); \ + return ret; \ + } + +GEN_READ(atomic_read_i64, int64_t) +GEN_READ(atomic_read_u64, uint64_t) +#undef GEN_READ + +#define GEN_SET(name, type) \ + void name(type *ptr, type val) \ + { \ + QemuSpin *lock = addr_to_lock(ptr); \ + \ + qemu_spin_lock(lock); \ + *ptr = val; \ + qemu_spin_unlock(lock); \ + } + +GEN_SET(atomic_set_i64, int64_t) +GEN_SET(atomic_set_u64, uint64_t) +#undef GEN_SET + +void atomic64_init(void) +{ + int i; + + lock_size = ROUND_UP(sizeof(QemuSpin), qemu_dcache_linesize); + lock_array = qemu_memalign(qemu_dcache_linesize, lock_size * NR_LOCKS); + for (i = 0; i < NR_LOCKS; i++) { + QemuSpin *lock = lock_array + i * lock_size; + + qemu_spin_init(lock); + } +} diff --git a/util/cacheinfo.c b/util/cacheinfo.c index db5172d07c..3cd080b83d 100644 --- a/util/cacheinfo.c +++ b/util/cacheinfo.c @@ -7,9 +7,13 @@ */ #include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "qemu/atomic.h" int qemu_icache_linesize = 0; +int qemu_icache_linesize_log; int qemu_dcache_linesize = 0; +int qemu_dcache_linesize_log; /* * Operating system specific detection mechanisms. @@ -172,6 +176,13 @@ static void __attribute__((constructor)) init_cache_info(void) arch_cache_info(&isize, &dsize); fallback_cache_info(&isize, &dsize); + assert((isize & (isize - 1)) == 0); + assert((dsize & (dsize - 1)) == 0); + qemu_icache_linesize = isize; + qemu_icache_linesize_log = ctz32(isize); qemu_dcache_linesize = dsize; + qemu_dcache_linesize_log = ctz32(dsize); + + atomic64_init(); } diff --git a/util/cutils.c b/util/cutils.c index 9205e09031..698bd315bd 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -769,3 +769,8 @@ char *size_to_str(uint64_t val) return g_strdup_printf("%0.3g %sB", (double)val / div, suffixes[i]); } + +int qemu_pstrcmp0(const char **str1, const char **str2) +{ + return g_strcmp0(*str1, *str2); +} diff --git a/util/error.c b/util/error.c index 3efdd69162..b5ccbd8eac 100644 --- a/util/error.c +++ b/util/error.c @@ -292,3 +292,16 @@ void error_propagate(Error **dst_errp, Error *local_err) error_free(local_err); } } + +void error_propagate_prepend(Error **dst_errp, Error *err, + const char *fmt, ...) +{ + va_list ap; + + if (dst_errp && !*dst_errp) { + va_start(ap, fmt); + error_vprepend(&err, fmt, ap); + va_end(ap); + } /* else error is being ignored, don't bother with prepending */ + error_propagate(dst_errp, err); +} diff --git a/util/hbitmap.c b/util/hbitmap.c index bcd304041a..8d402c59d9 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -723,6 +723,10 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size) } } +bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b) +{ + return (a->size == b->size) && (a->granularity == b->granularity); +} /** * Given HBitmaps A and B, let A := A (BITOR) B. @@ -731,14 +735,15 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size) * @return true if the merge was successful, * false if it was not attempted. */ -bool hbitmap_merge(HBitmap *a, const HBitmap *b) +bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result) { int i; uint64_t j; - if ((a->size != b->size) || (a->granularity != b->granularity)) { + if (!hbitmap_can_merge(a, b) || !hbitmap_can_merge(a, result)) { return false; } + assert(hbitmap_can_merge(b, result)); if (hbitmap_count(b) == 0) { return true; @@ -750,10 +755,13 @@ bool hbitmap_merge(HBitmap *a, const HBitmap *b) */ for (i = HBITMAP_LEVELS - 1; i >= 0; i--) { for (j = 0; j < a->sizes[i]; j++) { - a->levels[i][j] |= b->levels[i][j]; + result->levels[i][j] = a->levels[i][j] | b->levels[i][j]; } } + /* Recompute the dirty count */ + result->count = hb_count_between(result, 0, result->size - 1); + return true; } diff --git a/util/memfd.c b/util/memfd.c index 6287946b61..8debd0d037 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -45,22 +45,6 @@ static int memfd_create(const char *name, unsigned int flags) } #endif -#ifndef MFD_CLOEXEC -#define MFD_CLOEXEC 0x0001U -#endif - -#ifndef MFD_ALLOW_SEALING -#define MFD_ALLOW_SEALING 0x0002U -#endif - -#ifndef MFD_HUGETLB -#define MFD_HUGETLB 0x0004U -#endif - -#ifndef MFD_HUGE_SHIFT -#define MFD_HUGE_SHIFT 26 -#endif - int qemu_memfd_create(const char *name, size_t size, bool hugetlb, uint64_t hugetlbsize, unsigned int seals, Error **errp) { @@ -201,23 +185,16 @@ bool qemu_memfd_alloc_check(void) * * Check if host supports memfd. */ -bool qemu_memfd_check(void) +bool qemu_memfd_check(unsigned int flags) { #ifdef CONFIG_LINUX - static int memfd_check = MEMFD_TODO; + int mfd = memfd_create("test", flags); - if (memfd_check == MEMFD_TODO) { - int mfd = memfd_create("test", 0); - if (mfd >= 0) { - memfd_check = MEMFD_OK; - close(mfd); - } else { - memfd_check = MEMFD_KO; - } + if (mfd >= 0) { + close(mfd); + return true; } +#endif - return memfd_check == MEMFD_OK; -#else return false; -#endif } diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 13b6f8d776..fbd0dc8c57 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -88,6 +88,79 @@ int qemu_daemon(int nochdir, int noclose) return daemon(nochdir, noclose); } +bool qemu_write_pidfile(const char *path, Error **errp) +{ + int fd; + char pidstr[32]; + + while (1) { + struct stat a, b; + struct flock lock = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + .l_len = 0, + }; + + fd = qemu_open(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (fd == -1) { + error_setg_errno(errp, errno, "Cannot open pid file"); + return false; + } + + if (fstat(fd, &b) < 0) { + error_setg_errno(errp, errno, "Cannot stat file"); + goto fail_close; + } + + if (fcntl(fd, F_SETLK, &lock)) { + error_setg_errno(errp, errno, "Cannot lock pid file"); + goto fail_close; + } + + /* + * Now make sure the path we locked is the same one that now + * exists on the filesystem. + */ + if (stat(path, &a) < 0) { + /* + * PID file disappeared, someone else must be racing with + * us, so try again. + */ + close(fd); + continue; + } + + if (a.st_ino == b.st_ino) { + break; + } + + /* + * PID file was recreated, someone else must be racing with + * us, so try again. + */ + close(fd); + } + + if (ftruncate(fd, 0) < 0) { + error_setg_errno(errp, errno, "Failed to truncate pid file"); + goto fail_unlink; + } + + snprintf(pidstr, sizeof(pidstr), FMT_pid "\n", getpid()); + if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) { + error_setg(errp, "Failed to write pid file"); + goto fail_unlink; + } + + return true; + +fail_unlink: + unlink(path); +fail_close: + close(fd); + return false; +} + void *qemu_oom_check(void *ptr) { if (ptr == NULL) { diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 25dd1595ad..b4c17f5dfa 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -776,3 +776,30 @@ ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags, } return ret; } + +bool qemu_write_pidfile(const char *filename, Error **errp) +{ + char buffer[128]; + int len; + HANDLE file; + OVERLAPPED overlap; + BOOL ret; + memset(&overlap, 0, sizeof(overlap)); + + file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (file == INVALID_HANDLE_VALUE) { + error_setg(errp, "Failed to create PID file"); + return false; + } + len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", (pid_t)getpid()); + ret = WriteFile(file, (LPCVOID)buffer, (DWORD)len, + NULL, &overlap); + CloseHandle(file); + if (ret == 0) { + error_setg(errp, "Failed to write PID file"); + return false; + } + return true; +} diff --git a/util/qemu-error.c b/util/qemu-error.c index 4ab428f7e4..fcbe8a1f74 100644 --- a/util/qemu-error.c +++ b/util/qemu-error.c @@ -194,7 +194,6 @@ bool enable_timestamp_msg; * Format arguments like vsprintf(). The resulting message should be * a single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. - * It's wrong to call this in a QMP monitor. Use error_setg() there. */ static void vreport(report_type type, const char *fmt, va_list ap) { @@ -242,7 +241,6 @@ void error_vreport(const char *fmt, va_list ap) * Format arguments like vsprintf(). The resulting message should be * a single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. - * It's wrong to call this in a QMP monitor. Use error_setg() there. */ void warn_vreport(const char *fmt, va_list ap) { @@ -255,7 +253,6 @@ void warn_vreport(const char *fmt, va_list ap) * Format arguments like vsprintf(). The resulting message should be * a single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. - * It's wrong to call this in a QMP monitor. Use error_setg() there. */ void info_vreport(const char *fmt, va_list ap) { @@ -283,7 +280,6 @@ void error_report(const char *fmt, ...) * Format arguments like sprintf(). The resulting message should be a * single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. - * It's wrong to call this in a QMP monitor. Use error_setg() there. */ void warn_report(const char *fmt, ...) { @@ -300,7 +296,6 @@ void warn_report(const char *fmt, ...) * Format arguments like sprintf(). The resulting message should be a * single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. - * It's wrong to call this in a QMP monitor. Use error_setg() there. */ void info_report(const char *fmt, ...) { diff --git a/util/qemu-option.c b/util/qemu-option.c index 01886efe90..9a5f263294 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -208,17 +208,51 @@ out: return result; } +static const char *opt_type_to_string(enum QemuOptType type) +{ + switch (type) { + case QEMU_OPT_STRING: + return "str"; + case QEMU_OPT_BOOL: + return "bool (on/off)"; + case QEMU_OPT_NUMBER: + return "num"; + case QEMU_OPT_SIZE: + return "size"; + } + + g_assert_not_reached(); +} + void qemu_opts_print_help(QemuOptsList *list) { QemuOptDesc *desc; + int i; + GPtrArray *array = g_ptr_array_new(); assert(list); desc = list->desc; while (desc && desc->name) { - printf("%-16s %s\n", desc->name, - desc->help ? desc->help : "No description available"); + GString *str = g_string_new(NULL); + if (list->name) { + g_string_append_printf(str, "%s.", list->name); + } + g_string_append_printf(str, "%s=%s", desc->name, + opt_type_to_string(desc->type)); + if (desc->help) { + g_string_append_printf(str, " - %s", desc->help); + } + g_ptr_array_add(array, g_string_free(str, false)); desc++; } + + g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0); + for (i = 0; i < array->len; i++) { + printf("%s\n", (char *)array->pdata[i]); + } + g_ptr_array_set_free_func(array, g_free); + g_ptr_array_free(array, true); + } /* ------------------------------------------------------------------ */ @@ -486,7 +520,7 @@ int qemu_opt_unset(QemuOpts *opts, const char *name) } static void opt_set(QemuOpts *opts, const char *name, char *value, - bool prepend, Error **errp) + bool prepend, bool *invalidp, Error **errp) { QemuOpt *opt; const QemuOptDesc *desc; @@ -496,6 +530,9 @@ static void opt_set(QemuOpts *opts, const char *name, char *value, if (!desc && !opts_accepts_any(opts)) { g_free(value); error_setg(errp, QERR_INVALID_PARAMETER, name); + if (invalidp) { + *invalidp = true; + } return; } @@ -519,7 +556,7 @@ static void opt_set(QemuOpts *opts, const char *name, char *value, void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, Error **errp) { - opt_set(opts, name, g_strdup(value), false, errp); + opt_set(opts, name, g_strdup(value), false, NULL, errp); } void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, @@ -750,7 +787,8 @@ void qemu_opts_print(QemuOpts *opts, const char *separator) } static void opts_do_parse(QemuOpts *opts, const char *params, - const char *firstname, bool prepend, Error **errp) + const char *firstname, bool prepend, + bool *invalidp, Error **errp) { char *option = NULL; char *value = NULL; @@ -785,7 +823,7 @@ static void opts_do_parse(QemuOpts *opts, const char *params, } if (strcmp(option, "id") != 0) { /* store and parse */ - opt_set(opts, option, value, prepend, &local_err); + opt_set(opts, option, value, prepend, invalidp, &local_err); value = NULL; if (local_err) { error_propagate(errp, local_err); @@ -814,11 +852,12 @@ static void opts_do_parse(QemuOpts *opts, const char *params, void qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, Error **errp) { - opts_do_parse(opts, params, firstname, false, errp); + opts_do_parse(opts, params, firstname, false, NULL, errp); } static QemuOpts *opts_parse(QemuOptsList *list, const char *params, - bool permit_abbrev, bool defaults, Error **errp) + bool permit_abbrev, bool defaults, + bool *invalidp, Error **errp) { const char *firstname; char *id = NULL; @@ -850,7 +889,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, return NULL; } - opts_do_parse(opts, params, firstname, defaults, &local_err); + opts_do_parse(opts, params, firstname, defaults, invalidp, &local_err); if (local_err) { error_propagate(errp, local_err); qemu_opts_del(opts); @@ -870,7 +909,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, bool permit_abbrev, Error **errp) { - return opts_parse(list, params, permit_abbrev, false, errp); + return opts_parse(list, params, permit_abbrev, false, NULL, errp); } /** @@ -886,10 +925,16 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params, { Error *err = NULL; QemuOpts *opts; + bool invalidp = false; - opts = opts_parse(list, params, permit_abbrev, false, &err); + opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err); if (err) { - error_report_err(err); + if (invalidp && has_help_option(params)) { + qemu_opts_print_help(list); + error_free(err); + } else { + error_report_err(err); + } } return opts; } @@ -899,7 +944,7 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, { QemuOpts *opts; - opts = opts_parse(list, params, permit_abbrev, true, NULL); + opts = opts_parse(list, params, permit_abbrev, true, NULL, NULL); assert(opts); } diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 86bfe84037..1cc1b2f2c3 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -339,14 +339,19 @@ int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout) } -void timer_init_tl(QEMUTimer *ts, - QEMUTimerList *timer_list, int scale, - QEMUTimerCB *cb, void *opaque) +void timer_init_full(QEMUTimer *ts, + QEMUTimerListGroup *timer_list_group, QEMUClockType type, + int scale, int attributes, + QEMUTimerCB *cb, void *opaque) { - ts->timer_list = timer_list; + if (!timer_list_group) { + timer_list_group = &main_loop_tlg; + } + ts->timer_list = timer_list_group->tl[type]; ts->cb = cb; ts->opaque = opaque; ts->scale = scale; + ts->attributes = attributes; ts->expire_time = -1; } @@ -484,6 +489,7 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) bool progress = false; QEMUTimerCB *cb; void *opaque; + bool need_replay_checkpoint = false; if (!atomic_read(&timer_list->active_timers)) { return false; @@ -499,8 +505,15 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) break; default: case QEMU_CLOCK_VIRTUAL: - if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { - goto out; + if (replay_mode != REPLAY_MODE_NONE) { + /* Checkpoint for virtual clock is redundant in cases where + * it's being triggered with only non-EXTERNAL timers, because + * these timers don't change guest state directly. + * Since it has conditional dependence on specific timers, it is + * subject to race conditions and requires special handling. + * See below. + */ + need_replay_checkpoint = true; } break; case QEMU_CLOCK_HOST: @@ -515,14 +528,39 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) break; } + /* + * Extract expired timers from active timers list and and process them. + * + * In rr mode we need "filtered" checkpointing for virtual clock. The + * checkpoint must be recorded/replayed before processing any non-EXTERNAL timer, + * and that must only be done once since the clock value stays the same. Because + * non-EXTERNAL timers may appear in the timers list while it being processed, + * the checkpoint can be issued at a time until no timers are left and we are + * done". + */ current_time = qemu_clock_get_ns(timer_list->clock->type); - for(;;) { - qemu_mutex_lock(&timer_list->active_timers_lock); - ts = timer_list->active_timers; + qemu_mutex_lock(&timer_list->active_timers_lock); + while ((ts = timer_list->active_timers)) { if (!timer_expired_ns(ts, current_time)) { - qemu_mutex_unlock(&timer_list->active_timers_lock); + /* No expired timers left. The checkpoint can be skipped + * if no timers fired or they were all external. + */ break; } + if (need_replay_checkpoint + && !(ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)) { + /* once we got here, checkpoint clock only once */ + need_replay_checkpoint = false; + qemu_mutex_unlock(&timer_list->active_timers_lock); + if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) { + goto out; + } + qemu_mutex_lock(&timer_list->active_timers_lock); + /* The lock was released; start over again in case the list was + * modified. + */ + continue; + } /* remove timer from the list before calling the callback */ timer_list->active_timers = ts->next; @@ -530,12 +568,15 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) ts->expire_time = -1; cb = ts->cb; opaque = ts->opaque; - qemu_mutex_unlock(&timer_list->active_timers_lock); /* run the callback (the timer list can be modified) */ + qemu_mutex_unlock(&timer_list->active_timers_lock); cb(opaque); + qemu_mutex_lock(&timer_list->active_timers_lock); + progress = true; } + qemu_mutex_unlock(&timer_list->active_timers_lock); out: qemu_event_set(&timer_list->timers_done_ev); diff --git a/util/qsp.c b/util/qsp.c index 2de3a97594..a848b09c6d 100644 --- a/util/qsp.c +++ b/util/qsp.c @@ -84,13 +84,6 @@ struct QSPEntry { uint64_t n_acqs; uint64_t ns; unsigned int n_objs; /* count of coalesced objs; only used for reporting */ -#ifndef CONFIG_ATOMIC64 - /* - * If we cannot update the counts atomically, then use a seqlock. - * We don't need an associated lock because the updates are thread-local. - */ - QemuSeqLock sequence; -#endif }; typedef struct QSPEntry QSPEntry; @@ -345,46 +338,15 @@ static QSPEntry *qsp_entry_get(const void *obj, const char *file, int line, } /* - * @from is in the global hash table; read it atomically if the host - * supports it, otherwise use the seqlock. - */ -static void qsp_entry_aggregate(QSPEntry *to, const QSPEntry *from) -{ -#ifdef CONFIG_ATOMIC64 - to->ns += atomic_read__nocheck(&from->ns); - to->n_acqs += atomic_read__nocheck(&from->n_acqs); -#else - unsigned int version; - uint64_t ns, n_acqs; - - do { - version = seqlock_read_begin(&from->sequence); - ns = atomic_read__nocheck(&from->ns); - n_acqs = atomic_read__nocheck(&from->n_acqs); - } while (seqlock_read_retry(&from->sequence, version)); - - to->ns += ns; - to->n_acqs += n_acqs; -#endif -} - -/* * @e is in the global hash table; it is only written to by the current thread, * so we write to it atomically (as in "write once") to prevent torn reads. - * If the host doesn't support u64 atomics, use the seqlock. */ static inline void do_qsp_entry_record(QSPEntry *e, int64_t delta, bool acq) { -#ifndef CONFIG_ATOMIC64 - seqlock_write_begin(&e->sequence); -#endif - atomic_set__nocheck(&e->ns, e->ns + delta); + atomic_set_u64(&e->ns, e->ns + delta); if (acq) { - atomic_set__nocheck(&e->n_acqs, e->n_acqs + 1); + atomic_set_u64(&e->n_acqs, e->n_acqs + 1); } -#ifndef CONFIG_ATOMIC64 - seqlock_write_end(&e->sequence); -#endif } static inline void qsp_entry_record(QSPEntry *e, int64_t delta) @@ -550,7 +512,12 @@ static void qsp_aggregate(void *p, uint32_t h, void *up) hash = qsp_entry_no_thread_hash(e); agg = qsp_entry_find(ht, e, hash); - qsp_entry_aggregate(agg, e); + /* + * The entry is in the global hash table; read from it atomically (as in + * "read once"). + */ + agg->ns += atomic_read_u64(&e->ns); + agg->n_acqs += atomic_read_u64(&e->n_acqs); } static void qsp_iter_diff(void *p, uint32_t hash, void *htp) |