github.com/m3db/m3@v1.5.0/src/x/mmap/mmap_other.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  //go:build !linux && !windows
    22  // +build !linux,!windows
    23  
    24  package mmap
    25  
    26  import (
    27  	"fmt"
    28  	"syscall"
    29  	"unsafe"
    30  )
    31  
    32  // Fd mmaps a file
    33  func Fd(fd, offset, length int64, opts Options) (Descriptor, error) {
    34  	// MAP_PRIVATE because we only want to ever mmap immutable things and we don't
    35  	// ever want to propagate writes back to the underlying file
    36  	// Set HugeTLB to disabled because its not supported for files
    37  	opts.HugeTLB.Enabled = false
    38  	return mmap(fd, offset, length, syscall.MAP_PRIVATE, opts)
    39  }
    40  
    41  // Bytes requests a private (non-shared) region of anonymous (not backed by a file) memory from the O.S
    42  func Bytes(length int64, opts Options) (Descriptor, error) {
    43  	// offset is 0 because we're not indexing into a file
    44  	// fd is -1 and MAP_ANON because we're asking for an anonymous region of memory not tied to a file
    45  	// MAP_PRIVATE because we don't plan on sharing this region of memory with other processes
    46  	return mmap(-1, 0, length, syscall.MAP_ANON|syscall.MAP_PRIVATE, opts)
    47  }
    48  
    49  func mmap(fd, offset, length int64, flags int, opts Options) (Descriptor, error) {
    50  	if length == 0 {
    51  		// Return an empty slice (but not nil so callers who
    52  		// use nil to mean something special like not initialized
    53  		// get back an actual ref)
    54  		return Descriptor{Bytes: make([]byte, 0)}, nil
    55  	}
    56  
    57  	var prot int
    58  	if opts.Read {
    59  		prot = prot | syscall.PROT_READ
    60  	}
    61  	if opts.Write {
    62  		prot = prot | syscall.PROT_WRITE
    63  	}
    64  
    65  	b, err := syscall.Mmap(int(fd), offset, int(length), prot, flags)
    66  	if err != nil {
    67  		return Descriptor{}, fmt.Errorf("mmap error: %v", err)
    68  	}
    69  
    70  	if reporter := opts.ReporterOptions.Reporter; reporter != nil {
    71  		opts.ReporterOptions.Context.Size = length
    72  		if err := reporter.ReportMap(opts.ReporterOptions.Context); err != nil {
    73  			// Allow the reporter to deny an mmap to allow enforcement of proper
    74  			// reporting if it wants to.
    75  			syscall.Munmap(b)
    76  			return Descriptor{}, err
    77  		}
    78  	}
    79  
    80  	return Descriptor{
    81  		Bytes:           b,
    82  		ReporterOptions: opts.ReporterOptions,
    83  	}, nil
    84  }
    85  
    86  // Munmap munmaps a byte slice that is backed by an mmap
    87  func Munmap(desc Descriptor) error {
    88  	if len(desc.Bytes) == 0 {
    89  		// Never actually mmapd this, just returned empty slice
    90  		return nil
    91  	}
    92  
    93  	if err := syscall.Munmap(desc.Bytes); err != nil {
    94  		return fmt.Errorf("munmap error: %v", err)
    95  	}
    96  
    97  	if reporter := desc.ReporterOptions.Reporter; reporter != nil {
    98  		if err := reporter.ReportUnmap(desc.ReporterOptions.Context); err != nil {
    99  			// Allow the reporter to return an error from unmap to allow
   100  			// enforcement of proper reporting if it wants to.
   101  			return err
   102  		}
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  // MadviseDontNeed frees mmapped memory.
   109  // `MADV_DONTNEED` informs the kernel to free the mmapped pages right away instead of waiting for memory pressure.
   110  // NB(bodu): DO NOT FREE anonymously mapped memory or else it will null all of the underlying bytes as the
   111  // memory is not file backed.
   112  func MadviseDontNeed(desc Descriptor) error {
   113  	// Do nothing if there's no data.
   114  	if len(desc.Bytes) == 0 {
   115  		return nil
   116  	}
   117  	return madvise(desc.Bytes, syscall.MADV_DONTNEED)
   118  }
   119  
   120  // This is required because the unix package does not support the madvise system call.
   121  // This works generically for other non linux platforms.
   122  func madvise(b []byte, advice int) (err error) {
   123  	_, _, e1 := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&b[0])),
   124  		uintptr(len(b)), uintptr(advice))
   125  	if e1 != 0 {
   126  		err = e1
   127  	}
   128  	return
   129  }