summaryrefslogtreecommitdiffstats
path: root/src/cmd/internal/bio/buf_mmap.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal/bio/buf_mmap.go')
-rw-r--r--src/cmd/internal/bio/buf_mmap.go62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/cmd/internal/bio/buf_mmap.go b/src/cmd/internal/bio/buf_mmap.go
new file mode 100644
index 0000000..4b43d74
--- /dev/null
+++ b/src/cmd/internal/bio/buf_mmap.go
@@ -0,0 +1,62 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package bio
+
+import (
+ "runtime"
+ "sync/atomic"
+ "syscall"
+)
+
+// mmapLimit is the maximum number of mmaped regions to create before
+// falling back to reading into a heap-allocated slice. This exists
+// because some operating systems place a limit on the number of
+// distinct mapped regions per process. As of this writing:
+//
+// Darwin unlimited
+// DragonFly 1000000 (vm.max_proc_mmap)
+// FreeBSD unlimited
+// Linux 65530 (vm.max_map_count) // TODO: query /proc/sys/vm/max_map_count?
+// NetBSD unlimited
+// OpenBSD unlimited
+var mmapLimit int32 = 1<<31 - 1
+
+func init() {
+ // Linux is the only practically concerning OS.
+ if runtime.GOOS == "linux" {
+ mmapLimit = 30000
+ }
+}
+
+func (r *Reader) sliceOS(length uint64) ([]byte, bool) {
+ // For small slices, don't bother with the overhead of a
+ // mapping, especially since we have no way to unmap it.
+ const threshold = 16 << 10
+ if length < threshold {
+ return nil, false
+ }
+
+ // Have we reached the mmap limit?
+ if atomic.AddInt32(&mmapLimit, -1) < 0 {
+ atomic.AddInt32(&mmapLimit, 1)
+ return nil, false
+ }
+
+ // Page-align the offset.
+ off := r.Offset()
+ align := syscall.Getpagesize()
+ aoff := off &^ int64(align-1)
+
+ data, err := syscall.Mmap(int(r.f.Fd()), aoff, int(length+uint64(off-aoff)), syscall.PROT_READ, syscall.MAP_SHARED|syscall.MAP_FILE)
+ if err != nil {
+ return nil, false
+ }
+
+ data = data[off-aoff:]
+ r.MustSeek(int64(length), 1)
+ return data, true
+}