github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/mmap/mmap_linux.go (about) 1 // Copyright 2015 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 // Package mmap provides a way to memory-map a file. 6 package mmap 7 8 import ( 9 "errors" 10 "fmt" 11 "io" 12 "os" 13 "runtime" 14 "syscall" 15 ) 16 17 // debug is whether to print debugging messages for manual testing. 18 // 19 // The runtime.SetFinalizer documentation says that, "The finalizer for x is 20 // scheduled to run at some arbitrary time after x becomes unreachable. There 21 // is no guarantee that finalizers will run before a program exits", so we 22 // cannot automatically test that the finalizer runs. Instead, set this to true 23 // when running the manual test. 24 const debug = false 25 26 // ReaderAt reads a memory-mapped file. 27 // 28 // Like any io.ReaderAt, clients can execute parallel ReadAt calls, but it is 29 // not safe to call Close and reading methods concurrently. 30 type ReaderAt struct { 31 data []byte 32 } 33 34 // Close closes the reader. 35 func (r *ReaderAt) Close() error { 36 if r.data == nil { 37 return nil 38 } 39 data := r.data 40 r.data = nil 41 if debug { 42 var p *byte 43 if len(data) != 0 { 44 p = &data[0] 45 } 46 println("munmap", r, p) 47 } 48 runtime.SetFinalizer(r, nil) 49 return syscall.Munmap(data) 50 } 51 52 // Len returns the length of the underlying memory-mapped file. 53 func (r *ReaderAt) Len() int { 54 return len(r.data) 55 } 56 57 // At returns the byte at index i. 58 func (r *ReaderAt) At(i int) byte { 59 return r.data[i] 60 } 61 62 // ReadAt implements the io.ReaderAt interface. 63 func (r *ReaderAt) ReadAt(p []byte, off int64) (int, error) { 64 if r.data == nil { 65 return 0, errors.New("mmap: closed") 66 } 67 if off < 0 || int64(len(r.data)) < off { 68 return 0, fmt.Errorf("mmap: invalid ReadAt offset %d", off) 69 } 70 n := copy(p, r.data[off:]) 71 if n < len(p) { 72 return n, io.EOF 73 } 74 return n, nil 75 } 76 77 // Open memory-maps the named file for reading. 78 func Open(filename string) (*ReaderAt, error) { 79 f, err := os.Open(filename) 80 if err != nil { 81 return nil, err 82 } 83 defer f.Close() 84 fi, err := f.Stat() 85 if err != nil { 86 return nil, err 87 } 88 89 size := fi.Size() 90 if size == 0 { 91 return &ReaderAt{}, nil 92 } 93 if size < 0 { 94 return nil, fmt.Errorf("mmap: file %q has negative size", filename) 95 } 96 if size != int64(int(size)) { 97 return nil, fmt.Errorf("mmap: file %q is too large", filename) 98 } 99 100 data, err := syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED) 101 if err != nil { 102 return nil, err 103 } 104 r := &ReaderAt{data} 105 if debug { 106 var p *byte 107 if len(data) != 0 { 108 p = &data[0] 109 } 110 println("mmap", r, p) 111 } 112 runtime.SetFinalizer(r, (*ReaderAt).Close) 113 return r, nil 114 }