@@ -435,11 +435,30 @@ func (self *ViewBufferManager) readHoldingATask(totalLines int, then func()) {
435435 }
436436}
437437
438- // stopServingReadRequests takes the task away from the read-request queue and
439- // answers whatever it never got to , so that nobody is left waiting for a callback
440- // that isn't coming.
438+ // stopServingReadRequests stops holding read requests for a task and answers the
439+ // ones still waiting , so that nobody is left waiting for a callback that isn't
440+ // coming.
441441func (self * ViewBufferManager ) stopServingReadRequests () {
442- for _ , request := range self .readRequests .stopServing () {
442+ answerReadRequests (self .readRequests .stopServing ())
443+ }
444+
445+ // answerReadRequestsIfLatest answers the read requests still waiting once the given
446+ // task has given the view all of its content, unless another task has been asked for
447+ // since. The requests are waiting for that task's content then, so they are left for
448+ // it to serve.
449+ func (self * ViewBufferManager ) answerReadRequestsIfLatest (taskID int ) {
450+ self .taskIDMutex .Lock ()
451+ var unanswered []LinesToRead
452+ if taskID == self .newTaskID {
453+ unanswered = self .readRequests .stopServing ()
454+ }
455+ self .taskIDMutex .Unlock ()
456+
457+ answerReadRequests (unanswered )
458+ }
459+
460+ func answerReadRequests (requests []LinesToRead ) {
461+ for _ , request := range requests {
443462 if request .Then != nil {
444463 request .Then ()
445464 }
@@ -545,9 +564,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
545564
546565 loadingMutex := deadlock.Mutex {}
547566
548- // Begin serving before any goroutine starts, so that the first request below
549- // can't arrive before there is a task to take it.
550- readRequests := self .readRequests .beginServing ()
567+ readRequests := self .readRequests .beginServing (initialRequest )
551568
552569 scanner := bufio .NewScanner (r )
553570 scanner .Split (utils .ScanLinesAndTruncateWhenLongerThanBuffer (bufio .MaxScanTokenSize ))
@@ -705,6 +722,15 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
705722 linesToRead .Then ()
706723 }
707724 }
725+ // A task that is stopped is being replaced by one that renders the
726+ // content the caller is going to act on, so the request is left for
727+ // that one to serve. A request without a Then has nobody waiting on
728+ // it, and the task replacing this one reads what it needs by itself.
729+ handOver := func () {
730+ if linesToRead .Then != nil {
731+ self .readRequests .requeue (linesToRead )
732+ }
733+ }
708734 // A restore that hasn't painted yet keeps us reading past the lines
709735 // asked for, all the way to the end of the input if need be. What it
710736 // is looking for may be anywhere in the new content, and a rendering
@@ -713,14 +739,14 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
713739 // and the view somewhere the user didn't put it.
714740 for linesToRead .Total == - 1 || linesRead < linesToRead .Total || (restore != nil && ! painted ) {
715741 if stopped () {
716- callThen ()
742+ handOver ()
717743 break outer
718744 }
719745 var ok bool
720746 var line []byte
721747 select {
722748 case <- opts .Stop :
723- callThen ()
749+ handOver ()
724750 break outer
725751 case line , ok = <- lineChan :
726752 // process line below
@@ -752,7 +778,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
752778 // case above.
753779 select {
754780 case <- opts .Stop :
755- callThen ()
781+ handOver ()
756782 break outer
757783 default :
758784 }
@@ -805,10 +831,10 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
805831 }
806832
807833 // Whoever made a request the loop never got to is waiting to hear that the
808- // content it asked for has been read, and there is nothing here to read it
809- // any more: at end of input it has all been read already, and a task that
810- // was stopped is handing the view over to the one replacing it.
811- self .stopServingReadRequests ( )
834+ // content it asked for has been read. At end of input it has all been read
835+ // already. A task that was stopped leaves the requests to the one replacing
836+ // it.
837+ self .answerReadRequestsIfLatest ( opts . taskID )
812838
813839 refreshViewIfStale ()
814840
@@ -832,8 +858,6 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
832858 close (lineWrittenChan )
833859 })
834860
835- self .readRequests .enqueue (initialRequest )
836-
837861 <- done
838862
839863 return nil
@@ -842,6 +866,10 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
842866
843867// Close closes the task manager, killing whatever task may currently be running
844868func (self * ViewBufferManager ) Close () {
869+ // No task is going to read anything after this, so nobody may be left waiting
870+ // for content to be read.
871+ defer self .stopServingReadRequests ()
872+
845873 // stopCurrentTask is written by NewTask's goroutine under waitingMutex (and
846874 // so is the sync.Once it closes over), so read it under the lock and call
847875 // the captured value; a task starting on shutdown must not race us here.
@@ -900,6 +928,8 @@ func (self *ViewBufferManager) ReserveTask() TaskReservation {
900928 defer self .taskIDMutex .Unlock ()
901929
902930 self .newTaskID ++
931+ // Whoever asks for content to be read from now on is asking for this task's.
932+ self .readRequests .hold ()
903933 return TaskReservation {taskID : self .newTaskID }
904934}
905935
@@ -986,9 +1016,6 @@ func (self *ViewBufferManager) NewReservedTask(reservation TaskReservation, f fu
9861016 self .stopCurrentTask ()
9871017 }
9881018
989- // Nothing serves read requests between one task and the next.
990- self .stopServingReadRequests ()
991-
9921019 stop := make (chan struct {})
9931020 notifyStopped := make (chan struct {})
9941021
@@ -1006,6 +1033,10 @@ func (self *ViewBufferManager) NewReservedTask(reservation TaskReservation, f fu
10061033 self .Log .Error (err ) // might need an onError callback
10071034 }
10081035
1036+ // A task that reads no command's output, such as one showing a message, has
1037+ // given the view all of its content once it returns.
1038+ self .answerReadRequestsIfLatest (taskID )
1039+
10091040 close (notifyStopped )
10101041 })
10111042
0 commit comments