|
|
@ -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 |
|
|
|
} |