// Copyright 2026 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build darwin || linux || openbsd package unix import "unsafe" // minIovec is the size of the small initial allocation used by // Readv, Writev, etc. // // This small allocation gets stack allocated, which lets the // common use case of len(iovs) <= minIovec avoid more expensive // heap allocations. const minIovec = 8 // appendBytes converts bs to Iovecs and appends them to vecs. func appendBytes(vecs []Iovec, bs [][]byte) []Iovec { for _, b := range bs { var v Iovec v.SetLen(len(b)) if len(b) > 0 { v.Base = &b[0] } else { v.Base = (*byte)(unsafe.Pointer(&_zero)) } vecs = append(vecs, v) } return vecs } // writevRaceDetect tells the race detector that the program // has read the first n bytes stored in iovecs. func writevRaceDetect(iovecs []Iovec, n int) { if !raceenabled { return } for i := 0; n > 0 && i < len(iovecs); i++ { m := min(int(iovecs[i].Len), n) n -= m if m > 0 { raceReadRange(unsafe.Pointer(iovecs[i].Base), m) } } } // readvRaceDetect tells the race detector that the program // has written to the first n bytes stored in iovecs. func readvRaceDetect(iovecs []Iovec, n int, err error) { if !raceenabled { return } for i := 0; n > 0 && i < len(iovecs); i++ { m := min(int(iovecs[i].Len), n) n -= m if m > 0 { raceWriteRange(unsafe.Pointer(iovecs[i].Base), m) } } if err == nil { raceAcquire(unsafe.Pointer(&ioSync)) } } func Readv(fd int, iovs [][]byte) (n int, err error) { iovecs := make([]Iovec, 0, minIovec) iovecs = appendBytes(iovecs, iovs) n, err = readv(fd, iovecs) readvRaceDetect(iovecs, n, err) return n, err } func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) { iovecs := make([]Iovec, 0, minIovec) iovecs = appendBytes(iovecs, iovs) n, err = preadv(fd, iovecs, offset) readvRaceDetect(iovecs, n, err) return n, err } func Writev(fd int, iovs [][]byte) (n int, err error) { iovecs := make([]Iovec, 0, minIovec) iovecs = appendBytes(iovecs, iovs) if raceenabled { raceReleaseMerge(unsafe.Pointer(&ioSync)) } n, err = writev(fd, iovecs) writevRaceDetect(iovecs, n) return n, err } func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) { iovecs := make([]Iovec, 0, minIovec) iovecs = appendBytes(iovecs, iovs) if raceenabled { raceReleaseMerge(unsafe.Pointer(&ioSync)) } n, err = pwritev(fd, iovecs, offset) writevRaceDetect(iovecs, n) return n, err }