| 427 | } |
| 428 | |
| 429 | func (m *monitor) invoke(ctx context.Context, pid string, cfg *build.InvokeConfig) error { |
| 430 | m.muxIO.Enable(1) |
| 431 | defer m.muxIO.Disable(1) |
| 432 | if err := m.muxIO.SwitchTo(1); err != nil { |
| 433 | return errors.Errorf("failed to switch to process IO: %v", err) |
| 434 | } |
| 435 | invokeCtx, invokeCancel := context.WithCancelCause(ctx) |
| 436 | |
| 437 | containerIn, containerOut := ioset.Pipe() |
| 438 | m.invokeIO.SetOut(&containerOut) |
| 439 | waitInvokeDoneCh := make(chan struct{}) |
| 440 | var cancelOnce sync.Once |
| 441 | invokeCancelAndDetachFn := func() { |
| 442 | cancelOnce.Do(func() { |
| 443 | containerIn.Close() |
| 444 | m.invokeIO.SetOut(nil) |
| 445 | invokeCancel(errors.WithStack(context.Canceled)) |
| 446 | }) |
| 447 | <-waitInvokeDoneCh |
| 448 | } |
| 449 | defer invokeCancelAndDetachFn() |
| 450 | m.invokeCancel = invokeCancelAndDetachFn |
| 451 | |
| 452 | err := m.Invoke(invokeCtx, pid, cfg, containerIn.Stdin, containerIn.Stdout, containerIn.Stderr) |
| 453 | close(waitInvokeDoneCh) |
| 454 | |
| 455 | return err |
| 456 | } |
| 457 | |
| 458 | func (m *monitor) Close() error { |
| 459 | m.cancelRunningProcesses() |