src/pkg/net/sendfile_linux.go - The Go Programming Language

Golang

Source file src/pkg/net/sendfile_linux.go

     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 net
     6	
     7	import (
     8		"io"
     9		"os"
    10		"syscall"
    11	)
    12	
    13	// maxSendfileSize is the largest chunk size we ask the kernel to copy
    14	// at a time.
    15	const maxSendfileSize int = 4 << 20
    16	
    17	// sendFile copies the contents of r to c using the sendfile
    18	// system call to minimize copies.
    19	//
    20	// if handled == true, sendFile returns the number of bytes copied and any
    21	// non-EOF error.
    22	//
    23	// if handled == false, sendFile performed no work.
    24	func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
    25		var remain int64 = 1 << 62 // by default, copy until EOF
    26	
    27		lr, ok := r.(*io.LimitedReader)
    28		if ok {
    29			remain, r = lr.N, lr.R
    30			if remain <= 0 {
    31				return 0, nil, true
    32			}
    33		}
    34		f, ok := r.(*os.File)
    35		if !ok {
    36			return 0, nil, false
    37		}
    38	
    39		c.wio.Lock()
    40		defer c.wio.Unlock()
    41		if err := c.incref(false); err != nil {
    42			return 0, err, true
    43		}
    44		defer c.decref()
    45	
    46		dst := c.sysfd
    47		src := int(f.Fd())
    48		for remain > 0 {
    49			n := maxSendfileSize
    50			if int64(n) > remain {
    51				n = int(remain)
    52			}
    53			n, err1 := syscall.Sendfile(dst, src, nil, n)
    54			if n > 0 {
    55				written += int64(n)
    56				remain -= int64(n)
    57			}
    58			if n == 0 && err1 == nil {
    59				break
    60			}
    61			if err1 == syscall.EAGAIN && c.wdeadline >= 0 {
    62				if err1 = pollserver.WaitWrite(c); err1 == nil {
    63					continue
    64				}
    65			}
    66			if err1 != nil {
    67				// This includes syscall.ENOSYS (no kernel
    68				// support) and syscall.EINVAL (fd types which
    69				// don't implement sendfile together)
    70				err = &OpError{"sendfile", c.net, c.raddr, err1}
    71				break
    72			}
    73		}
    74		if lr != nil {
    75			lr.N = remain
    76		}
    77		return written, err, written > 0
    78	}