diff --git a/kitty/shm.py b/kitty/shm.py index ff1d09b27..f82e62ff0 100644 --- a/kitty/shm.py +++ b/kitty/shm.py @@ -82,7 +82,7 @@ class SharedMemory: self._name = name try: if flags & os.O_CREAT and size: - os.ftruncate(self._fd, size) + os.posix_fallocate(self._fd, 0, size) self.stats = os.fstat(self._fd) size = self.stats.st_size self._mmap = mmap.mmap(self._fd, size, access=mmap.ACCESS_READ if readonly else mmap.ACCESS_WRITE) diff --git a/tools/utils/shm/fallocate_darwin.go b/tools/utils/shm/fallocate_darwin.go new file mode 100644 index 000000000..62b748bc8 --- /dev/null +++ b/tools/utils/shm/fallocate_darwin.go @@ -0,0 +1,29 @@ +// License: GPLv3 Copyright: 2023, Kovid Goyal, + +package shm + +import ( + "fmt" + "syscall" + "unsafe" +) + +var _ = fmt.Print + +func Fallocate_simple(fd int, size int64) (err error) { + store := &syscall.Fstore_t{ + Flags: syscall.F_ALLOCATEALL, + Posmode: syscall.F_PEOFPOSMODE, + Offset: 0, + Length: int64(size), + } + + for { + if _, _, err = syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store))); !errors.Is(err, unix.EINTR) { + if err != 0 { + return err + } + return nil + } + } +} diff --git a/tools/utils/shm/fallocate_linux.go b/tools/utils/shm/fallocate_linux.go new file mode 100644 index 000000000..8cd91b68d --- /dev/null +++ b/tools/utils/shm/fallocate_linux.go @@ -0,0 +1,20 @@ +// License: GPLv3 Copyright: 2023, Kovid Goyal, + +package shm + +import ( + "errors" + "fmt" + + "golang.org/x/sys/unix" +) + +var _ = fmt.Print + +func Fallocate_simple(fd int, size int64) (err error) { + for { + if err = unix.Fallocate(fd, 0, 0, size); !errors.Is(err, unix.EINTR) { + return + } + } +} diff --git a/tools/utils/shm/fallocate_other.go b/tools/utils/shm/fallocate_other.go new file mode 100644 index 000000000..4481a592a --- /dev/null +++ b/tools/utils/shm/fallocate_other.go @@ -0,0 +1,16 @@ +// License: GPLv3 Copyright: 2023, Kovid Goyal, + +//go:build !darwin && !linux + +package shm + +import ( + "fmt" + "golang.org/x/sys/unix" +) + +var _ = fmt.Print + +func Fallocate_simple(fd int, size int64) (err error) { + return unix.ENOSYS +} diff --git a/tools/utils/shm/shm.go b/tools/utils/shm/shm.go index 3c512c217..36f0931e4 100644 --- a/tools/utils/shm/shm.go +++ b/tools/utils/shm/shm.go @@ -92,11 +92,19 @@ func CreateTemp(pattern string, size uint64) (MMap, error) { return create_temp(pattern, size) } +var force_use_of_fallocate bool = false + func truncate_or_unlink(ans *os.File, size uint64) (err error) { - for { - err = unix.Ftruncate(int(ans.Fd()), int64(size)) - if !errors.Is(err, unix.EINTR) { - break + fd := int(ans.Fd()) + if err = Fallocate_simple(fd, int64(size)); err != nil { + if force_use_of_fallocate { + return err + } + for { + err = unix.Ftruncate(fd, int64(size)) + if !errors.Is(err, unix.EINTR) { + break + } } } if err != nil { @@ -152,7 +160,7 @@ func ReadWithSizeAndUnlink(name string, file_callback ...func(fs.FileInfo) error } defer func() { mmap.Close() - mmap.Unlink() + _ = mmap.Unlink() }() slice, err := ReadWithSize(mmap, 0) if err != nil { @@ -164,7 +172,10 @@ func ReadWithSizeAndUnlink(name string, file_callback ...func(fs.FileInfo) error } func Read(self MMap, b []byte) (n int, err error) { - pos, _ := self.Seek(0, io.SeekCurrent) + pos, err := self.Seek(0, io.SeekCurrent) + if err != nil { + return 0, err + } if pos < 0 { pos = 0 } @@ -174,7 +185,7 @@ func Read(self MMap, b []byte) (n int, err error) { return 0, io.EOF } n = copy(b, s[pos:]) - self.Seek(int64(n), io.SeekCurrent) + _, err = self.Seek(int64(n), io.SeekCurrent) return } @@ -191,7 +202,9 @@ func Write(self MMap, b []byte) (n int, err error) { return 0, io.ErrShortWrite } n = copy(s[pos:], b) - self.Seek(int64(n), io.SeekCurrent) + if _, err = self.Seek(int64(n), io.SeekCurrent); err != nil { + return n, err + } if n < len(b) { return n, io.ErrShortWrite } @@ -220,7 +233,9 @@ func test_integration_with_python(args []string) (rc int, err error) { if err != nil { return 1, err } - WriteWithSize(mmap, data, 0) + if err = WriteWithSize(mmap, data, 0); err != nil { + return 1, err + } mmap.Close() fmt.Println(mmap.Name()) } diff --git a/tools/utils/shm/shm_test.go b/tools/utils/shm/shm_test.go index 086731f8e..5115bdb74 100644 --- a/tools/utils/shm/shm_test.go +++ b/tools/utils/shm/shm_test.go @@ -9,14 +9,17 @@ import ( "io/fs" "os" "reflect" + "runtime" "testing" ) var _ = fmt.Print func TestSHM(t *testing.T) { + force_use_of_fallocate = runtime.GOOS == "darwin" || runtime.GOOS == "linux" + defer func() { force_use_of_fallocate = false }() data := make([]byte, 13347) - rand.Read(data) + _, _ = rand.Read(data) mm, err := CreateTemp("test-kitty-shm-", uint64(len(data))) if err != nil { t.Fatal(err)