
On Wed, Oct 17, 2018 at 11:06:43AM +0200, Michal Privoznik wrote:
This new helper can be used to spawn a child process and run passed callback from it. This will come handy esp. if the callback is not thread safe.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virprocess.c | 81 ++++++++++++++++++++++++++++++++++++++++ src/util/virprocess.h | 16 ++++++++ 3 files changed, 98 insertions(+)
+/** + * virProcessRunInFork: + * @cb: callback to run + * @opaque: opaque data to @cb + * + * Do the fork and run @cb in the child. This can be used when + * @cb does something thread unsafe, for instance. However, due + * to possible signal propagation @cb should only call async + * signal safe functions. On return, the returned value is either + * -1 with error message reported if something went bad in the + * parent, if child has died from a signal or if the child + * returned EXIT_CANCELED. Otherwise the returned value is the + * exit status of the child.
Instead of; However, due to possible signal propagation @cb should only call async signal safe functions. Use: All signals will be reset to have their platform default handlers and unmasked. @cb must only use async signal safe functions. In particular no mutexes should be used in @cb, unless steps were taken before forking to guarantee a predictable state. @cb must not exec any external binaries, instead virCommand/virExec should be used for that purpose.
+ */ +int +virProcessRunInFork(virProcessForkCallback cb, + void *opaque) +{ + int ret = -1; + pid_t child = -1; + pid_t parent = getpid(); + int errfd[2] = { -1, -1 }; + + if (pipe2(errfd, O_CLOEXEC) < 0) { + virReportSystemError(errno, "%s", + _("Cannot create pipe for child")); + return -1; + } + + if ((child = virFork()) < 0) + goto cleanup; + + if (child == 0) { + VIR_FORCE_CLOSE(errfd[0]); + ret = virProcessForkHelper(errfd[1], parent, cb, opaque); + VIR_FORCE_CLOSE(errfd[1]); + _exit(ret < 0 ? EXIT_CANCELED : ret); + } else { + int status; + VIR_AUTOFREE(char *) buf = NULL; + + VIR_FORCE_CLOSE(errfd[1]); + ignore_value(virFileReadHeaderFD(errfd[0], 1024, &buf)); + ret = virProcessWait(child, &status, false); + if (!ret) { + ret = status == EXIT_CANCELED ? -1 : status; + if (ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("child reported: %s"), + NULLSTR(buf));
It would be desirable to include the exit status value in the message
+ } + } + } + + cleanup: + VIR_FORCE_CLOSE(errfd[0]); + VIR_FORCE_CLOSE(errfd[1]); + return ret; +}
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|