#else
# define QEMU_VMALLOC_ALIGN getpagesize()
#endif
+#define HUGETLBFS_MAGIC 0x958458f6
#include <termios.h>
#include <unistd.h>
#include "qemu/sockets.h"
#include <sys/mman.h>
#include <libgen.h>
+#include <setjmp.h>
+#include <sys/signal.h>
#ifdef CONFIG_LINUX
#include <sys/syscall.h>
+#include <sys/vfs.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
#endif
int qemu_get_thread_id(void)
return ptr;
}
-void *qemu_memalign(size_t alignment, size_t size)
+void *qemu_try_memalign(size_t alignment, size_t size)
{
void *ptr;
int ret;
ret = posix_memalign(&ptr, alignment, size);
if (ret != 0) {
- fprintf(stderr, "Failed to allocate %zu B: %s\n",
- size, strerror(ret));
- abort();
+ errno = ret;
+ ptr = NULL;
}
#elif defined(CONFIG_BSD)
- ptr = qemu_oom_check(valloc(size));
+ ptr = valloc(size);
#else
- ptr = qemu_oom_check(memalign(alignment, size));
+ 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)
+void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment)
{
size_t align = QEMU_VMALLOC_ALIGN;
size_t total = size + align - getpagesize();
return NULL;
}
+ if (alignment) {
+ *alignment = align;
+ }
ptr += offset;
total -= offset;
{
return g_strdup(exec_dir);
}
+
+static sigjmp_buf sigjump;
+
+static void sigbus_handler(int signal)
+{
+ siglongjmp(sigjump, 1);
+}
+
+static size_t fd_getpagesize(int fd)
+{
+#ifdef CONFIG_LINUX
+ struct statfs fs;
+ int ret;
+
+ if (fd != -1) {
+ do {
+ ret = fstatfs(fd, &fs);
+ } while (ret != 0 && errno == EINTR);
+
+ if (ret == 0 && fs.f_type == HUGETLBFS_MAGIC) {
+ return fs.f_bsize;
+ }
+ }
+#endif
+
+ return getpagesize();
+}
+
+void os_mem_prealloc(int fd, char *area, size_t memory)
+{
+ int ret;
+ struct sigaction act, oldact;
+ sigset_t set, oldset;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = &sigbus_handler;
+ act.sa_flags = 0;
+
+ ret = sigaction(SIGBUS, &act, &oldact);
+ if (ret) {
+ perror("os_mem_prealloc: failed to install signal handler");
+ exit(1);
+ }
+
+ /* unblock SIGBUS */
+ sigemptyset(&set);
+ sigaddset(&set, SIGBUS);
+ pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
+
+ if (sigsetjmp(sigjump, 1)) {
+ fprintf(stderr, "os_mem_prealloc: Insufficient free host memory "
+ "pages available to allocate guest RAM\n");
+ exit(1);
+ } else {
+ int i;
+ size_t hpagesize = fd_getpagesize(fd);
+
+ /* MAP_POPULATE silently ignores failures */
+ memory = (memory + hpagesize - 1) & -hpagesize;
+ for (i = 0; i < (memory / hpagesize); i++) {
+ memset(area + (hpagesize * i), 0, 1);
+ }
+
+ ret = sigaction(SIGBUS, &oldact, NULL);
+ if (ret) {
+ perror("os_mem_prealloc: failed to reinstall signal handler");
+ exit(1);
+ }
+
+ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ }
+}