driving writev(2) from DispatchData


(Johannes Weiss) #1

Hi swift-corelibs-dev,

I recently found myself with a DispatchData and wanted to use writev(2). So what I need was basically an array of pointers and lengths, not necessarily contiguous. That's exactly what DispatchData is so I thought it should be quite straightforward.

Obviously I need a guarantee that the pointers to the storage of all the DispatchData 'chunks' are all valid until writev returns.

I first checked the C API because it's documented and dispatch_data_apply seems to give me the guarantees that I need:

<quote source="man dispatch_data_apply">
     The dispatch_data_apply() function provides read access to represented memory without requiring it to be mapped as a
     single contiguous region. It traverses the memory regions represented by the data argument in logical order, invokes
     the specified applier block for each region and returns a boolean indicating whether traversal completed success-
     fully. The applier block is passed the following arguments for each memory region and returns a boolean indicating
     whether traversal should continue:
           dispatch_data_t rgn data object representing the region
           size_t offset logical position of the region in data
           const void *loc memory location of the region
           size_t size extent of the region
     The rgn data object is released by the system when the applier block returns. The associated memory location loc is
     valid only as long as rgn has not been deallocated; if loc is needed outside of the applier block, the rgn object
     must be retained in the block.
</quote>

Ie. to guarantee that all the `loc`s I get are still valid, I just need to make sure that all the `rgn`s I get are retained until writev returns. Easy!

Now I wanted to switch to Swift and unfortunately saw that DispatchData.enumerateBytes doesn't give me access to the region so I can't retain it :(.

So how can I achieve that, is it guaranteed that it's good enough to retain the overall DispatchData? Or in code, is this guaranteed to be correct?

extension DispatchData {
    func writeVector(fileDescriptor: Int32) -> ssize_t {
        var iobufs: [iovec] = []
        self.enumerateBytes { (buf, _, _) in
            var iobuf = iovec()
            iobuf.iov_base = UnsafeMutableRawPointer(mutating: buf.baseAddress!)
            iobuf.iov_len = buf.count
            iobufs.append(iobuf)
        }
        return writev(fileDescriptor, iobufs, Int32(iobufs.count))
    }
}

Many thanks,
  Johannes