mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-23 04:06:39 +00:00
1e7b32490d
This allows for building GoToSocial with [SQLite transpiled to WASM](https://github.com/ncruces/go-sqlite3) and accessed through [Wazero](https://wazero.io/).
98 lines
2.3 KiB
Go
98 lines
2.3 KiB
Go
//go:build (darwin || linux) && (amd64 || arm64 || riscv64) && !(sqlite3_noshm || sqlite3_nosys)
|
|
|
|
package util
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"unsafe"
|
|
|
|
"github.com/tetratelabs/wazero/api"
|
|
"github.com/tetratelabs/wazero/experimental"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func withAllocator(ctx context.Context) context.Context {
|
|
return experimental.WithMemoryAllocator(ctx,
|
|
experimental.MemoryAllocatorFunc(virtualAlloc))
|
|
}
|
|
|
|
type mmapState struct {
|
|
regions []*MappedRegion
|
|
}
|
|
|
|
func (s *mmapState) new(ctx context.Context, mod api.Module, size int32) *MappedRegion {
|
|
// Find unused region.
|
|
for _, r := range s.regions {
|
|
if !r.used && r.size == size {
|
|
return r
|
|
}
|
|
}
|
|
|
|
// Allocate page aligned memmory.
|
|
alloc := mod.ExportedFunction("aligned_alloc")
|
|
stack := [2]uint64{
|
|
uint64(unix.Getpagesize()),
|
|
uint64(size),
|
|
}
|
|
if err := alloc.CallWithStack(ctx, stack[:]); err != nil {
|
|
panic(err)
|
|
}
|
|
if stack[0] == 0 {
|
|
panic(OOMErr)
|
|
}
|
|
|
|
// Save the newly allocated region.
|
|
ptr := uint32(stack[0])
|
|
buf := View(mod, ptr, uint64(size))
|
|
addr := uintptr(unsafe.Pointer(&buf[0]))
|
|
s.regions = append(s.regions, &MappedRegion{
|
|
Ptr: ptr,
|
|
addr: addr,
|
|
size: size,
|
|
})
|
|
return s.regions[len(s.regions)-1]
|
|
}
|
|
|
|
type MappedRegion struct {
|
|
addr uintptr
|
|
Ptr uint32
|
|
size int32
|
|
used bool
|
|
}
|
|
|
|
func MapRegion(ctx context.Context, mod api.Module, f *os.File, offset int64, size int32, prot int) (*MappedRegion, error) {
|
|
s := ctx.Value(moduleKey{}).(*moduleState)
|
|
r := s.new(ctx, mod, size)
|
|
err := r.mmap(f, offset, prot)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
func (r *MappedRegion) Unmap() error {
|
|
// We can't munmap the region, otherwise it could be remaped.
|
|
// Instead, convert it to a protected, private, anonymous mapping.
|
|
// If successful, it can be reused for a subsequent mmap.
|
|
_, err := mmap(r.addr, uintptr(r.size),
|
|
unix.PROT_NONE, unix.MAP_PRIVATE|unix.MAP_ANON|unix.MAP_FIXED,
|
|
-1, 0)
|
|
r.used = err != nil
|
|
return err
|
|
}
|
|
|
|
func (r *MappedRegion) mmap(f *os.File, offset int64, prot int) error {
|
|
_, err := mmap(r.addr, uintptr(r.size),
|
|
prot, unix.MAP_SHARED|unix.MAP_FIXED,
|
|
int(f.Fd()), offset)
|
|
r.used = err == nil
|
|
return err
|
|
}
|
|
|
|
// We need the low level mmap for MAP_FIXED to work.
|
|
// Bind the syscall version hoping that it is more stable.
|
|
|
|
//go:linkname mmap syscall.mmap
|
|
func mmap(addr, length uintptr, prot, flag, fd int, pos int64) (*byte, error)
|