2017-06-09 21:52:26 +02:00
|
|
|
package cryptocore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"log"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
2017-08-16 18:33:00 +02:00
|
|
|
// Number of bytes to prefetch.
|
|
|
|
// 512 looks like a good compromise between throughput and latency - see
|
|
|
|
// randsize_test.go for numbers.
|
2017-06-09 21:52:26 +02:00
|
|
|
const prefetchN = 512
|
|
|
|
|
2017-06-11 19:56:59 +02:00
|
|
|
func init() {
|
|
|
|
randPrefetcher.refill = make(chan []byte)
|
|
|
|
go randPrefetcher.refillWorker()
|
|
|
|
}
|
|
|
|
|
2017-06-09 21:52:26 +02:00
|
|
|
type randPrefetcherT struct {
|
|
|
|
sync.Mutex
|
2017-06-11 19:56:59 +02:00
|
|
|
buf bytes.Buffer
|
|
|
|
refill chan []byte
|
2017-06-09 21:52:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *randPrefetcherT) read(want int) (out []byte) {
|
|
|
|
out = make([]byte, want)
|
|
|
|
r.Lock()
|
|
|
|
// Note: don't use defer, it slows us down!
|
|
|
|
have, err := r.buf.Read(out)
|
|
|
|
if have == want && err == nil {
|
|
|
|
r.Unlock()
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
// Buffer was empty -> re-fill
|
2017-06-11 19:56:59 +02:00
|
|
|
fresh := <-r.refill
|
|
|
|
if len(fresh) != prefetchN {
|
|
|
|
log.Panicf("randPrefetcher: refill: got %d bytes instead of %d", len(fresh), prefetchN)
|
|
|
|
}
|
2017-06-09 21:52:26 +02:00
|
|
|
r.buf.Reset()
|
2017-06-11 19:56:59 +02:00
|
|
|
r.buf.Write(fresh)
|
2017-06-09 21:52:26 +02:00
|
|
|
have, err = r.buf.Read(out)
|
|
|
|
if have != want || err != nil {
|
|
|
|
log.Panicf("randPrefetcher could not satisfy read: have=%d want=%d err=%v", have, want, err)
|
|
|
|
}
|
|
|
|
r.Unlock()
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2017-06-11 19:56:59 +02:00
|
|
|
func (r *randPrefetcherT) refillWorker() {
|
|
|
|
for {
|
|
|
|
r.refill <- RandBytes(prefetchN)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-09 21:52:26 +02:00
|
|
|
var randPrefetcher randPrefetcherT
|