diff --git a/func.go b/func.go index 0da2c269..9b9f0b23 100644 --- a/func.go +++ b/func.go @@ -10,7 +10,6 @@ import ( "math" "reflect" "runtime" - "sync" "unsafe" "github.com/ebitengine/purego/internal/strings" @@ -22,10 +21,6 @@ const ( align8ByteSize = 8 // 8-byte alignment boundary ) -var thePool = sync.Pool{New: func() any { - return new(syscall15Args) -}} - // RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name). // It panics if it can't find the name symbol. func RegisterLibFunc(fptr any, handle uintptr, name string) { @@ -310,8 +305,7 @@ func RegisterFunc(fptr any, cfn uintptr) { keepAlive = addValue(v, keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack) } - syscall := thePool.Get().(*syscall15Args) - defer thePool.Put(syscall) + syscall := &syscall15Args{} if runtime.GOARCH == "loong64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "s390x" { syscall.Set(cfn, sysargs[:], floats[:], 0) @@ -321,7 +315,6 @@ func RegisterFunc(fptr any, cfn uintptr) { syscall.Set(cfn, sysargs[:], floats[:], arm64_r8) runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall)) } else { - *syscall = syscall15Args{} // This is a fallback for Windows amd64, 386, and arm. Note this may not support floats syscall.a1, syscall.a2, _ = syscall_syscall15X(cfn, sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11], diff --git a/func_test.go b/func_test.go index 6ae69c40..64fe599f 100644 --- a/func_test.go +++ b/func_test.go @@ -11,6 +11,7 @@ import ( "path/filepath" "runtime" "strings" + "sync" "testing" "unsafe" @@ -35,6 +36,40 @@ func getSystemLibrary() (string, error) { } } +func TestRegisterFunc_ConcurrentPointerReturn(t *testing.T) { + library, err := getSystemLibrary() + if err != nil { + t.Fatalf("couldn't get system library: %s", err) + } + libc, err := load.OpenLibrary(library) + if err != nil { + t.Fatalf("failed to dlopen: %s", err) + } + + var alloc func(uint64) *byte + var free func(*byte) + purego.RegisterLibFunc(&alloc, libc, "malloc") + purego.RegisterLibFunc(&free, libc, "free") + + var wg sync.WaitGroup + + for i := 0; i < runtime.NumCPU(); i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 0; j < 400_000; j++ { + ptr := alloc(5) + if ptr == nil { + continue + } + free(ptr) + } + }(i) + } + + wg.Wait() +} + func TestRegisterFunc(t *testing.T) { library, err := getSystemLibrary() if err != nil { diff --git a/syscall_sysv.go b/syscall_sysv.go index e35b32e7..f6e9e29b 100644 --- a/syscall_sysv.go +++ b/syscall_sysv.go @@ -16,10 +16,7 @@ import ( var syscall15XABI0 uintptr func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) { - args := thePool.Get().(*syscall15Args) - defer thePool.Put(args) - - *args = syscall15Args{ + args := &syscall15Args{ fn: fn, a1: a1, a2: a2, a3: a3, a4: a4, a5: a5, a6: a6, a7: a7, a8: a8, a9: a9, a10: a10, a11: a11, a12: a12, a13: a13, a14: a14, a15: a15,