From 70ba95529ba0a8831a9aae846f7bb4ad1dc405d8 Mon Sep 17 00:00:00 2001 From: Tim Culverhouse Date: Mon, 29 Jul 2024 07:58:19 -0500 Subject: [PATCH] writer: add WriteStringLocked Fix a race condition in the writer when we are querying background color from the terminal widget. We do this by adding a mutex in the writer and only locking during the flush method, and adding a helper WriteStringLocked which protects access as well. Signed-off-by: Tim Culverhouse --- vaxis.go | 2 +- writer.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/vaxis.go b/vaxis.go index dd6b68c..e90895c 100644 --- a/vaxis.go +++ b/vaxis.go @@ -1006,7 +1006,7 @@ func (vx *Vaxis) QueryBackground() Color { if !vx.CanReportBackgroundColor() { return Color(0) } - vx.tw.WriteString(osc11) + vx.tw.WriteStringLocked(osc11) resp := <-vx.chBg var r, g, b int _, err := fmt.Sscanf(resp, "11;rgb:%x/%x/%x", &r, &g, &b) diff --git a/writer.go b/writer.go index 500ca8a..bcf8450 100644 --- a/writer.go +++ b/writer.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "io" + "sync" ) // writer is a buffered writer for a terminal. If the terminal supports @@ -13,6 +14,7 @@ type writer struct { buf *bytes.Buffer w io.Writer vx *Vaxis + mut sync.Mutex } func newWriter(vx *Vaxis) *writer { @@ -66,6 +68,15 @@ func (w *writer) Len() int { return w.buf.Len() } +// WriteStringLocked writes to the underlying terminal while the mutex is held. +// This does not handle any mouse nor synchronization state and is intended to +// be used for one-off synchronized sequence writes to the terminal +func (w *writer) WriteStringLocked(s string) (n int, err error) { + w.mut.Lock() + defer w.mut.Unlock() + return w.w.Write([]byte(s)) +} + func (w *writer) Flush() (n int, err error) { if w.buf.Len() == 0 { // If we didn't write any visual changes, make sure we make any @@ -95,5 +106,7 @@ func (w *writer) Flush() (n int, err error) { if w.vx.caps.synchronizedUpdate { w.buf.WriteString(decrst(synchronizedUpdate)) } + w.mut.Lock() + defer w.mut.Unlock() return w.w.Write(w.buf.Bytes()) } -- 2.45.2