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}"
|
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:
|
# 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)
|
r.shutdownRequested.Store(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *interruptableReaderImpl) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func newInterruptableReader(base *os.File) (interruptableReader, error) {
|
func newInterruptableReader(base *os.File) (interruptableReader, error) {
|
||||||
return &interruptableReaderImpl{base: base}, nil
|
return &interruptableReaderImpl{base: base}, nil
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,19 @@ type interruptableReaderImpl struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *interruptableReaderImpl) Read(p []byte) (n int, err error) {
|
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
|
// "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
|
// any of the three sets, plus 1. The indicated file descriptors in each set
|
||||||
// are checked, up to this limit"
|
// are checked, up to this limit"
|
||||||
@ -55,7 +68,7 @@ func (r *interruptableReaderImpl) Read(p []byte) (n int, err error) {
|
|||||||
err = io.EOF
|
err = io.EOF
|
||||||
|
|
||||||
// Let Interrupt() know we're done
|
// Let Interrupt() know we're done
|
||||||
r.interruptionComplete <- struct{}{}
|
r.Close()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -77,10 +90,18 @@ func (r *interruptableReaderImpl) Interrupt() {
|
|||||||
<-r.interruptionComplete
|
<-r.interruptionComplete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *interruptableReaderImpl) Close() error {
|
||||||
|
select {
|
||||||
|
case r.interruptionComplete <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func newInterruptableReader(base *os.File) (interruptableReader, error) {
|
func newInterruptableReader(base *os.File) (interruptableReader, error) {
|
||||||
reader := interruptableReaderImpl{
|
reader := interruptableReaderImpl{
|
||||||
base: base,
|
base: base,
|
||||||
interruptionComplete: make(chan struct{}),
|
interruptionComplete: make(chan struct{}, 1),
|
||||||
}
|
}
|
||||||
pr, pw, err := os.Pipe()
|
pr, pw, err := os.Pipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -74,6 +74,12 @@ type interruptableReader interface {
|
|||||||
|
|
||||||
// Interrupt unblocks the read call, either now or eventually.
|
// Interrupt unblocks the read call, either now or eventually.
|
||||||
Interrupt()
|
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 {
|
type UnixScreen struct {
|
||||||
@ -366,6 +372,7 @@ func (screen *UnixScreen) ShowCursorAt(column int, row int) {
|
|||||||
|
|
||||||
func (screen *UnixScreen) mainLoop() {
|
func (screen *UnixScreen) mainLoop() {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
screen.ttyInReader.Close()
|
||||||
log.Debug("Twin screen main loop done")
|
log.Debug("Twin screen main loop done")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user