()
| 226 | } |
| 227 | |
| 228 | func (p *windowsProcess) waitInternal() { |
| 229 | // put this on the bottom of the defer stack since the next defer can write to p.cmdErr |
| 230 | defer close(p.cmdDone) |
| 231 | defer func() { |
| 232 | // close the pseudoconsole handle when the process exits, if it hasn't already been closed. |
| 233 | // this is important because the PseudoConsole (conhost.exe) holds the write-end |
| 234 | // of the output pipe. If it is not closed, reads on that pipe will block, even though |
| 235 | // the command has exited. |
| 236 | // c.f. https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/ |
| 237 | p.pw.closeMutex.Lock() |
| 238 | defer p.pw.closeMutex.Unlock() |
| 239 | |
| 240 | err := p.pw.closeConsoleNoLock() |
| 241 | // if we already have an error from the command, prefer that error |
| 242 | // but if the command succeeded and closing the PseudoConsole fails |
| 243 | // then record that error so that we have a chance to see it |
| 244 | if err != nil && p.cmdErr == nil { |
| 245 | p.cmdErr = err |
| 246 | } |
| 247 | }() |
| 248 | |
| 249 | state, err := p.proc.Wait() |
| 250 | if err != nil { |
| 251 | p.cmdErr = err |
| 252 | return |
| 253 | } |
| 254 | if !state.Success() { |
| 255 | p.cmdErr = &exec.ExitError{ProcessState: state} |
| 256 | return |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | func (p *windowsProcess) Wait() error { |
| 261 | <-p.cmdDone |
no test coverage detected