|  | /* | 
|  | * 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; | 
|  |  | 
|  | 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. | 
|  | */ | 
|  | qemu_close_all_open_fd(NULL, 0); | 
|  |  | 
|  | /* 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); | 
|  | } |