From 21b522df4167f57195f6b4b40a49632905cc7fbb Mon Sep 17 00:00:00 2001 From: jdl Date: Wed, 31 Mar 2021 10:33:16 +0200 Subject: [PATCH] Added mmap. --- mmap/mmap.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 mmap/mmap.go diff --git a/mmap/mmap.go b/mmap/mmap.go new file mode 100644 index 0000000..b14e753 --- /dev/null +++ b/mmap/mmap.go @@ -0,0 +1,95 @@ +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 +}