[libvirt] [PATCH 1/8] Allow handshake with child process during startup
Eric Blake
eblake at redhat.com
Thu May 12 22:28:11 UTC 2011
On 05/11/2011 03:33 AM, Daniel P. Berrange wrote:
> Allow the parent process to perform a bi-directional handshake
> with the child process during fork/exec. The child process
> will fork and do its initial setup. Immediately prior to the
> exec(), it will stop & wait for a handshake from the parent
> process. The parent process will spawn the child and wait
> until the child reaches the handshake point. It will do
> whatever extra setup work is required, before signalling the
> child to continue.
>
> The implementation of this is done using two pairs of blocking
> pipes. The first pair is used to block the parent, until the
> child writes a single byte. Then the second pair pair is used
> to block the child, until the parent confirms with another
> single byte.
>
> * src/util/command.c, src/util/command.h,
> src/libvirt_private.syms: Add APIs to perform a handshake
> ---
> src/libvirt_private.syms | 3 +
> src/util/command.c | 161 +++++++++++++++++++++++++++++++++++++++++++++-
> src/util/command.h | 22 ++++++
> 3 files changed, 185 insertions(+), 1 deletions(-)
Hopefully there aren't too many rebase issues if Cole's virCommand
cleanup series goes in first.
> @@ -1255,6 +1315,10 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
> FD_CLR(i, &cmd->transfer);
> }
> }
> + if (cmd->handshake) {
> + VIR_FORCE_CLOSE(cmd->handshakeWait[1]);
> + VIR_FORCE_CLOSE(cmd->handshakeNotify[0]);
> + }
You don't need this hunk if you use virCommandTransferFD below...
> @@ -1395,6 +1459,94 @@ virCommandAbort(virCommandPtr cmd ATTRIBUTE_UNUSED)
> }
> #endif
>
> +
> +void virCommandRequireHandshake(virCommandPtr cmd)
> +{
> + if (!cmd || cmd->has_error)
> + return;
Avoid clobbering existing fds and causing an fd leak, by adding:
if (cmd->handshake) {
cmd->has_error = -1;
VIR_DEBUG("cannot require handshake twice");
return;
}
> +
> + if (pipe(cmd->handshakeWait) < 0) {
> + cmd->has_error = errno;
> + return;
> + }
> + if (pipe(cmd->handshakeNotify) < 0) {
> + VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
> + VIR_FORCE_CLOSE(cmd->handshakeWait[1]);
> + cmd->has_error = errno;
> + return;
> + }
> +
> + VIR_DEBUG("Transfer handshake wait=%d notify=%d",
> + cmd->handshakeWait[1], cmd->handshakeNotify[0]);
> + virCommandPreserveFD(cmd, cmd->handshakeWait[1]);
> + virCommandPreserveFD(cmd, cmd->handshakeNotify[0]);
...here's where to use virCommandTransferFD, for slightly less bookkeeping.
> +int virCommandHandshakeWait(virCommandPtr cmd)
> +{
> + char c;
> + int rv;
> + if (!cmd ||cmd->has_error == ENOMEM) {
> + virReportOOMError();
> + return -1;
> + }
> + if (cmd->has_error) {
Change to this, to avoid calling saferead on an invalid fd if no one
called virCommandRequireHandshake:
if (cmd->has_error || !cmd->handshake)
Also, on completion you either need to set cmd->handshake = false or
call VIR_CLOSE the fd on completion; if you do the latter, then on entry
you should check that the fd is not -1, so that we ensure no one calls
this method twice for a single child process.
> + if (c != '1') {
> + char *msg;
> + ssize_t len;
> + if (VIR_ALLOC_N(msg, 1024) < 0) {
> + virReportOOMError();
Should we stack-allocate this, to minimize the chance of a malloc
failure while reporting the child's failure?
> +
> +int virCommandHandshakeNotify(virCommandPtr cmd)
> +{
> + char c = '1';
> + if (!cmd ||cmd->has_error == ENOMEM) {
> + virReportOOMError();
> + return -1;
> + }
> + if (cmd->has_error) {
if (cmd->has_error || !cmd->handshake)
--
Eric Blake eblake at redhat.com +1-801-349-2682
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 619 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20110512/e679af16/attachment-0001.sig>
More information about the libvir-list
mailing list