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@xxxxxxxxxx +1-801-349-2682 Libvirt virtualization library http://libvirt.org
Attachment:
signature.asc
Description: OpenPGP digital signature
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list