-
Notifications
You must be signed in to change notification settings - Fork 0
/
pointer.go
97 lines (75 loc) · 1.65 KB
/
pointer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package pointer
// #include <stdlib.h>
import "C"
import (
"fmt"
"runtime"
"sync"
"unsafe"
)
var (
mutex sync.RWMutex
store = map[unsafe.Pointer]interface{}{}
stacks = map[unsafe.Pointer][]uintptr{}
)
func Save(v interface{}) unsafe.Pointer {
if v == nil {
return nil
}
// Generate real fake C pointer.
// This pointer will not store any data, but will be used for indexing purposes.
// This way we are keeping a real pointer and don't get casting errors from uintptr->Pointer conversions
var ptr unsafe.Pointer = C.malloc(C.size_t(1))
if ptr == nil {
panic("can't allocate 'cgo-pointer hack index pointer': ptr == nil")
}
pc := make([]uintptr, 10)
n_pc := runtime.Callers(1, pc)
mutex.Lock()
store[ptr] = v
stacks[ptr] = pc[:n_pc]
mutex.Unlock()
return ptr
}
func Restore(ptr unsafe.Pointer) (v interface{}) {
if ptr == nil {
panic("gopointer Restore received nil pointer")
}
mutex.RLock()
v = store[ptr]
mutex.RUnlock()
return
}
func Unref(ptr unsafe.Pointer) {
if ptr == nil {
panic("gopointer Unref received nil pointer")
}
mutex.Lock()
if _, ok := store[ptr]; !ok {
panic("received invalid go-pointer key in Unref")
}
delete(stacks, ptr)
delete(store, ptr)
mutex.Unlock()
C.free(ptr)
}
func DumpStoredPointers() {
mutex.Lock()
if len(store) == 0 {
fmt.Println("No stored gopointers left")
}
for p, t := range store {
pc := stacks[p]
frames := runtime.CallersFrames(pc)
fmt.Printf("%p: %T\n", p, t)
for {
frame, more := frames.Next()
fmt.Printf("- %s\n", frame.Function)
// Check whether there are more frames to process after this one.
if !more {
break
}
}
}
mutex.Unlock()
}