#include "qemu/thread.h"
#include <libgen.h>
#include "qemu/cutils.h"
-#include "qemu/compiler.h"
#include "qemu/units.h"
+#include "qemu/thread-context.h"
#ifdef CONFIG_LINUX
#include <sys/syscall.h>
#ifdef __FreeBSD__
#include <sys/thr.h>
-#include <sys/types.h>
#include <sys/user.h>
#include <libutil.h>
#endif
#include "qemu/mmap-alloc.h"
-#ifdef CONFIG_DEBUG_STACK_USAGE
-#include "qemu/error-report.h"
-#endif
-
#define MAX_MEM_PREALLOC_THREAD_COUNT 16
struct MemsetThread;
assert(f != -1);
}
+int qemu_socketpair(int domain, int type, int protocol, int sv[2])
+{
+ int ret;
+
+#ifdef SOCK_CLOEXEC
+ ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
+ if (ret != -1 || errno != EINVAL) {
+ return ret;
+ }
+#endif
+ ret = socketpair(domain, type, protocol, sv);;
+ if (ret == 0) {
+ qemu_set_cloexec(sv[0]);
+ qemu_set_cloexec(sv[1]);
+ }
+
+ return ret;
+}
+
char *
qemu_get_local_state_dir(void)
{
return;
}
#endif /* CONFIG_LINUX */
- warn_report("os_mem_prealloc: unrelated SIGBUS detected and ignored");
+ warn_report("qemu_prealloc_mem: unrelated SIGBUS detected and ignored");
}
static void *do_touch_pages(void *arg)
}
static inline int get_memset_num_threads(size_t hpagesize, size_t numpages,
- int smp_cpus)
+ int max_threads)
{
long host_procs = sysconf(_SC_NPROCESSORS_ONLN);
int ret = 1;
if (host_procs > 0) {
- ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), smp_cpus);
+ ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), max_threads);
}
/* Especially with gigantic pages, don't create more threads than pages. */
}
static int touch_all_pages(char *area, size_t hpagesize, size_t numpages,
- int smp_cpus, bool use_madv_populate_write)
+ int max_threads, ThreadContext *tc,
+ bool use_madv_populate_write)
{
static gsize initialized = 0;
MemsetContext context = {
- .num_threads = get_memset_num_threads(hpagesize, numpages, smp_cpus),
+ .num_threads = get_memset_num_threads(hpagesize, numpages, max_threads),
};
size_t numpages_per_thread, leftover;
void *(*touch_fn)(void *);
context.threads[i].numpages = numpages_per_thread + (i < leftover);
context.threads[i].hpagesize = hpagesize;
context.threads[i].context = &context;
- qemu_thread_create(&context.threads[i].pgthread, "touch_pages",
- touch_fn, &context.threads[i],
- QEMU_THREAD_JOINABLE);
+ if (tc) {
+ thread_context_create_thread(tc, &context.threads[i].pgthread,
+ "touch_pages",
+ touch_fn, &context.threads[i],
+ QEMU_THREAD_JOINABLE);
+ } else {
+ qemu_thread_create(&context.threads[i].pgthread, "touch_pages",
+ touch_fn, &context.threads[i],
+ QEMU_THREAD_JOINABLE);
+ }
addr += context.threads[i].numpages * hpagesize;
}
errno != EINVAL;
}
-void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
- Error **errp)
+bool qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
+ ThreadContext *tc, Error **errp)
{
static gsize initialized;
int ret;
size_t hpagesize = qemu_fd_getpagesize(fd);
- size_t numpages = DIV_ROUND_UP(memory, hpagesize);
+ size_t numpages = DIV_ROUND_UP(sz, hpagesize);
bool use_madv_populate_write;
struct sigaction act;
+ bool rv = true;
/*
* Sense on every invocation, as MADV_POPULATE_WRITE cannot be used for
if (ret) {
qemu_mutex_unlock(&sigbus_mutex);
error_setg_errno(errp, errno,
- "os_mem_prealloc: failed to install signal handler");
- return;
+ "qemu_prealloc_mem: failed to install signal handler");
+ return false;
}
}
/* touch pages simultaneously */
- ret = touch_all_pages(area, hpagesize, numpages, smp_cpus,
+ ret = touch_all_pages(area, hpagesize, numpages, max_threads, tc,
use_madv_populate_write);
if (ret) {
error_setg_errno(errp, -ret,
- "os_mem_prealloc: preallocating memory failed");
+ "qemu_prealloc_mem: preallocating memory failed");
+ rv = false;
}
if (!use_madv_populate_write) {
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");
+ perror("qemu_prealloc_mem: failed to reinstall signal handler");
exit(1);
}
qemu_mutex_unlock(&sigbus_mutex);
}
+ return rv;
}
char *qemu_get_pid_name(pid_t pid)
}
-pid_t qemu_fork(Error **errp)
-{
- sigset_t oldmask, newmask;
- struct sigaction sig_action;
- int saved_errno;
- pid_t pid;
-
- /*
- * Need to block signals now, so that child process can safely
- * kill off caller's signal handlers without a race.
- */
- sigfillset(&newmask);
- if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
- error_setg_errno(errp, errno,
- "cannot block signals");
- return -1;
- }
-
- pid = fork();
- saved_errno = errno;
-
- if (pid < 0) {
- /* attempt to restore signal mask, but ignore failure, to
- * avoid obscuring the fork failure */
- (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
- error_setg_errno(errp, saved_errno,
- "cannot fork child process");
- errno = saved_errno;
- return -1;
- } else if (pid) {
- /* parent process */
-
- /* Restore our original signal mask now that the child is
- * safely running. Only documented failures are EFAULT (not
- * possible, since we are using just-grabbed mask) or EINVAL
- * (not possible, since we are using correct arguments). */
- (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
- } else {
- /* child process */
- size_t i;
-
- /* Clear out all signal handlers from parent so nothing
- * unexpected can happen in our child once we unblock
- * signals */
- sig_action.sa_handler = SIG_DFL;
- sig_action.sa_flags = 0;
- sigemptyset(&sig_action.sa_mask);
-
- for (i = 1; i < NSIG; i++) {
- /* Only possible errors are EFAULT or EINVAL The former
- * won't happen, the latter we expect, so no need to check
- * return value */
- (void)sigaction(i, &sig_action, NULL);
- }
-
- /* Unmask all signals in child, since we've no idea what the
- * caller's done with their signal mask and don't want to
- * propagate that to children */
- sigemptyset(&newmask);
- if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
- Error *local_err = NULL;
- error_setg_errno(&local_err, errno,
- "cannot unblock signals");
- error_report_err(local_err);
- _exit(1);
- }
- }
- return pid;
-}
-
void *qemu_alloc_stack(size_t *sz)
{
- void *ptr, *guardpage;
+ void *ptr;
int flags;
#ifdef CONFIG_DEBUG_STACK_USAGE
void *ptr2;
abort();
}
-#if defined(HOST_IA64)
- /* separate register stack */
- guardpage = ptr + (((*sz - pagesz) / 2) & ~pagesz);
-#elif defined(HOST_HPPA)
- /* stack grows up */
- guardpage = ptr + *sz - pagesz;
-#else
- /* stack grows down */
- guardpage = ptr;
-#endif
- if (mprotect(guardpage, pagesz, PROT_NONE) != 0) {
+ /* Stack grows down -- guard page at the bottom. */
+ if (mprotect(ptr, pagesz, PROT_NONE) != 0) {
perror("failed to set up stack guard page");
abort();
}
/*
* Disable CFI checks.
- * We are going to call a signal hander directly. Such handler may or may not
+ * We are going to call a signal handler directly. Such handler may or may not
* have been defined in our binary, so there's no guarantee that the pointer
* used to set the handler is a cfi-valid pointer. Since the handlers are
* stored in kernel memory, changing the handler to an attacker-defined