mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-11 19:04:08 +00:00
71 lines
2.0 KiB
Go
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
|
|
}
|