mirror of
https://github.com/walles/moar.git
synced 2024-11-22 03:14:56 +03:00
Fix a hang
Before this change, if select() returned EINTR we would hang. This change: * Makes us ignore EINTRs and try again * Makes sure to not hang, even if the twin main loop would fail for some other reason.
This commit is contained in:
parent
27817741fc
commit
f4fed36bfd
2
build.sh
2
build.sh
@ -28,4 +28,4 @@ fi
|
||||
go build -trimpath -ldflags="-s -w -X main.versionString=${VERSION}" -o "${BINARY}"
|
||||
|
||||
# Alternative build line, if you want to attach to the running process in the Go debugger:
|
||||
# go build -ldflags="-X main.versionString=${VERSION}" -gcflags='-N -l' -o "${BINARY}"
|
||||
# go build -ldflags="-X main.versionString=${VERSION}" -gcflags="all=-N -l" -o "${BINARY}"
|
||||
|
@ -55,6 +55,10 @@ func (r *interruptableReaderImpl) Interrupt() {
|
||||
r.shutdownRequested.Store(true)
|
||||
}
|
||||
|
||||
func (r *interruptableReaderImpl) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newInterruptableReader(base *os.File) (interruptableReader, error) {
|
||||
return &interruptableReaderImpl{base: base}, nil
|
||||
}
|
||||
|
@ -24,6 +24,19 @@ type interruptableReaderImpl struct {
|
||||
}
|
||||
|
||||
func (r *interruptableReaderImpl) Read(p []byte) (n int, err error) {
|
||||
for {
|
||||
n, err = r.read(p)
|
||||
if err == syscall.EINTR {
|
||||
// Not really a problem, we can get this on window resizes for
|
||||
// example, just try again.
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (r *interruptableReaderImpl) read(p []byte) (n int, err error) {
|
||||
// "This argument should be set to the highest-numbered file descriptor in
|
||||
// any of the three sets, plus 1. The indicated file descriptors in each set
|
||||
// are checked, up to this limit"
|
||||
@ -55,7 +68,7 @@ func (r *interruptableReaderImpl) Read(p []byte) (n int, err error) {
|
||||
err = io.EOF
|
||||
|
||||
// Let Interrupt() know we're done
|
||||
r.interruptionComplete <- struct{}{}
|
||||
r.Close()
|
||||
|
||||
return
|
||||
}
|
||||
@ -77,10 +90,18 @@ func (r *interruptableReaderImpl) Interrupt() {
|
||||
<-r.interruptionComplete
|
||||
}
|
||||
|
||||
func (r *interruptableReaderImpl) Close() error {
|
||||
select {
|
||||
case r.interruptionComplete <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newInterruptableReader(base *os.File) (interruptableReader, error) {
|
||||
reader := interruptableReaderImpl{
|
||||
base: base,
|
||||
interruptionComplete: make(chan struct{}),
|
||||
interruptionComplete: make(chan struct{}, 1),
|
||||
}
|
||||
pr, pw, err := os.Pipe()
|
||||
if err != nil {
|
||||
|
@ -74,6 +74,12 @@ type interruptableReader interface {
|
||||
|
||||
// Interrupt unblocks the read call, either now or eventually.
|
||||
Interrupt()
|
||||
|
||||
// Close() should be called after you are done with the interruptableReader.
|
||||
//
|
||||
// It will not close the underlying reader, but it will prevent Interrupt()
|
||||
// from hanging if called after a failure in the screen mainLoop().
|
||||
Close() error
|
||||
}
|
||||
|
||||
type UnixScreen struct {
|
||||
@ -366,6 +372,7 @@ func (screen *UnixScreen) ShowCursorAt(column int, row int) {
|
||||
|
||||
func (screen *UnixScreen) mainLoop() {
|
||||
defer func() {
|
||||
screen.ttyInReader.Close()
|
||||
log.Debug("Twin screen main loop done")
|
||||
}()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user