I want to pass a Go instance as an argument to each call from C, like the code below.
I want to merely operate pointers to http.Client instances as opaque pointers in my C code.
I have a few questions.
- How to convert &http.Client to C type?
- How to prevent memory allocated by go from being freed?
- How to convert C.HTTP_CLIENT_HDL type to &http.Client type?
- How to free memory allocated by go?
typedef size_t HTTP_CLIENT_HDL
HTTP_CLIENT_HDL client_hdl = http_new_client();
int res = http_post(client_hdl, ...);
http_free_client(client_hdl);
/*
typedef size_t HTTP_CLIENT_HDL; // correct type?
*/
import "C"
import (
"net/http"
)
//export http_new_client
func http_new_client() (client_hdl C.HTTP_CLIENT_HDL){
client := &http.Client{
...
}
return C.HTTP_CLIENT_HDL(client) // Is correct?
// How to prevent memory allocated to the client variable from being freed?
}
//export http_post
func http_post(client_hdl C.HTTP_CLIENT_HDL, ...) (ret_val C.int) {
client := &http.Client???(client_hdl) // how to convert C.HTTP_CLIENT_HDL to &http.Client?
...
req, err := http.NewRequest("POST", ...)
if err != nil {
return 0
}
...
resp, err := client.Do(req)
...
return 1
}
//export http_free_client
func http_free_client(client_hdl C.HTTP_CLIENT_HDL){
client := &http.Client???(client_hdl) // how to convert C.HTTP_CLIENT_HDL type to &http.Client type?
free???(client) // how to free the memory for client ?
}
Well, Volker is correct:
cgorules dictate that you cannot pass to the C side pointers (references) to Go-allocated memory if that memory contains Go pointers (see this). Well, the full ruleset is more complex but you'd better check the manual.The rationale behind that is that even though no known contemporary implementation of Go employs moving garbage collector, the language spec does not preclude such implementation, which means the Go runtime powering your program must be able to know all the pointers to a particular Go-allocated memory chunk, and be able to update all of them if it so wishes.
So, a proper implementation would be to maintain a map of Go-allocated
*http.Clients to some non-pointer "handles", and make the C code work with them–something like this:Note that this code is not particularly effective as each call to
http_*functions goes through a mutex protecting the map of "handles" to*http.Clients.On a side note: do you really need to allocate
http.Clients? Thenet/httpcode is supposed to either work with the default client,http.DefaultClient, or with a single non-default instance, configured with particular parameters. IOW, you do not need to allocate a newhttp.Clientto perform an HTTP request usingnet/http, so maybe you're solving a non-problem to begin with.