func (s *sessionManager) waitForShell(shell engines.Shell) { // Wait for shell to finish shell.Wait() // Lock access to s.shells s.m.Lock() defer s.m.Unlock() // Remove shell from s.shells shells := s.shells[:0] for _, sh := range s.shells { if sh != shell { shells = append(shells, sh) } } s.shells = shells // Notify threads waiting if all shells are done if len(s.shells) == 0 && len(s.displays) == 0 { s.empty.Broadcast() } }
func (s *ShellServer) handleShell(ws *websocket.Conn, shell engines.Shell) { done := make(chan struct{}) // Create a shell handler s.updateRefCount(1) handler := NewShellHandler(ws, s.log.WithField("shell-instance-id", s.nextID())) // Connect pipes go ioext.CopyAndClose(shell.StdinPipe(), handler.StdinPipe()) go ioext.CopyAndClose(handler.StdoutPipe(), shell.StdoutPipe()) go ioext.CopyAndClose(handler.StderrPipe(), shell.StderrPipe()) // Start streaming handler.Communicate(shell.SetSize, shell.Abort) // Wait for call to abort all shells go func() { select { case <-s.done: shell.Abort() case <-done: } }() // Wait for the shell to terminate success, _ := shell.Wait() handler.Terminated(success) s.updateRefCount(-1) // Close done so we stop waiting for abort on all shells select { case <-done: default: close(done) } }