#include <glib/gprintf.h>
-#include "qemu-common.h"
#include "sysemu/sysemu.h"
#include "trace.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/madvise.h"
#include "qemu/sockets.h"
#include "qemu/thread.h"
#include <libgen.h>
#endif
#ifdef __FreeBSD__
-#include <sys/sysctl.h>
-#include <sys/user.h>
#include <sys/thr.h>
+#include <sys/types.h>
+#include <sys/user.h>
#include <libutil.h>
#endif
#ifdef __NetBSD__
-#include <sys/sysctl.h>
#include <lwp.h>
#endif
/* used by sigbus_handler() */
static MemsetContext *sigbus_memset_context;
+struct sigaction sigbus_oldact;
+static QemuMutex sigbus_mutex;
static QemuMutex page_mutex;
static QemuCond page_cond;
.l_len = 0,
};
- fd = qemu_open_old(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
+ fd = qemu_create(path, O_WRONLY, S_IRUSR | S_IWUSR, errp);
if (fd == -1) {
- error_setg_errno(errp, errno, "Cannot open pid file");
return false;
}
}
snprintf(pidstr, sizeof(pidstr), FMT_pid "\n", getpid());
- if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
+ if (qemu_write_full(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
error_setg(errp, "Failed to write pid file");
goto fail_unlink;
}
return false;
}
-void *qemu_oom_check(void *ptr)
-{
- if (ptr == NULL) {
- fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
- abort();
- }
- return ptr;
-}
-
-void *qemu_try_memalign(size_t alignment, size_t size)
-{
- void *ptr;
-
- if (alignment < sizeof(void*)) {
- alignment = sizeof(void*);
- } else {
- g_assert(is_power_of_2(alignment));
- }
-
-#if defined(CONFIG_POSIX_MEMALIGN)
- int ret;
- ret = posix_memalign(&ptr, alignment, size);
- if (ret != 0) {
- errno = ret;
- ptr = NULL;
- }
-#elif defined(CONFIG_BSD)
- ptr = valloc(size);
-#else
- ptr = memalign(alignment, size);
-#endif
- trace_qemu_memalign(alignment, size, ptr);
- return ptr;
-}
-
-void *qemu_memalign(size_t alignment, size_t size)
-{
- return qemu_oom_check(qemu_try_memalign(alignment, size));
-}
-
/* alloc shared memory pages */
void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared,
bool noreserve)
return ptr;
}
-void qemu_vfree(void *ptr)
-{
- trace_qemu_vfree(ptr);
- free(ptr);
-}
-
void qemu_anon_ram_free(void *ptr, size_t size)
{
trace_qemu_anon_ram_free(ptr, size);
qemu_ram_munmap(-1, ptr, size);
}
-void qemu_set_block(int fd)
+void qemu_socket_set_block(int fd)
{
- int f;
- f = fcntl(fd, F_GETFL);
- assert(f != -1);
- f = fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
- assert(f != -1);
+ g_unix_set_fd_nonblocking(fd, false, NULL);
}
-int qemu_try_set_nonblock(int fd)
+int qemu_socket_try_set_nonblock(int fd)
{
- int f;
- f = fcntl(fd, F_GETFL);
- if (f == -1) {
- return -errno;
- }
- if (fcntl(fd, F_SETFL, f | O_NONBLOCK) == -1) {
- return -errno;
- }
- return 0;
+ return g_unix_set_fd_nonblocking(fd, true, NULL) ? 0 : -errno;
}
-void qemu_set_nonblock(int fd)
+void qemu_socket_set_nonblock(int fd)
{
int f;
- f = qemu_try_set_nonblock(fd);
+ f = qemu_socket_try_set_nonblock(fd);
assert(f == 0);
}
assert(f != -1);
}
-/*
- * Creates a pipe with FD_CLOEXEC set on both file descriptors
- */
-int qemu_pipe(int pipefd[2])
-{
- int ret;
-
-#ifdef CONFIG_PIPE2
- ret = pipe2(pipefd, O_CLOEXEC);
- if (ret != -1 || errno != ENOSYS) {
- return ret;
- }
-#endif
- ret = pipe(pipefd);
- if (ret == 0) {
- qemu_set_cloexec(pipefd[0]);
- qemu_set_cloexec(pipefd[1]);
- }
-
- return ret;
-}
-
char *
-qemu_get_local_state_pathname(const char *relative_pathname)
+qemu_get_local_state_dir(void)
{
- g_autofree char *dir = g_strdup_printf("%s/%s",
- CONFIG_QEMU_LOCALSTATEDIR,
- relative_pathname);
- return get_relocated_path(dir);
+ return get_relocated_path(CONFIG_QEMU_LOCALSTATEDIR);
}
void qemu_set_tty_echo(int fd, bool echo)
tcsetattr(fd, TCSANOW, &tty);
}
-static const char *exec_dir;
-
-void qemu_init_exec_dir(const char *argv0)
-{
- char *p = NULL;
- char buf[PATH_MAX];
-
- if (exec_dir) {
- return;
- }
-
-#if defined(__linux__)
- {
- int len;
- len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
- if (len > 0) {
- buf[len] = 0;
- p = buf;
- }
- }
-#elif defined(__FreeBSD__) \
- || (defined(__NetBSD__) && defined(KERN_PROC_PATHNAME))
- {
-#if defined(__FreeBSD__)
- static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
-#else
- static int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
-#endif
- size_t len = sizeof(buf) - 1;
-
- *buf = '\0';
- if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) &&
- *buf) {
- buf[sizeof(buf) - 1] = '\0';
- p = buf;
- }
- }
-#elif defined(__APPLE__)
- {
- char fpath[PATH_MAX];
- uint32_t len = sizeof(fpath);
- if (_NSGetExecutablePath(fpath, &len) == 0) {
- p = realpath(fpath, buf);
- if (!p) {
- return;
- }
- }
- }
-#elif defined(__HAIKU__)
- {
- image_info ii;
- int32_t c = 0;
-
- *buf = '\0';
- while (get_next_image_info(0, &c, &ii) == B_OK) {
- if (ii.type == B_APP_IMAGE) {
- strncpy(buf, ii.name, sizeof(buf));
- buf[sizeof(buf) - 1] = 0;
- p = buf;
- break;
- }
- }
- }
-#endif
- /* If we don't have any way of figuring out the actual executable
- location then try argv[0]. */
- if (!p && argv0) {
- p = realpath(argv0, buf);
- }
- if (p) {
- exec_dir = g_path_get_dirname(p);
- } else {
- exec_dir = CONFIG_BINDIR;
- }
-}
-
-const char *qemu_get_exec_dir(void)
-{
- return exec_dir;
-}
-
+#ifdef CONFIG_LINUX
+static void sigbus_handler(int signal, siginfo_t *siginfo, void *ctx)
+#else /* CONFIG_LINUX */
static void sigbus_handler(int signal)
+#endif /* CONFIG_LINUX */
{
int i;
}
}
}
+
+#ifdef CONFIG_LINUX
+ /*
+ * We assume that the MCE SIGBUS handler could have been registered. We
+ * should never receive BUS_MCEERR_AO on any of our threads, but only on
+ * the main thread registered for PR_MCE_KILL_EARLY. Further, we should not
+ * receive BUS_MCEERR_AR triggered by action of other threads on one of
+ * our threads. So, no need to check for unrelated SIGBUS when seeing one
+ * for our threads.
+ *
+ * We will forward to the MCE handler, which will either handle the SIGBUS
+ * or reinstall the default SIGBUS handler and reraise the SIGBUS. The
+ * default SIGBUS handler will crash the process, so we don't care.
+ */
+ if (sigbus_oldact.sa_flags & SA_SIGINFO) {
+ sigbus_oldact.sa_sigaction(signal, siginfo, ctx);
+ return;
+ }
+#endif /* CONFIG_LINUX */
+ warn_report("os_mem_prealloc: unrelated SIGBUS detected and ignored");
}
static void *do_touch_pages(void *arg)
void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
Error **errp)
{
+ static gsize initialized;
int ret;
- struct sigaction act, oldact;
size_t hpagesize = qemu_fd_getpagesize(fd);
size_t numpages = DIV_ROUND_UP(memory, hpagesize);
bool use_madv_populate_write;
+ struct sigaction act;
/*
* Sense on every invocation, as MADV_POPULATE_WRITE cannot be used for
use_madv_populate_write = madv_populate_write_possible(area, hpagesize);
if (!use_madv_populate_write) {
+ if (g_once_init_enter(&initialized)) {
+ qemu_mutex_init(&sigbus_mutex);
+ g_once_init_leave(&initialized, 1);
+ }
+
+ qemu_mutex_lock(&sigbus_mutex);
memset(&act, 0, sizeof(act));
+#ifdef CONFIG_LINUX
+ act.sa_sigaction = &sigbus_handler;
+ act.sa_flags = SA_SIGINFO;
+#else /* CONFIG_LINUX */
act.sa_handler = &sigbus_handler;
act.sa_flags = 0;
+#endif /* CONFIG_LINUX */
- ret = sigaction(SIGBUS, &act, &oldact);
+ ret = sigaction(SIGBUS, &act, &sigbus_oldact);
if (ret) {
+ qemu_mutex_unlock(&sigbus_mutex);
error_setg_errno(errp, errno,
"os_mem_prealloc: failed to install signal handler");
return;
}
if (!use_madv_populate_write) {
- ret = sigaction(SIGBUS, &oldact, NULL);
+ ret = sigaction(SIGBUS, &sigbus_oldact, NULL);
if (ret) {
/* Terminate QEMU since it can't recover from error */
perror("os_mem_prealloc: failed to reinstall signal handler");
exit(1);
}
+ qemu_mutex_unlock(&sigbus_mutex);
}
}
#ifdef CONFIG_DEBUG_STACK_USAGE
void *ptr2;
#endif
- size_t pagesz = qemu_real_host_page_size;
+ size_t pagesz = qemu_real_host_page_size();
#ifdef _SC_THREAD_STACK_MIN
/* avoid stacks smaller than _SC_THREAD_STACK_MIN */
long min_stack_sz = sysconf(_SC_THREAD_STACK_MIN);
unsigned int usage;
void *ptr;
- for (ptr = stack + qemu_real_host_page_size; ptr < stack + sz;
+ for (ptr = stack + qemu_real_host_page_size(); ptr < stack + sz;
ptr += sizeof(uint32_t)) {
if (*(uint32_t *)ptr != 0xdeadbeaf) {
break;
action->sa_sigaction(info->ssi_signo, &si, NULL);
}
-#ifndef HOST_NAME_MAX
-# ifdef _POSIX_HOST_NAME_MAX
-# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
-# else
-# define HOST_NAME_MAX 255
-# endif
-#endif
-
-char *qemu_get_host_name(Error **errp)
-{
- long len = -1;
- g_autofree char *hostname = NULL;
-
-#ifdef _SC_HOST_NAME_MAX
- len = sysconf(_SC_HOST_NAME_MAX);
-#endif /* _SC_HOST_NAME_MAX */
-
- if (len < 0) {
- len = HOST_NAME_MAX;
- }
-
- /* Unfortunately, gethostname() below does not guarantee a
- * NULL terminated string. Therefore, allocate one byte more
- * to be sure. */
- hostname = g_new0(char, len + 1);
-
- if (gethostname(hostname, len) < 0) {
- error_setg_errno(errp, errno,
- "cannot get hostname");
- return NULL;
- }
-
- return g_steal_pointer(&hostname);
-}
-
size_t qemu_get_host_physmem(void)
{
#ifdef _SC_PHYS_PAGES
long pages = sysconf(_SC_PHYS_PAGES);
if (pages > 0) {
- if (pages > SIZE_MAX / qemu_real_host_page_size) {
+ if (pages > SIZE_MAX / qemu_real_host_page_size()) {
return SIZE_MAX;
} else {
- return pages * qemu_real_host_page_size;
+ return pages * qemu_real_host_page_size();
}
}
#endif
return 0;
}
+
+int qemu_msync(void *addr, size_t length, int fd)
+{
+ size_t align_mask = ~(qemu_real_host_page_size() - 1);
+
+ /**
+ * There are no strict reqs as per the length of mapping
+ * to be synced. Still the length needs to follow the address
+ * alignment changes. Additionally - round the size to the multiple
+ * of PAGE_SIZE
+ */
+ length += ((uintptr_t)addr & (qemu_real_host_page_size() - 1));
+ length = (length + ~align_mask) & align_mask;
+
+ addr = (void *)((uintptr_t)addr & align_mask);
+
+ return msync(addr, length, MS_SYNC);
+}