summaryrefslogtreecommitdiff
path: root/src/reader.go
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2017-08-16 03:24:23 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2017-08-16 03:33:48 +0900
commit487c8fe88f4cfcc55850b8aef73665b1d09b8fe0 (patch)
treed21e3b4a4fdcb2a6d6980d1f47fb3ede5bd5c557 /src/reader.go
parent0d171ba1d81886c6f9caf61867129e6daa268cd6 (diff)
downloadfzf-487c8fe88f4cfcc55850b8aef73665b1d09b8fe0.tar.gz
Make Reader event notification asynchronous
Instead of notifying the event coordinator (EventBox) whenever a new line is arrived, start a background goroutine that periodically does the task. Atomic.StoreInt32 is much cheaper than mutex synchronization that happens during EventBox update.
Diffstat (limited to 'src/reader.go')
-rw-r--r--src/reader.go39
1 files changed, 37 insertions, 2 deletions
diff --git a/src/reader.go b/src/reader.go
index 1572e5de..401b8f0f 100644
--- a/src/reader.go
+++ b/src/reader.go
@@ -4,6 +4,8 @@ import (
"bufio"
"io"
"os"
+ "sync/atomic"
+ "time"
"github.com/junegunn/fzf/src/util"
)
@@ -13,10 +15,43 @@ type Reader struct {
pusher func([]byte) bool
eventBox *util.EventBox
delimNil bool
+ event int32
+}
+
+// NewReader returns new Reader object
+func NewReader(pusher func([]byte) bool, eventBox *util.EventBox, delimNil bool) *Reader {
+ return &Reader{pusher, eventBox, delimNil, int32(EvtReady)}
+}
+
+func (r *Reader) startEventPoller() {
+ go func() {
+ ptr := &r.event
+ pollInterval := readerPollIntervalMin
+ for {
+ if atomic.CompareAndSwapInt32(ptr, int32(EvtReadNew), int32(EvtReady)) {
+ r.eventBox.Set(EvtReadNew, true)
+ pollInterval = readerPollIntervalMin
+ } else if atomic.LoadInt32(ptr) == int32(EvtReadFin) {
+ return
+ } else {
+ pollInterval += readerPollIntervalStep
+ if pollInterval > readerPollIntervalMax {
+ pollInterval = readerPollIntervalMax
+ }
+ }
+ time.Sleep(pollInterval)
+ }
+ }()
+}
+
+func (r *Reader) fin(success bool) {
+ atomic.StoreInt32(&r.event, int32(EvtReadFin))
+ r.eventBox.Set(EvtReadFin, success)
}
// ReadSource reads data from the default command or from standard input
func (r *Reader) ReadSource() {
+ r.startEventPoller()
var success bool
if util.IsTty() {
cmd := os.Getenv("FZF_DEFAULT_COMMAND")
@@ -27,7 +62,7 @@ func (r *Reader) ReadSource() {
} else {
success = r.readFromStdin()
}
- r.eventBox.Set(EvtReadFin, success)
+ r.fin(success)
}
func (r *Reader) feed(src io.Reader) {
@@ -51,7 +86,7 @@ func (r *Reader) feed(src io.Reader) {
}
}
if r.pusher(bytea) {
- r.eventBox.Set(EvtReadNew, true)
+ atomic.StoreInt32(&r.event, int32(EvtReadNew))
}
}
if err != nil {