diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/Makefile.objs | 1 | ||||
-rw-r--r-- | util/atomic64.c | 83 | ||||
-rw-r--r-- | util/cacheinfo.c | 11 | ||||
-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-timer.c | 2 | ||||
-rw-r--r-- | util/qsp.c | 49 |
8 files changed, 211 insertions, 70 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/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/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-timer.c b/util/qemu-timer.c index 86bfe84037..eb60d8f73a 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -496,6 +496,7 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) switch (timer_list->clock->type) { case QEMU_CLOCK_REALTIME: + case QEMU_CLOCK_VIRTUAL_EXT: break; default: case QEMU_CLOCK_VIRTUAL: @@ -597,6 +598,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type) return get_clock(); default: case QEMU_CLOCK_VIRTUAL: + case QEMU_CLOCK_VIRTUAL_EXT: if (use_icount) { return cpu_get_icount(); } else { 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) |