Get syscall based SHM working
This commit is contained in:
parent
d01d5297b8
commit
7e161ea94b
@ -51,34 +51,27 @@ type MMap interface {
|
|||||||
Unlink() error
|
Unlink() error
|
||||||
Slice() []byte
|
Slice() []byte
|
||||||
Name() string
|
Name() string
|
||||||
|
IsFilesystemBacked() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtectionFlags int
|
type AccessFlags int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
READ ProtectionFlags = iota
|
READ AccessFlags = iota
|
||||||
|
WRITE
|
||||||
COPY
|
COPY
|
||||||
RDWR
|
|
||||||
EXEC
|
|
||||||
ANON
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func mmap(sz int, inprot ProtectionFlags, anonymous bool, fd int, off int64) ([]byte, error) {
|
func mmap(sz int, access AccessFlags, fd int, off int64) ([]byte, error) {
|
||||||
flags := unix.MAP_SHARED
|
flags := unix.MAP_SHARED
|
||||||
prot := unix.PROT_READ
|
prot := unix.PROT_READ
|
||||||
switch {
|
switch access {
|
||||||
case inprot© != 0:
|
case COPY:
|
||||||
prot |= unix.PROT_WRITE
|
prot |= unix.PROT_WRITE
|
||||||
flags = unix.MAP_PRIVATE
|
flags = unix.MAP_PRIVATE
|
||||||
case inprot&RDWR != 0:
|
case WRITE:
|
||||||
prot |= unix.PROT_WRITE
|
prot |= unix.PROT_WRITE
|
||||||
}
|
}
|
||||||
if inprot&EXEC != 0 {
|
|
||||||
prot |= unix.PROT_EXEC
|
|
||||||
}
|
|
||||||
if anonymous {
|
|
||||||
flags |= unix.MAP_ANON
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := unix.Mmap(fd, off, sz, prot, flags)
|
b, err := unix.Mmap(fd, off, sz, prot, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -87,20 +80,24 @@ func mmap(sz int, inprot ProtectionFlags, anonymous bool, fd int, off int64) ([]
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func munmap(s []byte) error {
|
||||||
|
return unix.Munmap(s)
|
||||||
|
}
|
||||||
|
|
||||||
type file_based_mmap struct {
|
type file_based_mmap struct {
|
||||||
f *os.File
|
f *os.File
|
||||||
region []byte
|
region []byte
|
||||||
unlinked bool
|
unlinked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func file_mmap(f *os.File, size uint64, access ProtectionFlags, truncate bool) (MMap, error) {
|
func file_mmap(f *os.File, size uint64, access AccessFlags, truncate bool) (MMap, error) {
|
||||||
if truncate {
|
if truncate {
|
||||||
err := truncate_or_unlink(f, size)
|
err := truncate_or_unlink(f, size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
region, err := mmap(int(size), access, false, int(f.Fd()), 0)
|
region, err := mmap(int(size), access, int(f.Fd()), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
os.Remove(f.Name())
|
os.Remove(f.Name())
|
||||||
@ -117,9 +114,12 @@ func (self *file_based_mmap) Slice() []byte {
|
|||||||
return self.region
|
return self.region
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *file_based_mmap) Close() error {
|
func (self *file_based_mmap) Close() (err error) {
|
||||||
err := self.f.Close()
|
if self.region != nil {
|
||||||
|
self.f.Close()
|
||||||
|
err = munmap(self.region)
|
||||||
self.region = nil
|
self.region = nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +131,8 @@ func (self *file_based_mmap) Unlink() (err error) {
|
|||||||
return os.Remove(self.f.Name())
|
return os.Remove(self.f.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *file_based_mmap) IsFilesystemBacked() bool { return true }
|
||||||
|
|
||||||
func CreateTemp(pattern string, size uint64) (MMap, error) {
|
func CreateTemp(pattern string, size uint64) (MMap, error) {
|
||||||
return create_temp(pattern, size)
|
return create_temp(pattern, size)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,10 +16,10 @@ func create_temp(pattern string, size uint64) (MMap, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return file_mmap(ans, size, RDWR, true)
|
return file_mmap(ans, size, WRITE, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Open(name string) (MMap, error) {
|
func Open(name string, size uint64) (MMap, error) {
|
||||||
if !filepath.IsAbs(name) {
|
if !filepath.IsAbs(name) {
|
||||||
name = filepath.Join(SHM_DIR, name)
|
name = filepath.Join(SHM_DIR, name)
|
||||||
}
|
}
|
||||||
@ -27,10 +27,5 @@ func Open(name string) (MMap, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s, err := os.Stat(name)
|
return file_mmap(ans, size, READ, false)
|
||||||
if err != nil {
|
|
||||||
ans.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return file_mmap(ans, uint64(s.Size()), READ, false)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ func BytePtrFromString(s string) *byte {
|
|||||||
func shm_unlink(name string) (err error) {
|
func shm_unlink(name string) (err error) {
|
||||||
bname := BytePtrFromString(name)
|
bname := BytePtrFromString(name)
|
||||||
for {
|
for {
|
||||||
_, _, errno := unix.Syscall(unix.SYS_SHM_OPEN, uintptr(unsafe.Pointer(bname)), 0, 0)
|
_, _, errno := unix.Syscall(unix.SYS_SHM_UNLINK, uintptr(unsafe.Pointer(bname)), 0, 0)
|
||||||
if errno != unix.EINTR {
|
if errno != unix.EINTR {
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
err = fmt.Errorf("shm_unlink() failed with error: %w", errno)
|
err = fmt.Errorf("shm_unlink() failed with error: %w", errno)
|
||||||
@ -67,14 +67,14 @@ type syscall_based_mmap struct {
|
|||||||
unlinked bool
|
unlinked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func syscall_mmap(f *os.File, size uint64, access ProtectionFlags, truncate bool) (MMap, error) {
|
func syscall_mmap(f *os.File, size uint64, access AccessFlags, truncate bool) (MMap, error) {
|
||||||
if truncate {
|
if truncate {
|
||||||
err := truncate_or_unlink(f, size)
|
err := truncate_or_unlink(f, size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("truncate failed with error: %w", err)
|
return nil, fmt.Errorf("truncate failed with error: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
region, err := mmap(int(size), access, false, int(f.Fd()), 0)
|
region, err := mmap(int(size), access, int(f.Fd()), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
os.Remove(f.Name())
|
os.Remove(f.Name())
|
||||||
@ -91,10 +91,13 @@ func (self *syscall_based_mmap) Slice() []byte {
|
|||||||
return self.region
|
return self.region
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *syscall_based_mmap) Close() error {
|
func (self *syscall_based_mmap) Close() (err error) {
|
||||||
err := self.f.Close()
|
if self.region != nil {
|
||||||
|
self.f.Close()
|
||||||
|
munmap(self.region)
|
||||||
self.region = nil
|
self.region = nil
|
||||||
return err
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *syscall_based_mmap) Unlink() (err error) {
|
func (self *syscall_based_mmap) Unlink() (err error) {
|
||||||
@ -105,6 +108,8 @@ func (self *syscall_based_mmap) Unlink() (err error) {
|
|||||||
return shm_unlink(self.Name())
|
return shm_unlink(self.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *syscall_based_mmap) IsFilesystemBacked() bool { return false }
|
||||||
|
|
||||||
func create_temp(pattern string, size uint64) (ans MMap, err error) {
|
func create_temp(pattern string, size uint64) (ans MMap, err error) {
|
||||||
var prefix, suffix string
|
var prefix, suffix string
|
||||||
prefix, suffix, err = prefix_and_suffix(pattern)
|
prefix, suffix, err = prefix_and_suffix(pattern)
|
||||||
@ -126,7 +131,7 @@ func create_temp(pattern string, size uint64) (ans MMap, err error) {
|
|||||||
if err != nil && (errors.Is(err, fs.ErrExist) || errors.Unwrap(err) == unix.EEXIST) {
|
if err != nil && (errors.Is(err, fs.ErrExist) || errors.Unwrap(err) == unix.EEXIST) {
|
||||||
try += 1
|
try += 1
|
||||||
if try > 10000 {
|
if try > 10000 {
|
||||||
return nil, &os.PathError{Op: "createtemp", Path: prefix + "*" + suffix, Err: ErrExist}
|
return nil, &os.PathError{Op: "createtemp", Path: prefix + "*" + suffix, Err: fs.ErrExist}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -135,18 +140,13 @@ func create_temp(pattern string, size uint64) (ans MMap, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return syscall_mmap(f, size, RDWR, true)
|
return syscall_mmap(f, size, WRITE, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Open(name string) (MMap, error) {
|
func Open(name string, size uint64) (MMap, error) {
|
||||||
ans, err := shm_open(name, os.O_RDONLY, 0)
|
ans, err := shm_open(name, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s, err := os.Stat(name)
|
return syscall_mmap(ans, size, READ, false)
|
||||||
if err != nil {
|
|
||||||
ans.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return syscall_mmap(ans, uint64(s.Size()), READ, false)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,9 +23,12 @@ func TestSHM(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
copy(mm.Slice(), data)
|
copy(mm.Slice(), data)
|
||||||
mm.Close()
|
err = mm.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to close with error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
g, err := Open(mm.Name())
|
g, err := Open(mm.Name(), uint64(len(data)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -33,11 +36,22 @@ func TestSHM(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(data, data2) {
|
if !reflect.DeepEqual(data, data2) {
|
||||||
t.Fatalf("Could not read back written data: Written data length: %d Read data length: %d", len(data), len(data2))
|
t.Fatalf("Could not read back written data: Written data length: %d Read data length: %d", len(data), len(data2))
|
||||||
}
|
}
|
||||||
g.Close()
|
err = g.Close()
|
||||||
g.Unlink()
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to close with error: %v", err)
|
||||||
|
}
|
||||||
|
err = g.Unlink()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to unlink with error: %v", err)
|
||||||
|
}
|
||||||
|
g, err = Open(mm.Name(), uint64(len(data)))
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Unlinking failed could re-open the SHM data. Data equal: %v Data length: %d", reflect.DeepEqual(g.Slice(), data), len(g.Slice()))
|
||||||
|
}
|
||||||
|
if mm.IsFilesystemBacked() {
|
||||||
_, err = os.Stat(mm.Name())
|
_, err = os.Stat(mm.Name())
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
t.Fatalf("Unlinking %s did not work", mm.Name())
|
t.Fatalf("Unlinking %s did not work", mm.Name())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user