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.

Reply via email to