github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/net/fd_select.go (about) 1 // Copyright 2010 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 // Waiting for FDs via select(2). 6 7 package net 8 9 import ( 10 "errors" 11 "os" 12 "syscall" 13 ) 14 15 type pollster struct { 16 readFds, writeFds, repeatFds *syscall.FdSet 17 maxFd int 18 readyReadFds, readyWriteFds *syscall.FdSet 19 nReady int 20 lastFd int 21 closed bool 22 } 23 24 func newpollster() (p *pollster, err error) { 25 p = new(pollster) 26 p.readFds = new(syscall.FdSet) 27 p.writeFds = new(syscall.FdSet) 28 p.repeatFds = new(syscall.FdSet) 29 p.readyReadFds = new(syscall.FdSet) 30 p.readyWriteFds = new(syscall.FdSet) 31 p.maxFd = -1 32 p.nReady = 0 33 p.lastFd = 0 34 return p, nil 35 } 36 37 func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) { 38 // pollServer is locked. 39 40 if p.closed { 41 return false, errors.New("pollster closed") 42 } 43 44 if mode == 'r' { 45 syscall.FDSet(fd, p.readFds) 46 } else { 47 syscall.FDSet(fd, p.writeFds) 48 } 49 50 if repeat { 51 syscall.FDSet(fd, p.repeatFds) 52 } 53 54 if fd > p.maxFd { 55 p.maxFd = fd 56 } 57 58 return true, nil 59 } 60 61 func (p *pollster) DelFD(fd int, mode int) bool { 62 // pollServer is locked. 63 64 if p.closed { 65 return false 66 } 67 68 if mode == 'r' { 69 if !syscall.FDIsSet(fd, p.readFds) { 70 print("Select unexpected fd=", fd, " for read\n") 71 return false 72 } 73 syscall.FDClr(fd, p.readFds) 74 } else { 75 if !syscall.FDIsSet(fd, p.writeFds) { 76 print("Select unexpected fd=", fd, " for write\n") 77 return false 78 } 79 syscall.FDClr(fd, p.writeFds) 80 } 81 82 // Doesn't matter if not already present. 83 syscall.FDClr(fd, p.repeatFds) 84 85 // We don't worry about maxFd here. 86 87 return true 88 } 89 90 func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) { 91 if p.nReady == 0 { 92 var timeout *syscall.Timeval 93 var tv syscall.Timeval 94 timeout = nil 95 if nsec > 0 { 96 tv = syscall.NsecToTimeval(nsec) 97 timeout = &tv 98 } 99 100 var n int 101 var e error 102 var tmpReadFds, tmpWriteFds syscall.FdSet 103 for { 104 if p.closed { 105 return -1, 0, errors.New("pollster closed") 106 } 107 108 // Temporary syscall.FdSet's into which the values are copied 109 // because select mutates the values. 110 tmpReadFds = *p.readFds 111 tmpWriteFds = *p.writeFds 112 113 s.Unlock() 114 n, e = syscall.Select(p.maxFd+1, &tmpReadFds, &tmpWriteFds, nil, timeout) 115 s.Lock() 116 117 if e != syscall.EINTR { 118 break 119 } 120 } 121 if e == syscall.EBADF { 122 // Some file descriptor has been closed. 123 tmpReadFds = syscall.FdSet{} 124 tmpWriteFds = syscall.FdSet{} 125 n = 0 126 for i := 0; i < p.maxFd+1; i++ { 127 if syscall.FDIsSet(i, p.readFds) { 128 var s syscall.Stat_t 129 if syscall.Fstat(i, &s) == syscall.EBADF { 130 syscall.FDSet(i, &tmpReadFds) 131 n++ 132 } 133 } else if syscall.FDIsSet(i, p.writeFds) { 134 var s syscall.Stat_t 135 if syscall.Fstat(i, &s) == syscall.EBADF { 136 syscall.FDSet(i, &tmpWriteFds) 137 n++ 138 } 139 } 140 } 141 } else if e != nil { 142 return -1, 0, os.NewSyscallError("select", e) 143 } 144 if n == 0 { 145 return -1, 0, nil 146 } 147 148 p.nReady = n 149 *p.readyReadFds = tmpReadFds 150 *p.readyWriteFds = tmpWriteFds 151 p.lastFd = 0 152 } 153 154 flag := false 155 for i := p.lastFd; i < p.maxFd+1; i++ { 156 if syscall.FDIsSet(i, p.readyReadFds) { 157 flag = true 158 mode = 'r' 159 syscall.FDClr(i, p.readyReadFds) 160 } else if syscall.FDIsSet(i, p.readyWriteFds) { 161 flag = true 162 mode = 'w' 163 syscall.FDClr(i, p.readyWriteFds) 164 } 165 if flag { 166 if !syscall.FDIsSet(i, p.repeatFds) { 167 p.DelFD(i, mode) 168 } 169 p.nReady-- 170 p.lastFd = i 171 return i, mode, nil 172 } 173 } 174 175 // Will not reach here. Just to shut up the compiler. 176 return -1, 0, nil 177 } 178 179 func (p *pollster) Close() error { 180 p.closed = true 181 return nil 182 }