handles: use real pointers to keep track of handles
With the change to 1.6 rules, we couldn't use the Go pointers, so we went with casting the list indices into pointers. The runtime does not like this, however. It will sometimes detect that we have a pointer with a very small value and consider it an invalid pointer, bringing down the application with it. Work around that by asking libc for the smallest amount of memory it'll give us so we have an actual allocated pointer to use. We then use this pointer value as the key in our map to find the Go object we're tracking.
This commit is contained in:
parent
f05417aaba
commit
f1240e6565
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