summary refs log tree commit diff stats
path: root/system/async-teardown.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2023-10-09 10:11:17 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2023-10-09 10:11:18 -0400
commit1527c6b6fa6c6775523287e33f78b41afc7ba46c (patch)
treee245ed1f0f1856b800b391e22da9d09b21950540 /system/async-teardown.c
parentf7294103560260ff09ffdf316cf6ba6d4e368d85 (diff)
parent912eef205ae9ccfd477c343a51a7c2dcfae2ba43 (diff)
downloadfocaccia-qemu-1527c6b6fa6c6775523287e33f78b41afc7ba46c.tar.gz
focaccia-qemu-1527c6b6fa6c6775523287e33f78b41afc7ba46c.zip
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* util/log: re-allow switching away from stderr log file
* finish audio configuration rework
* cleanup HVF stubs
* remove more mentions of softmmu

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmUi/kIUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroOXWwf/YW16QMzqdAPVHYRf9NcCneRF16El
# t3lEod0q0sHhchPbh9e04aKbh+oBNeWu9sFyTl11Fwsi+DGmp/b28ziva75/4rfd
# h5N9aX/z2jwPqy93IwPDu3soKXCCgTK+ywtD/5GLQwBGqxs7W2xUEEb7eCnVefHa
# zwL3MOUqPICeqOnR1TNw9k3N3veF04D+rmchTwbAjAmx1f8EI+mK9VlGK9V8TUjP
# 3HjpZYJluc0a92lR5VONJ7V25QfttsjLysTgpFwVAQPS6Frzatc/hWclfLYgw9vl
# 2Irk83FV8gXPRl0XKNcqSDsv6h/yGP6TDFIB8QwRSRGBqIQi5aOlfBJzsQ==
# =qbm7
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 08 Oct 2023 15:08:50 EDT
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (25 commits)
  audio, qtest: get rid of QEMU_AUDIO_DRV
  audio: reintroduce default audio backend for VNC
  audio: do not use first -audiodev as default audio device
  audio: extend -audio to allow creating a default backend
  audio: extract audio_define_default
  audio: disable default backends if -audio/-audiodev is used
  audio: error hints need a trailing \n
  cutils: squelch compiler warnings with custom paths
  configure: change $softmmu to $system
  system: Rename softmmu/ directory as system/
  meson: Rename target_softmmu_arch -> target_system_arch
  meson: Rename softmmu_mods -> system_mods
  target/i386: Rename i386_softmmu_kvm_ss -> i386_kvm_ss
  semihosting: Rename softmmu_FOO_user() -> uaccess_FOO_user()
  gdbstub: Rename 'softmmu' -> 'system'
  accel: Rename accel_softmmu* -> accel_system*
  tcg: Correct invalid mentions of 'softmmu' by 'system-mode'
  fuzz: Correct invalid mentions of 'softmmu' by 'system'
  cpu: Correct invalid mentions of 'softmmu' by 'system-mode'
  travis-ci: Correct invalid mentions of 'softmmu' by 'system'
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'system/async-teardown.c')
-rw-r--r--system/async-teardown.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/system/async-teardown.c b/system/async-teardown.c
new file mode 100644
index 0000000000..396963c091
--- /dev/null
+++ b/system/async-teardown.c
@@ -0,0 +1,143 @@
+/*
+ * Asynchronous teardown
+ *
+ * Copyright IBM, Corp. 2022
+ *
+ * Authors:
+ *  Claudio Imbrenda <imbrenda@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version.  See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include <dirent.h>
+#include <sys/prctl.h>
+#include <sched.h>
+
+#include "qemu/async-teardown.h"
+
+#ifdef _SC_THREAD_STACK_MIN
+#define CLONE_STACK_SIZE sysconf(_SC_THREAD_STACK_MIN)
+#else
+#define CLONE_STACK_SIZE 16384
+#endif
+
+static pid_t the_ppid;
+
+/*
+ * Close all open file descriptors.
+ */
+static void close_all_open_fd(void)
+{
+    struct dirent *de;
+    int fd, dfd;
+    DIR *dir;
+
+#ifdef CONFIG_CLOSE_RANGE
+    int r = close_range(0, ~0U, 0);
+    if (!r) {
+        /* Success, no need to try other ways. */
+        return;
+    }
+#endif
+
+    dir = opendir("/proc/self/fd");
+    if (!dir) {
+        /* If /proc is not mounted, there is nothing that can be done. */
+        return;
+    }
+    /* Avoid closing the directory. */
+    dfd = dirfd(dir);
+
+    for (de = readdir(dir); de; de = readdir(dir)) {
+        fd = atoi(de->d_name);
+        if (fd != dfd) {
+            close(fd);
+        }
+    }
+    closedir(dir);
+}
+
+static void hup_handler(int signal)
+{
+    /* Check every second if this process has been reparented. */
+    while (the_ppid == getppid()) {
+        /* sleep() is safe to use in a signal handler. */
+        sleep(1);
+    }
+
+    /* At this point the parent process has terminated completely. */
+    _exit(0);
+}
+
+static int async_teardown_fn(void *arg)
+{
+    struct sigaction sa = { .sa_handler = hup_handler };
+    sigset_t hup_signal;
+    char name[16];
+
+    /* Set a meaningful name for this process. */
+    snprintf(name, 16, "cleanup/%d", the_ppid);
+    prctl(PR_SET_NAME, (unsigned long)name);
+
+    /*
+     * Close all file descriptors that might have been inherited from the
+     * main qemu process when doing clone, needed to make libvirt happy.
+     * Not using close_range for increased compatibility with older kernels.
+     */
+    close_all_open_fd();
+
+    /* Set up a handler for SIGHUP and unblock SIGHUP. */
+    sigaction(SIGHUP, &sa, NULL);
+    sigemptyset(&hup_signal);
+    sigaddset(&hup_signal, SIGHUP);
+    sigprocmask(SIG_UNBLOCK, &hup_signal, NULL);
+
+    /* Ask to receive SIGHUP when the parent dies. */
+    prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+    /*
+     * Sleep forever, unless the parent process has already terminated. The
+     * only interruption can come from the SIGHUP signal, which in normal
+     * operation is received when the parent process dies.
+     */
+    if (the_ppid == getppid()) {
+        pause();
+    }
+
+    /* At this point the parent process has terminated completely. */
+    _exit(0);
+}
+
+/*
+ * Allocate a new stack of a reasonable size, and return a pointer to its top.
+ */
+static void *new_stack_for_clone(void)
+{
+    size_t stack_size = CLONE_STACK_SIZE;
+    char *stack_ptr;
+
+    /* Allocate a new stack and get a pointer to its top. */
+    stack_ptr = qemu_alloc_stack(&stack_size);
+    stack_ptr += stack_size;
+
+    return stack_ptr;
+}
+
+/*
+ * Block all signals, start (clone) a new process sharing the address space
+ * with qemu (CLONE_VM), then restore signals.
+ */
+void init_async_teardown(void)
+{
+    sigset_t all_signals, old_signals;
+
+    the_ppid = getpid();
+
+    sigfillset(&all_signals);
+    sigprocmask(SIG_BLOCK, &all_signals, &old_signals);
+    clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL);
+    sigprocmask(SIG_SETMASK, &old_signals, NULL);
+}