ref.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package seq
  5. //#cgo LDFLAGS: -llog
  6. //#include <android/log.h>
  7. //#include <string.h>
  8. //import "C"
  9. import (
  10. "fmt"
  11. "runtime"
  12. "sync"
  13. )
  14. type countedObj struct {
  15. obj interface{}
  16. cnt int32
  17. }
  18. // also known to bind/java/Seq.java and bind/objc/seq_darwin.m
  19. const NullRefNum = 41
  20. // refs stores Go objects that have been passed to another language.
  21. var refs struct {
  22. sync.Mutex
  23. next int32 // next reference number to use for Go object, always negative
  24. refs map[interface{}]int32
  25. objs map[int32]countedObj
  26. }
  27. func init() {
  28. refs.Lock()
  29. refs.next = -24 // Go objects get negative reference numbers. Arbitrary starting point.
  30. refs.refs = make(map[interface{}]int32)
  31. refs.objs = make(map[int32]countedObj)
  32. refs.Unlock()
  33. }
  34. // A Ref represents a Java or Go object passed across the language
  35. // boundary.
  36. type Ref struct {
  37. Bind_Num int32
  38. }
  39. type proxy interface {
  40. // Use a strange name and hope that user code does not implement it
  41. Bind_proxy_refnum__() int32
  42. }
  43. // ToRefNum increments the reference count for an object and
  44. // returns its refnum.
  45. func ToRefNum(obj interface{}) int32 {
  46. // We don't track foreign objects, so if obj is a proxy
  47. // return its refnum.
  48. if r, ok := obj.(proxy); ok {
  49. refnum := r.Bind_proxy_refnum__()
  50. if refnum <= 0 {
  51. panic(fmt.Errorf("seq: proxy contained invalid Go refnum: %d", refnum))
  52. }
  53. return refnum
  54. }
  55. refs.Lock()
  56. num := refs.refs[obj]
  57. if num != 0 {
  58. s := refs.objs[num]
  59. refs.objs[num] = countedObj{s.obj, s.cnt + 1}
  60. } else {
  61. num = refs.next
  62. refs.next--
  63. if refs.next > 0 {
  64. panic("refs.next underflow")
  65. }
  66. refs.refs[obj] = num
  67. refs.objs[num] = countedObj{obj, 1}
  68. }
  69. refs.Unlock()
  70. return num
  71. }
  72. // FromRefNum returns the Ref for a refnum. If the refnum specifies a
  73. // foreign object, a finalizer is set to track its lifetime.
  74. func FromRefNum(num int32) *Ref {
  75. if num == NullRefNum {
  76. return nil
  77. }
  78. ref := &Ref{num}
  79. if num > 0 {
  80. // This is a foreign object reference.
  81. // Track its lifetime with a finalizer.
  82. runtime.SetFinalizer(ref, FinalizeRef)
  83. }
  84. return ref
  85. }
  86. // Bind_IncNum increments the foreign reference count and
  87. // return the refnum.
  88. func (r *Ref) Bind_IncNum() int32 {
  89. refnum := r.Bind_Num
  90. IncForeignRef(refnum)
  91. // Make sure this reference is not finalized before
  92. // the foreign reference count is incremented.
  93. runtime.KeepAlive(r)
  94. return refnum
  95. }
  96. // Get returns the underlying object.
  97. func (r *Ref) Get() interface{} {
  98. refnum := r.Bind_Num
  99. refs.Lock()
  100. o, ok := refs.objs[refnum]
  101. refs.Unlock()
  102. if !ok {
  103. panic(fmt.Sprintf("unknown ref %d", refnum))
  104. }
  105. // This is a Go reference and its refnum was incremented
  106. // before crossing the language barrier.
  107. Delete(refnum)
  108. return o.obj
  109. }
  110. // Inc increments the reference count for a refnum. Called from Bind_proxy_refnum
  111. // functions.
  112. func Inc(num int32) {
  113. refs.Lock()
  114. o, ok := refs.objs[num]
  115. if !ok {
  116. panic(fmt.Sprintf("seq.Inc: unknown refnum: %d", num))
  117. }
  118. refs.objs[num] = countedObj{o.obj, o.cnt + 1}
  119. refs.Unlock()
  120. }
  121. // Delete decrements the reference count and removes the pinned object
  122. // from the object map when the reference count becomes zero.
  123. func Delete(num int32) {
  124. refs.Lock()
  125. defer refs.Unlock()
  126. o, ok := refs.objs[num]
  127. if !ok {
  128. panic(fmt.Sprintf("seq.Delete unknown refnum: %d", num))
  129. }
  130. if o.cnt <= 1 {
  131. delete(refs.objs, num)
  132. delete(refs.refs, o.obj)
  133. } else {
  134. refs.objs[num] = countedObj{o.obj, o.cnt - 1}
  135. }
  136. }