-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
In go1.6, cgo rules regarding the passing of Go pointers to C libraries changed to prevent unsafe interactions with the Go garbage collector. We need to change so that we pass an indirect reference to the Go object to the c-runtime. This code has been tested to the extent that is required to address the particular panic reported with #4 However, a more extensive regression test has not yet been performed. Signed-off-by: Jon Seymour <[email protected]>
- Loading branch information
Jon Seymour
committed
Mar 26, 2016
1 parent
e77291c
commit 62c8441
Showing
7 changed files
with
120 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
typedef struct shareable { | ||
int sharedIndex; | ||
} shareable; | ||
|
||
shareable * newShareable(int i); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package openzwave | ||
|
||
import "testing" | ||
|
||
func Test_RoundtripMarshaling(t *testing.T) { | ||
a := &api{} | ||
a.init(a) | ||
c := a.C() | ||
aa := unmarshal(c).Go().(*api) | ||
if a != aa { | ||
t.Fatalf("failed to round trip") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#include "api.h" | ||
|
||
shareable * newShareable(int i) { | ||
shareable * r = (shareable *) malloc(sizeof(shareable)); | ||
r->sharedIndex = i; | ||
return r; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package openzwave | ||
|
||
// #cgo LDFLAGS: -lopenzwave -Lgo/src/github.com/ninjasphere/go-openzwave/openzwave | ||
// #cgo CPPFLAGS: -Iopenzwave/cpp/src/platform -Iopenzwave/cpp/src -Iopenzwave/cpp/src/value_classes | ||
// #include "api.h" | ||
import "C" | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
"unsafe" | ||
) | ||
|
||
// This module fixes an issue revealed when Go 1.6 tightened up the rules | ||
// about sharing of Go pointers with C code. https://github.com/golang/go/issues/12416 | ||
// | ||
// Now we register a reference with a map and get a pointer to a structure in the C heap on return. | ||
// We use the integer recorded in this structure to map back into the Go world. | ||
// | ||
// That way there are O(1) marshaling operations, and Go pointer is never shared with or | ||
// dereferenced by the C world | ||
// | ||
var shared = map[int]Shareable{} | ||
var sharedCount = 0 | ||
var mu sync.RWMutex | ||
|
||
type Shareable interface { | ||
C() unsafe.Pointer | ||
Go() interface{} | ||
} | ||
|
||
type shareable struct { | ||
cref *C.shareable | ||
goObject interface{} | ||
} | ||
|
||
func (s *shareable) init(goObject interface{}) { | ||
mu.Lock() | ||
defer mu.Unlock() | ||
|
||
sharedCount++ | ||
s.cref = C.newShareable(C.int(sharedCount)) | ||
shared[int(s.cref.sharedIndex)] = s | ||
s.goObject = goObject | ||
} | ||
|
||
func (s *shareable) destroy() { | ||
if s.cref != nil { | ||
mu.Lock() | ||
defer mu.Unlock() | ||
delete(shared, int(s.cref.sharedIndex)) | ||
C.free(s.C()) | ||
s.cref = nil | ||
} | ||
} | ||
|
||
func (s *shareable) C() unsafe.Pointer { | ||
return unsafe.Pointer(s.cref) | ||
} | ||
|
||
func (s *shareable) Go() interface{} { | ||
if s == nil { | ||
return nil | ||
} else { | ||
return s.goObject | ||
} | ||
} | ||
|
||
func unmarshal(c unsafe.Pointer) Shareable { | ||
mu.RLock() | ||
defer mu.RUnlock() | ||
|
||
i := (*C.shareable)(c).sharedIndex | ||
if i == 0 { | ||
return nil | ||
} else { | ||
if s, ok := shared[int(i)]; !ok { | ||
panic(fmt.Errorf("failure to unmarshal index %d", int(i))) | ||
} else { | ||
return s | ||
} | ||
} | ||
} |