package mt import ( "fmt" "os" "reflect" "syscall" "unsafe" "golang.org/x/sys/unix" ) // Map creates a memory map of the given file. func Map( prot int, // Memory protection bitmask. See syscall.PROT_* flags. flags int, // See syscall.MAP_* flags. MAP_SHARED is usually fine. length int64, f *os.File, ) ( []byte, error, ) { addr, _, errno := syscall.Syscall6( syscall.SYS_MMAP, 0, // addr: 0 => allow kernel to choose uintptr(length), uintptr(prot), uintptr(flags), f.Fd(), 0) // offset: 0 => start of file if errno != 0 { return nil, syscall.Errno(errno) } var b []byte hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b)) hdr.Data = addr hdr.Cap = int(length) hdr.Len = 0 return b, nil } // Unmap unmaps the data obtained by Map. func Unmap(data []byte) error { _, _, errno := syscall.Syscall( syscall.SYS_MUNMAP, uintptr(unsafe.Pointer(&data[:1][0])), uintptr(cap(data)), 0) if errno != 0 { return syscall.Errno(errno) } return nil } // Remap truncates the file to `newSize` and returns a new memory map for the // file. func Remap( f *os.File, data []byte, newSize int64, ) ([]byte, error) { const mRemapMayMove = 0x1 if err := f.Truncate(newSize); err != nil { return data, err } addr, size, errno := unix.Syscall6( unix.SYS_MREMAP, uintptr(unsafe.Pointer(&data[:1][0])), uintptr(cap(data)), uintptr(newSize), uintptr(mRemapMayMove), 0, 0) if errno != 0 { return data, syscall.Errno(errno) } hdr := (*reflect.SliceHeader)(unsafe.Pointer(&data)) hdr.Data = addr hdr.Cap = int(newSize) hdr.Len = int(newSize) if int64(size) != newSize { panic(fmt.Sprintf("mremap returned incorrect size %d != %d", size, newSize)) } return data, nil }