mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-03 22:25:57 +00: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:
parent
911c80aa3b
commit
2e4f3dab41
6 changed files with 94 additions and 11 deletions
|
|
@ -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)
|
||||
|
|
|
|||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue