├── LICENSE ├── README.md ├── _example ├── callback.h └── main.go ├── doc.go └── pointer.go /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Yasuhiro Matsumoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-pointer 2 | 3 | Utility for cgo 4 | 5 | ## Usage 6 | 7 | https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md 8 | 9 | In go 1.6, cgo argument can't be passed Go pointer. 10 | 11 | ``` 12 | var s string 13 | C.pass_pointer(pointer.Save(&s)) 14 | v := *(pointer.Restore(C.get_from_pointer()).(*string)) 15 | ``` 16 | 17 | ## Installation 18 | 19 | ``` 20 | go get github.com/mattn/go-pointer 21 | ``` 22 | 23 | ## License 24 | 25 | MIT 26 | 27 | ## Author 28 | 29 | Yasuhiro Matsumoto (a.k.a mattn) 30 | -------------------------------------------------------------------------------- /_example/callback.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef void (*callback)(void*); 4 | 5 | static void call_later(int delay, callback cb, void* data) { 6 | sleep(delay); 7 | cb(data); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /_example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include "callback.h" 5 | 6 | void call_later_go_cb(void*); 7 | */ 8 | import "C" 9 | import ( 10 | "fmt" 11 | "unsafe" 12 | 13 | "github.com/mattn/go-pointer" 14 | ) 15 | 16 | type Foo struct { 17 | v int 18 | } 19 | 20 | func main() { 21 | f := &Foo{123} 22 | C.call_later(3, C.callback(C.call_later_go_cb), pointer.Save(f)) 23 | } 24 | 25 | //export call_later_go_cb 26 | func call_later_go_cb(data unsafe.Pointer) { 27 | f := pointer.Restore(data).(*Foo) 28 | fmt.Println(f.v) 29 | } 30 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | package pointer 2 | -------------------------------------------------------------------------------- /pointer.go: -------------------------------------------------------------------------------- 1 | package pointer 2 | 3 | // #include 4 | import "C" 5 | import ( 6 | "sync" 7 | "unsafe" 8 | ) 9 | 10 | var ( 11 | mutex sync.RWMutex 12 | store = map[unsafe.Pointer]interface{}{} 13 | ) 14 | 15 | func Save(v interface{}) unsafe.Pointer { 16 | if v == nil { 17 | return nil 18 | } 19 | 20 | // Generate real fake C pointer. 21 | // This pointer will not store any data, but will bi used for indexing purposes. 22 | // Since Go doest allow to cast dangling pointer to unsafe.Pointer, we do rally allocate one byte. 23 | // Why we need indexing, because Go doest allow C code to store pointers to Go data. 24 | var ptr unsafe.Pointer = C.malloc(C.size_t(1)) 25 | if ptr == nil { 26 | panic("can't allocate 'cgo-pointer hack index pointer': ptr == nil") 27 | } 28 | 29 | mutex.Lock() 30 | store[ptr] = v 31 | mutex.Unlock() 32 | 33 | return ptr 34 | } 35 | 36 | func Restore(ptr unsafe.Pointer) (v interface{}) { 37 | if ptr == nil { 38 | return nil 39 | } 40 | 41 | mutex.RLock() 42 | v = store[ptr] 43 | mutex.RUnlock() 44 | return 45 | } 46 | 47 | func Unref(ptr unsafe.Pointer) { 48 | if ptr == nil { 49 | return 50 | } 51 | 52 | mutex.Lock() 53 | delete(store, ptr) 54 | mutex.Unlock() 55 | 56 | C.free(ptr) 57 | } 58 | --------------------------------------------------------------------------------