mirror of
https://github.com/ceph/go-ceph
synced 2024-12-20 21:33:06 +00:00
65 lines
1.9 KiB
Go
65 lines
1.9 KiB
Go
|
package callbacks
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// The logic of this file is largely adapted from:
|
||
|
// https://github.com/golang/go/wiki/cgo#function-variables
|
||
|
//
|
||
|
// Also helpful:
|
||
|
// https://eli.thegreenplace.net/2019/passing-callbacks-and-pointers-to-cgo/
|
||
|
|
||
|
// Callbacks provides a tracker for data that is to be passed between Go
|
||
|
// and C callback functions. The Go callback/object may not be passed
|
||
|
// by a pointer to C code and so instead integer indexes into an internal
|
||
|
// map are used.
|
||
|
// Typically the item being added will either be a callback function or
|
||
|
// a data structure containing a callback function. It is up to the caller
|
||
|
// to control and validate what "callbacks" get used.
|
||
|
type Callbacks struct {
|
||
|
mutex sync.RWMutex
|
||
|
cmap map[int]interface{}
|
||
|
}
|
||
|
|
||
|
// New returns a new callbacks tracker.
|
||
|
func New() *Callbacks {
|
||
|
return &Callbacks{cmap: make(map[int]interface{})}
|
||
|
}
|
||
|
|
||
|
// Add a callback/object to the tracker and return a new index
|
||
|
// for the object.
|
||
|
func (cb *Callbacks) Add(v interface{}) int {
|
||
|
cb.mutex.Lock()
|
||
|
defer cb.mutex.Unlock()
|
||
|
// this approach assumes that there are typically very few callbacks
|
||
|
// in play at once and can just use the length of the map as our
|
||
|
// index. But in case of collisions we fall back to simply incrementing
|
||
|
// until we find a free key like in the cgo wiki page.
|
||
|
// If this code ever becomes a hot path there's surely plenty of room
|
||
|
// for optimization in the future :-)
|
||
|
index := len(cb.cmap) + 1
|
||
|
for {
|
||
|
if _, found := cb.cmap[index]; !found {
|
||
|
break
|
||
|
}
|
||
|
index++
|
||
|
}
|
||
|
cb.cmap[index] = v
|
||
|
return index
|
||
|
}
|
||
|
|
||
|
// Remove a callback/object given it's index.
|
||
|
func (cb *Callbacks) Remove(index int) {
|
||
|
cb.mutex.Lock()
|
||
|
defer cb.mutex.Unlock()
|
||
|
delete(cb.cmap, index)
|
||
|
}
|
||
|
|
||
|
// Lookup returns a mapped callback/object given an index.
|
||
|
func (cb *Callbacks) Lookup(index int) interface{} {
|
||
|
cb.mutex.RLock()
|
||
|
defer cb.mutex.RUnlock()
|
||
|
return cb.cmap[index]
|
||
|
}
|