12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- // Copyright 2021 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found at https://github.com/golang/go/blob/master/LICENSE.
- package frankenphp
- import (
- "sync"
- "sync/atomic"
- )
- // handle is based on the CL here: https://go-review.googlesource.com/c/go/+/600875
- type handle uintptr
- // slot represents a slot in the handles slice for concurrent access.
- type slot struct {
- value any
- }
- var (
- handles []*atomic.Pointer[slot]
- releasedIdx sync.Pool
- nilSlot = &slot{}
- growLock sync.RWMutex
- handLen atomic.Uint64
- )
- func init() {
- handles = make([]*atomic.Pointer[slot], 0)
- handLen = atomic.Uint64{}
- releasedIdx.New = func() interface{} {
- return nil
- }
- growLock = sync.RWMutex{}
- }
- func newHandle(v any) handle {
- var h uint64 = 1
- s := &slot{value: v}
- for {
- if released := releasedIdx.Get(); released != nil {
- h = released.(uint64)
- }
- if h > handLen.Load() {
- growLock.Lock()
- handles = append(handles, &atomic.Pointer[slot]{})
- handLen.Store(uint64(len(handles)))
- growLock.Unlock()
- }
- growLock.RLock()
- if handles[h-1].CompareAndSwap(nilSlot, s) {
- growLock.RUnlock()
- return handle(h)
- } else if handles[h-1].CompareAndSwap(nil, s) {
- growLock.RUnlock()
- return handle(h)
- } else {
- h++
- }
- growLock.RUnlock()
- }
- }
- func (h handle) Value() any {
- growLock.RLock()
- defer growLock.RUnlock()
- if h > handle(len(handles)) {
- panic("runtime/cgo: misuse of an invalid handle")
- }
- v := handles[h-1].Load()
- if v == nil || v == nilSlot {
- panic("runtime/cgo: misuse of an released handle")
- }
- return v.value
- }
- func (h handle) Delete() {
- growLock.RLock()
- defer growLock.RUnlock()
- if h == 0 {
- panic("runtime/cgo: misuse of an zero handle")
- }
- if h > handle(len(handles)) {
- panic("runtime/cgo: misuse of an invalid handle")
- }
- if v := handles[h-1].Swap(nilSlot); v == nil || v == nilSlot {
- panic("runtime/cgo: misuse of an released handle")
- }
- //nolint:staticcheck
- releasedIdx.Put(uint64(h))
- }
|