github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/net/sendfile_solaris.go (about) 1 // Copyright 2015 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 // Not strictly needed, but very helpful for debugging, see issue #10221. 14 //go:cgo_import_dynamic _ _ "libsendfile.so" 15 //go:cgo_import_dynamic _ _ "libsocket.so" 16 17 // maxSendfileSize is the largest chunk size we ask the kernel to copy 18 // at a time. 19 const maxSendfileSize int = 4 << 20 20 21 // sendFile copies the contents of r to c using the sendfile 22 // system call to minimize copies. 23 // 24 // if handled == true, sendFile returns the number of bytes copied and any 25 // non-EOF error. 26 // 27 // if handled == false, sendFile performed no work. 28 func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { 29 return // Solaris sendfile is disabled until Issue 13892 is understood and fixed 30 31 // Solaris uses 0 as the "until EOF" value. If you pass in more bytes than the 32 // file contains, it will loop back to the beginning ad nauseam until it's sent 33 // exactly the number of bytes told to. As such, we need to know exactly how many 34 // bytes to send. 35 var remain int64 = 0 36 37 lr, ok := r.(*io.LimitedReader) 38 if ok { 39 remain, r = lr.N, lr.R 40 if remain <= 0 { 41 return 0, nil, true 42 } 43 } 44 f, ok := r.(*os.File) 45 if !ok { 46 return 0, nil, false 47 } 48 49 if remain == 0 { 50 fi, err := f.Stat() 51 if err != nil { 52 return 0, err, false 53 } 54 55 remain = fi.Size() 56 } 57 58 // The other quirk with Solaris's sendfile implementation is that it doesn't 59 // use the current position of the file -- if you pass it offset 0, it starts 60 // from offset 0. There's no way to tell it "start from current position", so 61 // we have to manage that explicitly. 62 pos, err := f.Seek(0, os.SEEK_CUR) 63 if err != nil { 64 return 0, err, false 65 } 66 67 if err := c.writeLock(); err != nil { 68 return 0, err, true 69 } 70 defer c.writeUnlock() 71 72 dst := c.sysfd 73 src := int(f.Fd()) 74 for remain > 0 { 75 n := maxSendfileSize 76 if int64(n) > remain { 77 n = int(remain) 78 } 79 pos1 := pos 80 n, err1 := syscall.Sendfile(dst, src, &pos1, n) 81 if n > 0 { 82 pos += int64(n) 83 written += int64(n) 84 remain -= int64(n) 85 } 86 if n == 0 && err1 == nil { 87 break 88 } 89 if err1 == syscall.EAGAIN { 90 if err1 = c.pd.waitWrite(); err1 == nil { 91 continue 92 } 93 } 94 if err1 == syscall.EINTR { 95 continue 96 } 97 if err1 != nil { 98 // This includes syscall.ENOSYS (no kernel 99 // support) and syscall.EINVAL (fd types which 100 // don't implement sendfile) 101 err = err1 102 break 103 } 104 } 105 if lr != nil { 106 lr.N = remain 107 } 108 if err != nil { 109 err = os.NewSyscallError("sendfile", err) 110 } 111 return written, err, written > 0 112 }