Files
gopeed/pkg/download/engine/ffmpeg/memory_windows.go
T

71 lines
2.0 KiB
Go

//go:build windows && (amd64 || arm64)
package ffmpeg
import (
"context"
"fmt"
"unsafe"
"github.com/tetratelabs/wazero/experimental"
"golang.org/x/sys/windows"
)
// Keep large, short-lived WASM buffers out of the Go heap. Closing a module
// releases its committed pages immediately, without waiting for GC/scavenging.
func withLinearMemory(ctx context.Context) (context.Context, func()) {
return withOwnedMemory(ctx, experimental.MemoryAllocatorFunc(
func(_, max uint64) experimental.LinearMemory {
return &windowsLinearMemory{max: max}
}))
}
// Reserve the address range once, committing zero-filled pages on demand. This
// avoids both copying the previous buffer and temporarily retaining two large
// Go allocations when memory.grow runs. The backing address never changes.
type windowsLinearMemory struct {
address uintptr
max uint64
size uint64
freed bool
}
func (m *windowsLinearMemory) Reallocate(size uint64) []byte {
if m.freed || size > m.max || m.max > uint64(^uint(0)>>1) {
return nil
}
if size == 0 {
return []byte{}
}
if m.address == 0 {
address, err := windows.VirtualAlloc(0, uintptr(m.max), windows.MEM_RESERVE, windows.PAGE_READWRITE)
if err != nil {
panic(fmt.Errorf("ffmpeg: reserve WASM memory: %w", err))
}
m.address = address
}
if size > m.size {
_, err := windows.VirtualAlloc(m.address, uintptr(size), windows.MEM_COMMIT, windows.PAGE_READWRITE)
if err != nil {
if m.size == 0 {
// Instantiation cannot proceed without the minimum memory. Wazero
// has not taken ownership yet, so release the reservation here.
m.Free()
panic(fmt.Errorf("ffmpeg: commit WASM memory: %w", err))
}
return nil // memory.grow reports failure to the guest.
}
m.size = size
}
return unsafe.Slice((*byte)(unsafe.Pointer(m.address)), int(size))
}
func (m *windowsLinearMemory) Free() {
if m.address != 0 {
_ = windows.VirtualFree(m.address, 0, windows.MEM_RELEASE)
m.address = 0
}
m.size = 0
m.freed = true
}