96 lines
1.7 KiB
Go
96 lines
1.7 KiB
Go
|
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
|
||
|
}
|