mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 11:31:16 +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;
|
virProcessKillPainfully;
|
||||||
virProcessKillPainfullyDelay;
|
virProcessKillPainfullyDelay;
|
||||||
virProcessNamespaceAvailable;
|
virProcessNamespaceAvailable;
|
||||||
|
virProcessRunInFork;
|
||||||
virProcessRunInMountNamespace;
|
virProcessRunInMountNamespace;
|
||||||
virProcessSchedPolicyTypeFromString;
|
virProcessSchedPolicyTypeFromString;
|
||||||
virProcessSchedPolicyTypeToString;
|
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)
|
#if defined(HAVE_SYS_MOUNT_H) && defined(HAVE_UNSHARE)
|
||||||
int
|
int
|
||||||
virProcessSetupPrivateMountNS(void)
|
virProcessSetupPrivateMountNS(void)
|
||||||
|
@ -93,6 +93,22 @@ int virProcessRunInMountNamespace(pid_t pid,
|
|||||||
virProcessNamespaceCallback cb,
|
virProcessNamespaceCallback cb,
|
||||||
void *opaque);
|
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 virProcessSetupPrivateMountNS(void);
|
||||||
|
|
||||||
int virProcessSetScheduler(pid_t pid,
|
int virProcessSetScheduler(pid_t pid,
|
||||||
|
Loading…
Reference in New Issue
Block a user