buf_mmap.go (1667B)
1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin dragonfly freebsd linux netbsd openbsd 6 7 package bio 8 9 import ( 10 "runtime" 11 "sync/atomic" 12 "syscall" 13 ) 14 15 // mmapLimit is the maximum number of mmaped regions to create before 16 // falling back to reading into a heap-allocated slice. This exists 17 // because some operating systems place a limit on the number of 18 // distinct mapped regions per process. As of this writing: 19 // 20 // Darwin unlimited 21 // DragonFly 1000000 (vm.max_proc_mmap) 22 // FreeBSD unlimited 23 // Linux 65530 (vm.max_map_count) // TODO: query /proc/sys/vm/max_map_count? 24 // NetBSD unlimited 25 // OpenBSD unlimited 26 var mmapLimit int32 = 1<<31 - 1 27 28 func init() { 29 // Linux is the only practically concerning OS. 30 if runtime.GOOS == "linux" { 31 mmapLimit = 30000 32 } 33 } 34 35 func (r *Reader) sliceOS(length uint64) ([]byte, bool) { 36 // For small slices, don't bother with the overhead of a 37 // mapping, especially since we have no way to unmap it. 38 const threshold = 16 << 10 39 if length < threshold { 40 return nil, false 41 } 42 43 // Have we reached the mmap limit? 44 if atomic.AddInt32(&mmapLimit, -1) < 0 { 45 atomic.AddInt32(&mmapLimit, 1) 46 return nil, false 47 } 48 49 // Page-align the offset. 50 off := r.Offset() 51 align := syscall.Getpagesize() 52 aoff := off &^ int64(align-1) 53 54 data, err := syscall.Mmap(int(r.f.Fd()), aoff, int(length+uint64(off-aoff)), syscall.PROT_READ, syscall.MAP_SHARED|syscall.MAP_FILE) 55 if err != nil { 56 return nil, false 57 } 58 59 data = data[off-aoff:] 60 r.MustSeek(int64(length), 1) 61 return data, true 62 }