readv_unix.go (2581B)
1 // Copyright 2026 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build darwin || linux || openbsd 6 7 package unix 8 9 import "unsafe" 10 11 // minIovec is the size of the small initial allocation used by 12 // Readv, Writev, etc. 13 // 14 // This small allocation gets stack allocated, which lets the 15 // common use case of len(iovs) <= minIovec avoid more expensive 16 // heap allocations. 17 const minIovec = 8 18 19 // appendBytes converts bs to Iovecs and appends them to vecs. 20 func appendBytes(vecs []Iovec, bs [][]byte) []Iovec { 21 for _, b := range bs { 22 var v Iovec 23 v.SetLen(len(b)) 24 if len(b) > 0 { 25 v.Base = &b[0] 26 } else { 27 v.Base = (*byte)(unsafe.Pointer(&_zero)) 28 } 29 vecs = append(vecs, v) 30 } 31 return vecs 32 } 33 34 // writevRaceDetect tells the race detector that the program 35 // has read the first n bytes stored in iovecs. 36 func writevRaceDetect(iovecs []Iovec, n int) { 37 if !raceenabled { 38 return 39 } 40 for i := 0; n > 0 && i < len(iovecs); i++ { 41 m := min(int(iovecs[i].Len), n) 42 n -= m 43 if m > 0 { 44 raceReadRange(unsafe.Pointer(iovecs[i].Base), m) 45 } 46 } 47 } 48 49 // readvRaceDetect tells the race detector that the program 50 // has written to the first n bytes stored in iovecs. 51 func readvRaceDetect(iovecs []Iovec, n int, err error) { 52 if !raceenabled { 53 return 54 } 55 for i := 0; n > 0 && i < len(iovecs); i++ { 56 m := min(int(iovecs[i].Len), n) 57 n -= m 58 if m > 0 { 59 raceWriteRange(unsafe.Pointer(iovecs[i].Base), m) 60 } 61 } 62 if err == nil { 63 raceAcquire(unsafe.Pointer(&ioSync)) 64 } 65 } 66 67 func Readv(fd int, iovs [][]byte) (n int, err error) { 68 iovecs := make([]Iovec, 0, minIovec) 69 iovecs = appendBytes(iovecs, iovs) 70 n, err = readv(fd, iovecs) 71 readvRaceDetect(iovecs, n, err) 72 return n, err 73 } 74 75 func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) { 76 iovecs := make([]Iovec, 0, minIovec) 77 iovecs = appendBytes(iovecs, iovs) 78 n, err = preadv(fd, iovecs, offset) 79 readvRaceDetect(iovecs, n, err) 80 return n, err 81 } 82 83 func Writev(fd int, iovs [][]byte) (n int, err error) { 84 iovecs := make([]Iovec, 0, minIovec) 85 iovecs = appendBytes(iovecs, iovs) 86 if raceenabled { 87 raceReleaseMerge(unsafe.Pointer(&ioSync)) 88 } 89 n, err = writev(fd, iovecs) 90 writevRaceDetect(iovecs, n) 91 return n, err 92 } 93 94 func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) { 95 iovecs := make([]Iovec, 0, minIovec) 96 iovecs = appendBytes(iovecs, iovs) 97 if raceenabled { 98 raceReleaseMerge(unsafe.Pointer(&ioSync)) 99 } 100 n, err = pwritev(fd, iovecs, offset) 101 writevRaceDetect(iovecs, n) 102 return n, err 103 }