Home | History | Annotate | Download | only in poll
      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 
      5 package poll
      6 
      7 import "syscall"
      8 
      9 // maxSendfileSize is the largest chunk size we ask the kernel to copy
     10 // at a time.
     11 const maxSendfileSize int = 4 << 20
     12 
     13 // SendFile wraps the sendfile system call.
     14 func SendFile(dstFD *FD, src int, remain int64) (int64, error) {
     15 	if err := dstFD.writeLock(); err != nil {
     16 		return 0, err
     17 	}
     18 	defer dstFD.writeUnlock()
     19 
     20 	dst := int(dstFD.Sysfd)
     21 	var written int64
     22 	var err error
     23 	for remain > 0 {
     24 		n := maxSendfileSize
     25 		if int64(n) > remain {
     26 			n = int(remain)
     27 		}
     28 		n, err1 := syscall.Sendfile(dst, src, nil, n)
     29 		if n > 0 {
     30 			written += int64(n)
     31 			remain -= int64(n)
     32 		}
     33 		if n == 0 && err1 == nil {
     34 			break
     35 		}
     36 		if err1 == syscall.EAGAIN {
     37 			if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
     38 				continue
     39 			}
     40 		}
     41 		if err1 != nil {
     42 			// This includes syscall.ENOSYS (no kernel
     43 			// support) and syscall.EINVAL (fd types which
     44 			// don't implement sendfile)
     45 			err = err1
     46 			break
     47 		}
     48 	}
     49 	return written, err
     50 }
     51