1// Copyright 2011 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 5package poll 6 7import "syscall" 8 9// maxSendfileSize is the largest chunk size we ask the kernel to copy 10// at a time. 11const maxSendfileSize int = 4 << 20 12 13// SendFile wraps the sendfile system call. 14func SendFile(dstFD *FD, src int, remain int64) (written int64, err error, handled bool) { 15 defer func() { 16 TestHookDidSendFile(dstFD, src, written, err, handled) 17 }() 18 if err := dstFD.writeLock(); err != nil { 19 return 0, err, false 20 } 21 defer dstFD.writeUnlock() 22 23 if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { 24 return 0, err, false 25 } 26 27 dst := dstFD.Sysfd 28 for remain > 0 { 29 n := maxSendfileSize 30 if int64(n) > remain { 31 n = int(remain) 32 } 33 n, err = syscall.Sendfile(dst, src, nil, n) 34 if n > 0 { 35 written += int64(n) 36 remain -= int64(n) 37 continue 38 } else if err != syscall.EAGAIN && err != syscall.EINTR { 39 // This includes syscall.ENOSYS (no kernel 40 // support) and syscall.EINVAL (fd types which 41 // don't implement sendfile), and other errors. 42 // We should end the loop when there is no error 43 // returned from sendfile(2) or it is not a retryable error. 44 break 45 } 46 if err == syscall.EINTR { 47 continue 48 } 49 if err = dstFD.pd.waitWrite(dstFD.isFile); err != nil { 50 break 51 } 52 } 53 handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL) 54 return 55} 56