v0.3.0 write output on its own goroutine, blocked terminal report
This commit is contained in:
7 files changed
+288
-78
No files matched your search
@@ -0,0 +1,56 @@
|
||||
package terminal
|
||||
|
||||
import "time"
|
||||
|
||||
// sendLocked queues what the operation in progress rendered and wakes the writer.
|
||||
// Caller MUST hold mu.
|
||||
func (t *termImpl) sendLocked() {
|
||||
buf := &t.output.buf
|
||||
if buf.Len() == 0 {
|
||||
return
|
||||
}
|
||||
t.queued = append(t.queued, buf.Bytes()...)
|
||||
buf.Reset()
|
||||
select {
|
||||
case t.wake <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// writeLoop is the only writer of terminal output after Init. It returns once Fini
|
||||
// has queued the restoring sequences and they are written; a terminal that never
|
||||
// takes them leaves it in its write, and Fini stops waiting.
|
||||
func (t *termImpl) writeLoop() {
|
||||
defer close(t.writerDone)
|
||||
for {
|
||||
select {
|
||||
case <-t.wake:
|
||||
t.drain()
|
||||
case <-t.quit:
|
||||
t.drain()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drain writes what is queued until nothing is, and draws a frame held while a
|
||||
// write was out once that write returns. The write runs without mu, so whoever
|
||||
// draws meanwhile finds writeSince set and holds its frame instead of waiting.
|
||||
func (t *termImpl) drain() {
|
||||
t.mu.Lock()
|
||||
for {
|
||||
if len(t.queued) == 0 {
|
||||
t.releaseLocked()
|
||||
}
|
||||
if len(t.queued) == 0 {
|
||||
break
|
||||
}
|
||||
t.writing, t.queued = t.queued, t.writing[:0]
|
||||
t.writeSince.Store(time.Now().UnixNano())
|
||||
t.mu.Unlock()
|
||||
_ = t.backend.Write(t.writing) // a failed write is lost, as one through a buffered writer was
|
||||
t.writeSince.Store(0)
|
||||
t.mu.Lock()
|
||||
}
|
||||
t.mu.Unlock()
|
||||
}
|
||||
Reference in new issue
Block a user