github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/pkg/random/random.go (about) 1 package random 2 3 import ( 4 cryptorand "crypto/rand" 5 "io" 6 "math" 7 "math/big" 8 "math/rand" 9 "sync" 10 "time" 11 ) 12 13 // Rand is a global *rand.Rand instance, which initialized with NewSource() source. 14 var Rand = rand.New(NewSource()) 15 16 // Reader is a global, shared instance of a pseudorandom bytes generator. 17 // It doesn't consume entropy. 18 var Reader io.Reader = &reader{rnd: Rand} 19 20 // copypaste from standard math/rand 21 type lockedSource struct { 22 lk sync.Mutex 23 src rand.Source 24 } 25 26 func (r *lockedSource) Int63() (n int64) { 27 r.lk.Lock() 28 n = r.src.Int63() 29 r.lk.Unlock() 30 return 31 } 32 33 func (r *lockedSource) Seed(seed int64) { 34 r.lk.Lock() 35 r.src.Seed(seed) 36 r.lk.Unlock() 37 } 38 39 // NewSource returns math/rand.Source safe for concurrent use and initialized 40 // with current unix-nano timestamp 41 func NewSource() rand.Source { 42 var seed int64 43 if cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)); err != nil { 44 // This should not happen, but worst-case fallback to time-based seed. 45 seed = time.Now().UnixNano() 46 } else { 47 seed = cryptoseed.Int64() 48 } 49 return &lockedSource{ 50 src: rand.NewSource(seed), 51 } 52 } 53 54 type reader struct { 55 rnd *rand.Rand 56 } 57 58 func (r *reader) Read(b []byte) (int, error) { 59 i := 0 60 for { 61 val := r.rnd.Int63() 62 for val > 0 { 63 b[i] = byte(val) 64 i++ 65 if i == len(b) { 66 return i, nil 67 } 68 val >>= 8 69 } 70 } 71 }