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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
     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  }
    63  

View as plain text