I have read this proposal carefully https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md#proposal 1. Go code may pass a Go pointer to C provided that the Go memory to which it points does not contain any Go pointers.
- The C code must not store any Go pointers in Go memory, even temporarily. - When passing a pointer to a field in a struct, the Go memory in question is the memory occupied by the field, not the entire struct. - When passing a pointer to an element in an array or slice, the Go memory in question is the entire array or the entire backing array of the slice. - *Passing a Go pointer to C code means that that Go pointer is visible to C code; passing one Go pointer does not cause any other Go pointers to become visible.* - *The maximum number of Go pointers that can become visible to C code in a single function call is the number of arguments to the function.* So does it is correct that you cannot call some C api like `writev` safely without concatenating all the byte slices together into one big byte slice? On Saturday, March 13, 2021 at 10:24:52 PM UTC+8 rmfr wrote: > Say here is a C api like `ssize_t writev(const struct iovec *iov, int > iovcnt)` which the definition of iovec is like below: > > ``` > struct iovec { > uint8_t *Base; /* Base address. */ > uint64_t Len; /* Length. */ > }; > ``` > > For C api which like `ssize_t write(const void *buf, size_t nbyte)`, the > solution would be quite straight forward: > > ``` > bs := make([]byte, 1024*1024*512) > // without extra memory allocation and copying of the whole input byte > slice :-D > rc := C.write(unsafe.Pointer(&bs[0]), C.int(len(bs))) > ``` > > But how to call C `writev` style API without extra memory allocation or > copying of the whole byte slice vector? > > ``` > bsv := make([][]byte, 1024) > for i := range bsv{ > bsv[i] = make([]byte, 5*1024*(rand.Intn(i)+1)) > } > // assuming that allocation of a iovec array is acceptable > // but allocation and copying of all bsv[x] byte slice member is > unacceptable > // > iovec := make([]syscall.Iovec, len(bsv)) > for i := range bsv { > bs := bsv[i] > if len(bs) > 0 { > iovec[i].Base = unsafe.Pointer(&bs[0]) > iovec[i].Len = uint64(len(bs)) > } > } > // > // rc := C.writev( /* how? :-( */) > rc := C.writev(unsafe.Pointer(&iovec[0]), C.int(len(iovec))) // Does this > code is right and safe? > ``` > > Does the code above is right? > > I have read cgo's docs carefully, and here is a constraint from > https://golang.org/cmd/cgo/#hdr-Passing_pointers: > > > Go code may pass a Go pointer to C provided the Go memory to which it > points does not contain any Go pointers. > > If the Go memory pointed by `unsafe.Pointer(&iovec[0])` contains pointer > which points to these byte slice members of bsv, so it would be a > *violation* of the cgo constraint above. And that means you could not > call C `writev` style API without allocation and copying of the whole > vector. > > Please correct me if I get something wrong. Thanks a lot :-D > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/ed9086ad-db73-489c-8bd5-dc2c17639ffan%40googlegroups.com.