aboutsummaryrefslogtreecommitdiffstats
path: root/cshared/objects.go
diff options
context:
space:
mode:
Diffstat (limited to 'cshared/objects.go')
-rw-r--r--cshared/objects.go182
1 files changed, 182 insertions, 0 deletions
diff --git a/cshared/objects.go b/cshared/objects.go
new file mode 100644
index 0000000..0517449
--- /dev/null
+++ b/cshared/objects.go
@@ -0,0 +1,182 @@
+// +build ignore
+package main
+
+import (
+ "C"
+ "fmt"
+ "math"
+ "sync"
+ "reflect"
+)
+
+type Handle uint64
+
+const (
+ ErrorCodeSuccess = iota
+ ErrorCodeNotFound = -iota
+ ErrorCodeInternal = -iota
+)
+
+const MessageNotFound string = "object not found"
+const InvalidHandle Handle = 0
+const IH uint64 = uint64(InvalidHandle)
+var counter Handle = InvalidHandle
+var opMutex sync.Mutex
+var registryHandle2Obj map[Handle]interface{} = map[Handle]interface{}{}
+var registryObj2Handle map[uintptr][]Handle = map[uintptr][]Handle{}
+var trace bool = false
+
+func getNewHandle() Handle {
+ counter++
+ if counter == math.MaxUint64 {
+ panic("Handle cache is exhausted")
+ }
+ return counter
+}
+
+func RegisterObject(obj interface{}) Handle {
+ data_ptr := reflect.ValueOf(&obj).Elem().InterfaceData()[1]
+ if trace {
+ fmt.Printf("RegisterObject 0x%x\t%v\n", data_ptr, obj)
+ }
+ opMutex.Lock()
+ defer opMutex.Unlock()
+ handles, ok := registryObj2Handle[data_ptr]
+ if ok {
+ for _, h := range(handles) {
+ other, ok := registryHandle2Obj[h]
+ if !ok {
+ panic("Inconsistent internal object mapping state (1)")
+ }
+ if other == obj {
+ if trace {
+ fmt.Printf("RegisterObject 0x%x reused %d\n", data_ptr, h)
+ }
+ return h
+ }
+ }
+ }
+ handle := getNewHandle()
+ registryHandle2Obj[handle] = obj
+ registryObj2Handle[data_ptr] = append(registryObj2Handle[data_ptr], handle)
+ if trace {
+ c_dump_objects()
+ }
+ return handle
+}
+
+func UnregisterObject(handle Handle) int {
+ if trace {
+ fmt.Printf("UnregisterObject %d\n", handle)
+ }
+ if handle == InvalidHandle {
+ return ErrorCodeNotFound
+ }
+ opMutex.Lock()
+ defer opMutex.Unlock()
+ obj, ok := registryHandle2Obj[handle]
+ if !ok {
+ return ErrorCodeNotFound
+ }
+ delete(registryHandle2Obj, handle)
+ data_ptr := reflect.ValueOf(&obj).Elem().InterfaceData()[1]
+ other_handles, ok := registryObj2Handle[data_ptr]
+ if !ok {
+ panic(fmt.Sprintf("Inconsistent internal object mapping state (2): %d",
+ handle))
+ }
+ hi := -1
+ for i, h := range(other_handles) {
+ if h == handle {
+ hi = i
+ break
+ }
+ }
+ if hi < 0 {
+ panic(fmt.Sprintf("Inconsistent internal object mapping state (3): %d",
+ handle))
+ }
+ if len(other_handles) == 1 {
+ delete(registryObj2Handle, data_ptr)
+ } else {
+ registryObj2Handle[data_ptr] = append(other_handles[:hi], other_handles[hi + 1:]...)
+ }
+ if trace {
+ c_dump_objects()
+ }
+ return ErrorCodeSuccess
+}
+
+func GetObject(handle Handle) (interface{}, bool) {
+ if handle == InvalidHandle {
+ return nil, false
+ }
+ opMutex.Lock()
+ defer opMutex.Unlock()
+ a, b := registryHandle2Obj[handle]
+ return a, b
+}
+
+func GetHandle(obj interface{}) (Handle, bool) {
+ data_ptr := reflect.ValueOf(&obj).Elem().InterfaceData()[1]
+ opMutex.Lock()
+ defer opMutex.Unlock()
+ handles, ok := registryObj2Handle[data_ptr]
+ if !ok {
+ return InvalidHandle, false
+ }
+ for _, h := range(handles) {
+ candidate := registryHandle2Obj[h]
+ if candidate == obj {
+ return h, true
+ }
+ }
+ return InvalidHandle, false
+}
+
+func CopyString(str string) string {
+ buf := make([]byte, len(str))
+ copy(buf, []byte(str))
+ return string(buf)
+}
+
+func SafeIsNil(v reflect.Value) bool {
+ defer func() { recover() }()
+ return v.IsNil()
+}
+
+//export c_dispose
+func c_dispose(handle uint64) {
+ UnregisterObject(Handle(handle))
+}
+
+//export c_objects_size
+func c_objects_size() int {
+ return len(registryHandle2Obj)
+}
+
+//export c_dump_objects
+func c_dump_objects() {
+ fmt.Printf("handles (%d):\n", len(registryHandle2Obj))
+ for h, obj := range(registryHandle2Obj) {
+ fmt.Printf("0x%x\t0x%x %v\n", h,
+ reflect.ValueOf(&obj).Elem().InterfaceData()[1], obj)
+ }
+ fmt.Println()
+ phs := 0
+ for _, h := range(registryObj2Handle) {
+ phs += len(h)
+ }
+ fmt.Printf("pointers (%d):\n", phs)
+ for ptr, h := range(registryObj2Handle) {
+ fmt.Printf("0x%x\t%v\n", ptr, h)
+ }
+}
+
+//export c_set_trace
+func c_set_trace(val bool) {
+ trace = val
+}
+
+// dummy main() is needed by the linker
+func main() {}