mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +00:00
virprocess: Introduce virProcessRunInFork
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> Reviewed-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
parent
24b74d187c
commit
9e8e74f463
@ -2633,6 +2633,7 @@ virProcessKill;
|
||||
virProcessKillPainfully;
|
||||
virProcessKillPainfullyDelay;
|
||||
virProcessNamespaceAvailable;
|
||||
virProcessRunInFork;
|
||||
virProcessRunInMountNamespace;
|
||||
virProcessSchedPolicyTypeFromString;
|
||||
virProcessSchedPolicyTypeToString;
|
||||
|
@ -1165,6 +1165,92 @@ virProcessRunInMountNamespace(pid_t pid,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virProcessRunInForkHelper(int errfd,
|
||||
pid_t ppid,
|
||||
virProcessForkCallback cb,
|
||||
void *opaque)
|
||||
{
|
||||
if (cb(ppid, opaque) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
if (err) {
|
||||
size_t len = strlen(err->message) + 1;
|
||||
ignore_value(safewrite(errfd, err->message, len));
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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. 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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 = virProcessRunInForkHelper(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 == 0) {
|
||||
ret = status == EXIT_CANCELED ? -1 : status;
|
||||
if (ret) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("child reported (status=%d): %s"),
|
||||
status, NULLSTR(buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_FORCE_CLOSE(errfd[0]);
|
||||
VIR_FORCE_CLOSE(errfd[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_SYS_MOUNT_H) && defined(HAVE_UNSHARE)
|
||||
int
|
||||
virProcessSetupPrivateMountNS(void)
|
||||
|
@ -93,6 +93,22 @@ int virProcessRunInMountNamespace(pid_t pid,
|
||||
virProcessNamespaceCallback cb,
|
||||
void *opaque);
|
||||
|
||||
/**
|
||||
* virProcessForkCallback:
|
||||
* @ppid: parent's pid
|
||||
* @opaque: opaque data
|
||||
*
|
||||
* Callback to run in fork()-ed process.
|
||||
*
|
||||
* Returns: 0 on success,
|
||||
* -1 on error (treated as EXIT_CANCELED)
|
||||
*/
|
||||
typedef int (*virProcessForkCallback)(pid_t ppid,
|
||||
void *opaque);
|
||||
|
||||
int virProcessRunInFork(virProcessForkCallback cb,
|
||||
void *opaque);
|
||||
|
||||
int virProcessSetupPrivateMountNS(void);
|
||||
|
||||
int virProcessSetScheduler(pid_t pid,
|
||||
|
Loading…
Reference in New Issue
Block a user