Merge pull request #296 from libgit2/cmn/track-real-pointers

handles: use real pointers to keep track of handles
This commit is contained in:
Carlos Martín Nieto 2016-02-18 18:43:56 +01:00
commit fa644d2fc9
1 changed files with 15 additions and 41 deletions

View File

@ -1,5 +1,9 @@
package git package git
/*
#include <stdlib.h>
*/
import "C"
import ( import (
"fmt" "fmt"
"sync" "sync"
@ -9,75 +13,45 @@ import (
type HandleList struct { type HandleList struct {
sync.RWMutex sync.RWMutex
// stores the Go pointers // stores the Go pointers
handles []interface{} handles map[unsafe.Pointer]interface{}
// Indicates which indices are in use.
set map[int]bool
} }
func NewHandleList() *HandleList { func NewHandleList() *HandleList {
return &HandleList{ return &HandleList{
handles: make([]interface{}, 5), handles: make(map[unsafe.Pointer]interface{}),
set: make(map[int]bool),
} }
} }
// 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++ {
if !v.set[i] {
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 // 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 // returns a pointer value which can be passed to C as an opaque
// pointer. // pointer.
func (v *HandleList) Track(pointer interface{}) unsafe.Pointer { func (v *HandleList) Track(pointer interface{}) unsafe.Pointer {
handle := C.malloc(1)
v.Lock() v.Lock()
v.handles[handle] = pointer
slot := v.findUnusedSlot()
v.handles[slot] = pointer
v.set[slot] = true
v.Unlock() v.Unlock()
return unsafe.Pointer(uintptr(slot)) return handle
} }
// Untrack stops tracking the pointer given by the handle // Untrack stops tracking the pointer given by the handle
func (v *HandleList) Untrack(handle unsafe.Pointer) { func (v *HandleList) Untrack(handle unsafe.Pointer) {
slot := int(uintptr(handle))
v.Lock() v.Lock()
delete(v.handles, handle)
v.handles[slot] = nil C.free(handle)
delete(v.set, slot)
v.Unlock() v.Unlock()
} }
// Get retrieves the pointer from the given handle // Get retrieves the pointer from the given handle
func (v *HandleList) Get(handle unsafe.Pointer) interface{} { func (v *HandleList) Get(handle unsafe.Pointer) interface{} {
slot := int(uintptr(handle))
v.RLock() v.RLock()
defer v.RUnlock()
if !v.set[slot] { ptr, ok := v.handles[handle]
if !ok {
panic(fmt.Sprintf("invalid pointer handle: %p", handle)) panic(fmt.Sprintf("invalid pointer handle: %p", handle))
} }
ptr := v.handles[slot]
v.RUnlock()
return ptr return ptr
} }