Merge pull request #296 from libgit2/cmn/track-real-pointers
handles: use real pointers to keep track of handles
This commit is contained in:
commit
fa644d2fc9
56
handles.go
56
handles.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue