v0.3.0 write output on its own goroutine, blocked terminal report

This commit is contained in:
lixen committed 2026-10-14 20:38:40 -04:00
1 parent c657af606d
commit 0919d2a6b1
7 files changed
+288 -78

No files matched your search

+56
View File
@@ -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()
}