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