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