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 }