aboutsummaryrefslogtreecommitdiff
path: root/util/oslib-posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/oslib-posix.c')
-rw-r--r--util/oslib-posix.c223
1 files changed, 221 insertions, 2 deletions
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index e764416..4ff577e 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -31,7 +31,7 @@
#include <glib/gprintf.h>
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "trace.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -58,6 +58,7 @@
#include <lwp.h>
#endif
+#include "qemu/memalign.h"
#include "qemu/mmap-alloc.h"
#define MAX_MEM_PREALLOC_THREAD_COUNT 16
@@ -111,6 +112,21 @@ int qemu_get_thread_id(void)
#endif
}
+int qemu_kill_thread(int tid, int sig)
+{
+#if defined(__linux__)
+ return syscall(__NR_tgkill, getpid(), tid, sig);
+#elif defined(__FreeBSD__)
+ return thr_kill2(getpid(), tid, sig);
+#elif defined(__NetBSD__)
+ return _lwp_kill(tid, sig);
+#elif defined(__OpenBSD__)
+ return thrkill(tid, sig, NULL);
+#else
+ return kill(tid, sig);
+#endif
+}
+
int qemu_daemon(int nochdir, int noclose)
{
return daemon(nochdir, noclose);
@@ -195,11 +211,21 @@ void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared,
const uint32_t qemu_map_flags = (shared ? QEMU_MAP_SHARED : 0) |
(noreserve ? QEMU_MAP_NORESERVE : 0);
size_t align = QEMU_VMALLOC_ALIGN;
+#ifndef EMSCRIPTEN
void *ptr = qemu_ram_mmap(-1, size, align, qemu_map_flags, 0);
if (ptr == MAP_FAILED) {
return NULL;
}
+#else
+ /*
+ * qemu_ram_mmap is not implemented for Emscripten. Use qemu_memalign
+ * for the anonymous allocation. noreserve is ignored as there is no swap
+ * space on Emscripten, and shared is ignored as there is no other
+ * processes on Emscripten.
+ */
+ void *ptr = qemu_memalign(align, size);
+#endif
if (alignment) {
*alignment = align;
@@ -212,7 +238,16 @@ void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared,
void qemu_anon_ram_free(void *ptr, size_t size)
{
trace_qemu_anon_ram_free(ptr, size);
+#ifndef EMSCRIPTEN
qemu_ram_munmap(-1, ptr, size);
+#else
+ /*
+ * qemu_ram_munmap is not implemented for Emscripten and qemu_memalign
+ * was used for the allocation. Use the corresponding freeing function
+ * here.
+ */
+ qemu_vfree(ptr);
+#endif
}
void qemu_socket_set_block(int fd)
@@ -263,7 +298,7 @@ int qemu_socketpair(int domain, int type, int protocol, int sv[2])
return ret;
}
#endif
- ret = socketpair(domain, type, protocol, sv);;
+ ret = socketpair(domain, type, protocol, sv);
if (ret == 0) {
qemu_set_cloexec(sv[0]);
qemu_set_cloexec(sv[1]);
@@ -573,7 +608,15 @@ bool qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
{
static gsize initialized;
int ret;
+#ifndef EMSCRIPTEN
size_t hpagesize = qemu_fd_getpagesize(fd);
+#else
+ /*
+ * mmap-alloc.c is excluded from Emscripten build, so qemu_fd_getpagesize
+ * is unavailable. Fallback to the lower level implementation.
+ */
+ size_t hpagesize = qemu_real_host_page_size();
+#endif
size_t numpages = DIV_ROUND_UP(sz, hpagesize);
bool use_madv_populate_write;
struct sigaction act;
@@ -807,3 +850,179 @@ int qemu_msync(void *addr, size_t length, int fd)
return msync(addr, length, MS_SYNC);
}
+
+static bool qemu_close_all_open_fd_proc(const int *skip, unsigned int nskip)
+{
+ struct dirent *de;
+ int fd, dfd;
+ DIR *dir;
+ unsigned int skip_start = 0, skip_end = nskip;
+
+ dir = opendir("/proc/self/fd");
+ if (!dir) {
+ /* If /proc is not mounted, there is nothing that can be done. */
+ return false;
+ }
+ /* Avoid closing the directory. */
+ dfd = dirfd(dir);
+
+ for (de = readdir(dir); de; de = readdir(dir)) {
+ bool close_fd = true;
+
+ if (de->d_name[0] == '.') {
+ continue;
+ }
+ fd = atoi(de->d_name);
+ if (fd == dfd) {
+ continue;
+ }
+
+ for (unsigned int i = skip_start; i < skip_end; i++) {
+ if (fd < skip[i]) {
+ /* We are below the next skipped fd, break */
+ break;
+ } else if (fd == skip[i]) {
+ close_fd = false;
+ /* Restrict the range as we found fds matching start/end */
+ if (i == skip_start) {
+ skip_start++;
+ } else if (i == skip_end) {
+ skip_end--;
+ }
+ break;
+ }
+ }
+
+ if (close_fd) {
+ close(fd);
+ }
+ }
+ closedir(dir);
+
+ return true;
+}
+
+static bool qemu_close_all_open_fd_close_range(const int *skip,
+ unsigned int nskip,
+ int open_max)
+{
+#ifdef CONFIG_CLOSE_RANGE
+ int max_fd = open_max - 1;
+ int first = 0, last;
+ unsigned int cur_skip = 0;
+ int ret;
+
+ do {
+ /* Find the start boundary of the range to close */
+ while (cur_skip < nskip && first == skip[cur_skip]) {
+ cur_skip++;
+ first++;
+ }
+
+ /* Find the upper boundary of the range to close */
+ last = max_fd;
+ if (cur_skip < nskip) {
+ last = skip[cur_skip] - 1;
+ last = MIN(last, max_fd);
+ }
+
+ /* With the adjustments to the range, we might be done. */
+ if (first > last) {
+ break;
+ }
+
+ ret = close_range(first, last, 0);
+ if (ret < 0) {
+ return false;
+ }
+
+ first = last + 1;
+ } while (last < max_fd);
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+static void qemu_close_all_open_fd_fallback(const int *skip, unsigned int nskip,
+ int open_max)
+{
+ unsigned int cur_skip = 0;
+
+ /* Fallback */
+ for (int i = 0; i < open_max; i++) {
+ if (cur_skip < nskip && i == skip[cur_skip]) {
+ cur_skip++;
+ continue;
+ }
+ close(i);
+ }
+}
+
+/*
+ * Close all open file descriptors.
+ */
+void qemu_close_all_open_fd(const int *skip, unsigned int nskip)
+{
+ int open_max = sysconf(_SC_OPEN_MAX);
+
+ assert(skip != NULL || nskip == 0);
+
+ if (!qemu_close_all_open_fd_close_range(skip, nskip, open_max) &&
+ !qemu_close_all_open_fd_proc(skip, nskip)) {
+ qemu_close_all_open_fd_fallback(skip, nskip, open_max);
+ }
+}
+
+int qemu_shm_alloc(size_t size, Error **errp)
+{
+ g_autoptr(GString) shm_name = g_string_new(NULL);
+ int fd, oflag, cur_sequence;
+ static int sequence;
+ mode_t mode;
+
+ cur_sequence = qatomic_fetch_inc(&sequence);
+
+ /*
+ * Let's use `mode = 0` because we don't want other processes to open our
+ * memory unless we share the file descriptor with them.
+ */
+ mode = 0;
+ oflag = O_RDWR | O_CREAT | O_EXCL;
+
+ /*
+ * Some operating systems allow creating anonymous POSIX shared memory
+ * objects (e.g. FreeBSD provides the SHM_ANON constant), but this is not
+ * defined by POSIX, so let's create a unique name.
+ *
+ * From Linux's shm_open(3) man-page:
+ * For portable use, a shared memory object should be identified
+ * by a name of the form /somename;"
+ */
+ g_string_printf(shm_name, "/qemu-" FMT_pid "-shm-%d", getpid(),
+ cur_sequence);
+
+ fd = shm_open(shm_name->str, oflag, mode);
+ if (fd < 0) {
+ error_setg_errno(errp, errno,
+ "failed to create POSIX shared memory");
+ return -1;
+ }
+
+ /*
+ * We have the file descriptor, so we no longer need to expose the
+ * POSIX shared memory object. However it will remain allocated as long as
+ * there are file descriptors pointing to it.
+ */
+ shm_unlink(shm_name->str);
+
+ if (ftruncate(fd, size) == -1) {
+ error_setg_errno(errp, errno,
+ "failed to resize POSIX shared memory to %zu", size);
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}