/* * SPDX-License-Identifier: BSD-3-Clause * Originally derived from nbdkit common/utils/exit-with-parent.c * Copyright Red Hat * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Red Hat nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Implement the --exit-with-parent feature on operating systems which * support it. */ #include "qemu/osdep.h" #include "qemu/exit-with-parent.h" #if defined(__linux__) #include /* * Send SIGTERM to self when the parent exits. This will cause * qemu_system_killed() to be called. * * PR_SET_PDEATHSIG has been defined since Linux 2.1.57. */ int set_exit_with_parent(void) { return prctl(PR_SET_PDEATHSIG, SIGTERM); } #elif defined(__FreeBSD__) #include /* * Send SIGTERM to self when the parent exits. This will cause * qemu_system_killed() to be called. * * PROC_PDEATHSIG_CTL has been defined since FreeBSD 11.2. */ int set_exit_with_parent(void) { const int sig = SIGTERM; return procctl(P_PID, 0, PROC_PDEATHSIG_CTL, (void *) &sig); } #elif defined(__APPLE__) /* For macOS. */ #include "qemu/thread.h" #include "qemu/error-report.h" #include "system/runstate.h" #include static void * exit_with_parent_loop(void *vp) { const pid_t ppid = getppid(); int fd; struct kevent kev, res[1]; int r; /* Register the kevent to wait for ppid to exit. */ fd = kqueue(); if (fd == -1) { error_report("exit_with_parent_loop: kqueue: %m"); return NULL; } EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL); if (kevent(fd, &kev, 1, NULL, 0, NULL) == -1) { error_report("exit_with_parent_loop: kevent: %m"); close(fd); return NULL; } /* Wait for the kevent to happen. */ r = kevent(fd, 0, 0, res, 1, NULL); if (r == 1 && res[0].ident == ppid) { /* Behave like Linux and FreeBSD above, as if SIGTERM was sent */ qemu_system_killed(SIGTERM, ppid); } close(fd); return NULL; } int set_exit_with_parent(void) { QemuThread exit_with_parent_thread; /* * We have to block waiting for kevent, so that requires that we * start a background thread. */ qemu_thread_create(&exit_with_parent_thread, "exit-parent", exit_with_parent_loop, NULL, QEMU_THREAD_DETACHED); return 0; } #else /* any platform that doesn't support this function */ int set_exit_with_parent(void) { g_assert_not_reached(); } #endif