mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-19 15:04:50 +02:00
Use fallocate() rather than truncate() when creating SHM memory
With truncate() the OS might not actually allocate the space leading to a SIGBUS if /dev/shm runs out of space when actually using the mmap. By using fallocate we ensure that once the SHM mmap is created it wont fail
This commit is contained in:
29
tools/utils/shm/fallocate_darwin.go
Normal file
29
tools/utils/shm/fallocate_darwin.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
20
tools/utils/shm/fallocate_linux.go
Normal file
20
tools/utils/shm/fallocate_linux.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
16
tools/utils/shm/fallocate_other.go
Normal file
16
tools/utils/shm/fallocate_other.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
//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
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user