Stop FIFO reader after terminal errors
This commit is contained in:
committed by
Brandon McGinty
parent
6aeab4fd5c
commit
41759b95f6
@@ -1,6 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.stormux.org/storm/barnard/gumble/gumble"
|
"git.stormux.org/storm/barnard/gumble/gumble"
|
||||||
@@ -15,6 +17,23 @@ func TestEscRemovesTerminalControlSequences(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testReadCloser struct{ io.Reader }
|
||||||
|
|
||||||
|
func (testReadCloser) Close() error { return nil }
|
||||||
|
|
||||||
|
// Regression: an EOF from the FIFO was ignored and caused an unbounded busy
|
||||||
|
// loop. The reader must deliver a final command then close its output.
|
||||||
|
func TestReadFIFOStopsOnEOF(t *testing.T) {
|
||||||
|
out := make(chan string)
|
||||||
|
go readFIFO(testReadCloser{strings.NewReader("command\n")}, out)
|
||||||
|
if got := <-out; got != "command" {
|
||||||
|
t.Fatalf("got %q", got)
|
||||||
|
}
|
||||||
|
if _, ok := <-out; ok {
|
||||||
|
t.Fatal("FIFO output remained open after EOF")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUserChangeNotification(t *testing.T) {
|
func TestUserChangeNotification(t *testing.T) {
|
||||||
current := &gumble.Channel{ID: 1, Name: "Current"}
|
current := &gumble.Channel{ID: 1, Name: "Current"}
|
||||||
other := &gumble.Channel{ID: 2, Name: "Other"}
|
other := &gumble.Channel{ID: 2, Name: "Other"}
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ Priority 3: configuration, UI, and binding hardening
|
|||||||
temporary file/directory before rename. Avoid broad unrelated formatting
|
temporary file/directory before rename. Avoid broad unrelated formatting
|
||||||
changes while fixing this.
|
changes while fixing this.
|
||||||
|
|
||||||
29. FIFO reader spins after an error
|
[x] 29. FIFO reader spins after an error
|
||||||
File: main.go
|
File: main.go
|
||||||
setup_fifo ignores all ReadBytes errors and retries immediately. It also
|
setup_fifo ignores all ReadBytes errors and retries immediately. It also
|
||||||
never closes the FIFO descriptor. Exit the reader on terminal errors,
|
never closes the FIFO descriptor. Exit the reader on terminal errors,
|
||||||
|
|||||||
@@ -88,18 +88,27 @@ func setup_fifo(fn string) (chan string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return t, err
|
return t, err
|
||||||
}
|
}
|
||||||
go func(fh io.Reader, out chan string) {
|
go readFIFO(file, t)
|
||||||
reader := bufio.NewReader(fh)
|
|
||||||
for {
|
|
||||||
line, err := reader.ReadBytes('\n')
|
|
||||||
if err == nil {
|
|
||||||
out <- strings.TrimSpace(string(line))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(file, t)
|
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readFIFO forwards complete commands and terminates on EOF or any read
|
||||||
|
// failure. Retrying an unrecoverable FIFO error used to spin a CPU forever.
|
||||||
|
func readFIFO(fh io.ReadCloser, out chan<- string) {
|
||||||
|
defer fh.Close()
|
||||||
|
defer close(out)
|
||||||
|
reader := bufio.NewReader(fh)
|
||||||
|
for {
|
||||||
|
line, err := reader.ReadBytes('\n')
|
||||||
|
if len(line) != 0 {
|
||||||
|
out <- strings.TrimSpace(string(line))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Command line flags
|
// Command line flags
|
||||||
server := flag.String("server", "localhost:64738", "the server to connect to")
|
server := flag.String("server", "localhost:64738", "the server to connect to")
|
||||||
|
|||||||
Reference in New Issue
Block a user