1// Copyright 2011 Evan Shaw. 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// This file defines the common package interface and contains a little bit of 6// factored out logic. 7 8// Package mmap allows mapping files into memory. It tries to provide a simple, reasonably portable interface, 9// but doesn't go out of its way to abstract away every little platform detail. 10// This specifically means: 11// * forked processes may or may not inherit mappings 12// * a file's timestamp may or may not be updated by writes through mappings 13// * specifying a size larger than the file's actual size can increase the file's size 14// * If the mapped file is being modified by another process while your program's running, don't expect consistent results between platforms 15package mmap 16 17import ( 18 "errors" 19 "os" 20 "reflect" 21 "unsafe" 22) 23 24const ( 25 // RDONLY maps the memory read-only. 26 // Attempts to write to the MMap object will result in undefined behavior. 27 RDONLY = 0 28 // RDWR maps the memory as read-write. Writes to the MMap object will update the 29 // underlying file. 30 RDWR = 1 << iota 31 // COPY maps the memory as copy-on-write. Writes to the MMap object will affect 32 // memory, but the underlying file will remain unchanged. 33 COPY 34 // If EXEC is set, the mapped memory is marked as executable. 35 EXEC 36) 37 38const ( 39 // If the ANON flag is set, the mapped memory will not be backed by a file. 40 ANON = 1 << iota 41) 42 43// MMap represents a file mapped into memory. 44type MMap []byte 45 46// Map maps an entire file into memory. 47// If ANON is set in flags, f is ignored. 48func Map(f *os.File, prot, flags int) (MMap, error) { 49 return MapRegion(f, -1, prot, flags, 0) 50} 51 52// MapRegion maps part of a file into memory. 53// The offset parameter must be a multiple of the system's page size. 54// If length < 0, the entire file will be mapped. 55// If ANON is set in flags, f is ignored. 56func MapRegion(f *os.File, length int, prot, flags int, offset int64) (MMap, error) { 57 if offset%int64(os.Getpagesize()) != 0 { 58 return nil, errors.New("offset parameter must be a multiple of the system's page size") 59 } 60 61 var fd uintptr 62 if flags&ANON == 0 { 63 fd = uintptr(f.Fd()) 64 if length < 0 { 65 fi, err := f.Stat() 66 if err != nil { 67 return nil, err 68 } 69 length = int(fi.Size()) 70 } 71 } else { 72 if length <= 0 { 73 return nil, errors.New("anonymous mapping requires non-zero length") 74 } 75 fd = ^uintptr(0) 76 } 77 return mmap(length, uintptr(prot), uintptr(flags), fd, offset) 78} 79 80func (m *MMap) header() *reflect.SliceHeader { 81 return (*reflect.SliceHeader)(unsafe.Pointer(m)) 82} 83 84// Lock keeps the mapped region in physical memory, ensuring that it will not be 85// swapped out. 86func (m MMap) Lock() error { 87 dh := m.header() 88 return lock(dh.Data, uintptr(dh.Len)) 89} 90 91// Unlock reverses the effect of Lock, allowing the mapped region to potentially 92// be swapped out. 93// If m is already unlocked, aan error will result. 94func (m MMap) Unlock() error { 95 dh := m.header() 96 return unlock(dh.Data, uintptr(dh.Len)) 97} 98 99// Flush synchronizes the mapping's contents to the file's contents on disk. 100func (m MMap) Flush() error { 101 dh := m.header() 102 return flush(dh.Data, uintptr(dh.Len)) 103} 104 105// Unmap deletes the memory mapped region, flushes any remaining changes, and sets 106// m to nil. 107// Trying to read or write any remaining references to m after Unmap is called will 108// result in undefined behavior. 109// Unmap should only be called on the slice value that was originally returned from 110// a call to Map. Calling Unmap on a derived slice may cause errors. 111func (m *MMap) Unmap() error { 112 dh := m.header() 113 err := unmap(dh.Data, uintptr(dh.Len)) 114 *m = nil 115 return err 116} 117