On 1/22/21 11:58 AM, Max Reitz wrote: >>> + if (!self) { >>> + /* >>> + * This SIGUSR2 came from an external source, not from >>> + * qemu_coroutine_new(), so perform the default action. >>> + */ >>> + exit(0); >>> + } >> >> (2) exit() is generally unsafe to call in signal handlers. >> >> We could reason whether or not it is safe in this particular case (POSIX >> describes the exact conditions -- >> <https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03_03>), >> >> but it's much simpler to just call _exit(). >> >> >> (3) "Performing the default action" would be slightly different from >> calling _exit(). When a process is terminated with a signal, the parent >> can distinguish that, when reaping the child. See waitpid() / >> WIFSIGNALED() / WTERMSIG(), versus WIFEXITED() / WEXITSTATUS(). >> >> So for the "default action", we'd have to: >> - restore the SIGUSR2 handler to SIG_DFL, and >> - re-raise the signal for the thread, and >> - because the signal being handled is automatically blocked unless >> SA_NODEFER was set: unblock the signal for the thread. >> >> The pthread_sigmask() call, made for the last step, would be the one >> that would not return. >> >> *However*, all of this complexity is not really useful here. We don't >> really want to simulate being "forcefully terminated" by the unexpected >> (asynchronous) SIGUSR2. We just want to exit. >> >> Therefore, _exit() is fine. But, we should use an exit code different >> from 0, as this is definitely not a pristine exit from QEMU. I'm not >> sure if a convention exists for nonzero exit codes in QEMU; if not, then >> just pass EXIT_FAILURE to _exit(). > > I’m fine with calling _exit(). I hope, Eric is, too (as long as the > comment no longer claims this were the default behavior).
Using _exit(nonzero) is fine by me as long as the comment is accurate. There are signals like SIGINT where you really DO want to terminate by signal rather than using _exit(SIGINT+128), because shells can tell the difference [1]; but SIGUSR2 is not one of the signals where shells special-case their behavior. [1] https://www.cons.org/cracauer/sigint.html > > Given that SIGUSR2 is not something that qemu is prepared to receive > from the outside, EXIT_FAILURE seems right to me. (Even abort() could > be justified, but I don’t think generating a core dump does any good here.) > > (As for qemu-specific exit code conventions, the only ones I know of are > for certain qemu-img subcommands. I’m sure you grepped, too, but I > can’t find anything for the system emulator.) > >> (4) Furthermore, please update the comment, because "perform the default >> action" is not precise. > > Sure, that’s definitely easier than to re-raise SIGUSR2. Works for me as well. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org