| package git |
| |
| import ( |
| "fmt" |
| "sync" |
| "unsafe" |
| ) |
| |
| type HandleList struct { |
| sync.RWMutex |
| // stores the Go pointers |
| handles []interface{} |
| // Indicates which indices are in use, and keeps a pointer to slot int variable (the handle) |
| // in the Go world, so that the Go garbage collector does not free it. |
| set map[int]*int |
| } |
| |
| func NewHandleList() *HandleList { |
| return &HandleList{ |
| handles: make([]interface{}, 5), |
| set: make(map[int]*int), |
| } |
| } |
| |
| // findUnusedSlot finds the smallest-index empty space in our |
| // list. You must only run this function while holding a write lock. |
| func (v *HandleList) findUnusedSlot() int { |
| for i := 1; i < len(v.handles); i++ { |
| _, isUsed := v.set[i] |
| if !isUsed { |
| return i |
| } |
| } |
| |
| // reaching here means we've run out of entries so append and |
| // return the new index, which is equal to the old length. |
| slot := len(v.handles) |
| v.handles = append(v.handles, nil) |
| |
| return slot |
| } |
| |
| // Track adds the given pointer to the list of pointers to track and |
| // returns a pointer value which can be passed to C as an opaque |
| // pointer. |
| func (v *HandleList) Track(pointer interface{}) unsafe.Pointer { |
| v.Lock() |
| |
| slot := v.findUnusedSlot() |
| v.handles[slot] = pointer |
| v.set[slot] = &slot // Keep a pointer to slot in Go world, so it's not freed by GC. |
| |
| v.Unlock() |
| |
| return unsafe.Pointer(&slot) |
| } |
| |
| // Untrack stops tracking the pointer given by the handle |
| func (v *HandleList) Untrack(handle unsafe.Pointer) { |
| slot := *(*int)(handle) |
| |
| v.Lock() |
| |
| v.handles[slot] = nil |
| delete(v.set, slot) |
| |
| v.Unlock() |
| } |
| |
| // Get retrieves the pointer from the given handle |
| func (v *HandleList) Get(handle unsafe.Pointer) interface{} { |
| slot := *(*int)(handle) |
| |
| v.RLock() |
| |
| if _, ok := v.set[slot]; !ok { |
| panic(fmt.Sprintf("invalid pointer handle: %p", handle)) |
| } |
| |
| ptr := v.handles[slot] |
| |
| v.RUnlock() |
| |
| return ptr |
| } |