sendfile_linux.go 1.6 KB

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