From dbb5e20a65504eddb797c63d61273406b9f36850 Mon Sep 17 00:00:00 2001 From: Flier Lu Date: Thu, 24 Oct 2024 21:17:36 +0800 Subject: [PATCH 1/2] reducing lock conflicts with handleMap --- internal/handle/go1_15.go | 16 ---------------- internal/handle/go1_17.go | 14 -------------- internal/handle/go1_9.go | 18 ------------------ internal/handle/handle.go | 35 ++++++++++++++++++++++++++++------- 4 files changed, 28 insertions(+), 55 deletions(-) delete mode 100644 internal/handle/go1_15.go delete mode 100644 internal/handle/go1_17.go delete mode 100644 internal/handle/go1_9.go diff --git a/internal/handle/go1_15.go b/internal/handle/go1_15.go deleted file mode 100644 index 70ecbaf..0000000 --- a/internal/handle/go1_15.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build go1.15 && !go1.17 -// +build go1.15,!go1.17 - -package handle - -// Delete invalidates a handle. This method should only be called once -// the program no longer needs to pass the handle to C and the C code -// no longer has a copy of the handle value. -// -// The method panics if the handle is invalid. -func (h Handle) Delete() { - _, ok := handles.LoadAndDelete(uintptr(h)) - if !ok { - panic("runtime/cgo: misuse of an invalid Handle") - } -} diff --git a/internal/handle/go1_17.go b/internal/handle/go1_17.go deleted file mode 100644 index 3b54c0b..0000000 --- a/internal/handle/go1_17.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build go1.17 -// +build go1.17 - -package handle - -import "C" -import "runtime/cgo" - -// Handle provides a way to pass values that contain Go pointers (pointers to memory allocated by Go) -// between Go and C without breaking the cgo pointer passing rules. -type Handle = cgo.Handle - -// New returns a handle for a given value. -var New = cgo.NewHandle diff --git a/internal/handle/go1_9.go b/internal/handle/go1_9.go deleted file mode 100644 index 3d14c8a..0000000 --- a/internal/handle/go1_9.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build go1.9 && !go1.15 -// +build go1.9,!go1.15 - -package handle - -// Delete invalidates a handle. This method should only be called once -// the program no longer needs to pass the handle to C and the C code -// no longer has a copy of the handle value. -// -// The method panics if the handle is invalid. -func (h Handle) Delete() { - _, ok := handles.Load(uintptr(h)) - if ok { - handles.Delete(uintptr(h)) - } else { - panic("runtime/cgo: misuse of an invalid Handle") - } -} diff --git a/internal/handle/handle.go b/internal/handle/handle.go index b24ad85..30394dc 100644 --- a/internal/handle/handle.go +++ b/internal/handle/handle.go @@ -1,12 +1,11 @@ -//go:build !go1.17 -// +build !go1.17 - // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package handle import ( + "runtime" + "strconv" "sync" "sync/atomic" ) @@ -78,7 +77,8 @@ func New(v interface{}) Handle { panic("runtime/cgo: ran out of handle space") } - handles.Store(h, v) + handles(Handle(h)).Store(h, v) + return Handle(h) } @@ -86,14 +86,35 @@ func New(v interface{}) Handle { // // The method panics if the handle is invalid. func (h Handle) Value() interface{} { - v, ok := handles.Load(uintptr(h)) + v, ok := handles(h).Load(uintptr(h)) if !ok { panic("runtime/cgo: misuse of an invalid Handle") } return v } +func (h Handle) Delete() { + _, ok := handles(h).LoadAndDelete(uintptr(h)) + if !ok { + panic("runtime/cgo: misuse of an invalid Handle") + } +} + +func handles(h Handle) *sync.Map { + return &handleMap[uintptr(h)%uintptr(len(handleMap))] +} + var ( - handles = sync.Map{} // map[Handle]interface{} - handleIdx uintptr // atomic + mapSize = "" // --ldflags="-X 'github.com/flier/gohs/internal/handle.mapSize=64'" + handleMap = newHandleMap() // []map[Handle]interface{} + handleIdx uintptr // atomic ) + +func newHandleMap() []sync.Map { + n, err := strconv.Atoi(mapSize) + if err != nil { + n = runtime.NumCPU() * 2 + } + + return make([]sync.Map, n) +} From d5759eab0c59a63b4ce62fb5f788897d5f70920e Mon Sep 17 00:00:00 2001 From: Flier Lu Date: Fri, 25 Oct 2024 10:09:16 +0800 Subject: [PATCH 2/2] add document for Delete --- internal/handle/handle.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/handle/handle.go b/internal/handle/handle.go index 30394dc..d493bcd 100644 --- a/internal/handle/handle.go +++ b/internal/handle/handle.go @@ -93,6 +93,11 @@ func (h Handle) Value() interface{} { return v } +// Delete invalidates a handle. +// This method should only be called once the program no longer needs to pass the handle to C +// and the C code no longer has a copy of the handle value. +// +// The method panics if the handle is invalid. func (h Handle) Delete() { _, ok := handles(h).LoadAndDelete(uintptr(h)) if !ok {