Source file
src/os/zero_copy_linux.go
1
2
3
4
5 package os
6
7 import (
8 "internal/poll"
9 "io"
10 "syscall"
11 )
12
13 var (
14 pollCopyFileRange = poll.CopyFileRange
15 pollSplice = poll.Splice
16 )
17
18 func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) {
19 pfd, network := getPollFDAndNetwork(w)
20
21 if pfd == nil || !pfd.IsStream || !isUnixOrTCP(string(network)) {
22 return
23 }
24
25 sc, err := f.SyscallConn()
26 if err != nil {
27 return
28 }
29
30 rerr := sc.Read(func(fd uintptr) (done bool) {
31 written, err, handled = poll.SendFile(pfd, int(fd), 0)
32 return true
33 })
34
35 if err == nil {
36 err = rerr
37 }
38
39 return written, handled, wrapSyscallError("sendfile", err)
40 }
41
42 func (f *File) readFrom(r io.Reader) (written int64, handled bool, err error) {
43
44
45
46
47
48 if f.appendMode {
49 return 0, false, nil
50 }
51
52 written, handled, err = f.copyFileRange(r)
53 if handled {
54 return
55 }
56 return f.spliceToFile(r)
57 }
58
59 func (f *File) spliceToFile(r io.Reader) (written int64, handled bool, err error) {
60 var (
61 remain int64
62 lr *io.LimitedReader
63 )
64 if lr, r, remain = tryLimitedReader(r); remain <= 0 {
65 return 0, true, nil
66 }
67
68 pfd, _ := getPollFDAndNetwork(r)
69
70
71
72
73
74
75
76 if pfd == nil || !pfd.IsStream {
77 return
78 }
79
80 written, handled, err = pollSplice(&f.pfd, pfd, remain)
81
82 if lr != nil {
83 lr.N = remain - written
84 }
85
86 return written, handled, wrapSyscallError("splice", err)
87 }
88
89 func (f *File) copyFileRange(r io.Reader) (written int64, handled bool, err error) {
90 var (
91 remain int64
92 lr *io.LimitedReader
93 )
94 if lr, r, remain = tryLimitedReader(r); remain <= 0 {
95 return 0, true, nil
96 }
97
98 var src *File
99 switch v := r.(type) {
100 case *File:
101 src = v
102 case fileWithoutWriteTo:
103 src = v.File
104 default:
105 return 0, false, nil
106 }
107
108 if src.checkValid("ReadFrom") != nil {
109
110
111 return 0, false, nil
112 }
113
114 written, handled, err = pollCopyFileRange(&f.pfd, &src.pfd, remain)
115 if lr != nil {
116 lr.N -= written
117 }
118 return written, handled, wrapSyscallError("copy_file_range", err)
119 }
120
121
122
123
124 func getPollFDAndNetwork(i any) (*poll.FD, poll.String) {
125 sc, ok := i.(syscall.Conn)
126 if !ok {
127 return nil, ""
128 }
129 rc, err := sc.SyscallConn()
130 if err != nil {
131 return nil, ""
132 }
133 irc, ok := rc.(interface {
134 PollFD() *poll.FD
135 Network() poll.String
136 })
137 if !ok {
138 return nil, ""
139 }
140 return irc.PollFD(), irc.Network()
141 }
142
143 func isUnixOrTCP(network string) bool {
144 switch network {
145 case "tcp", "tcp4", "tcp6", "unix":
146 return true
147 default:
148 return false
149 }
150 }
151
View as plain text